s3-dcerpc: rationalize packet creation in the server code
[Samba.git] / source3 / librpc / rpc / dcerpc_helpers.c
blobe089e9cbf04cd936014eff02ba9897f628dc8c29
1 /*
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/>.
21 #include "includes.h"
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"
30 #include "librpc/rpc/dcerpc_spnego.h"
32 #undef DBGC_CLASS
33 #define DBGC_CLASS DBGC_RPC_PARSE
35 /**
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,
50 uint8_t pfc_flags,
51 uint16_t auth_length,
52 uint32_t call_id,
53 union dcerpc_payload *u,
54 DATA_BLOB *blob)
56 struct ncacn_packet r;
57 enum ndr_err_code ndr_err;
59 r.rpc_vers = 5;
60 r.rpc_vers_minor = 0;
61 r.ptype = ptype;
62 r.pfc_flags = pfc_flags;
63 r.drep[0] = DCERPC_DREP_LE;
64 r.drep[1] = 0;
65 r.drep[2] = 0;
66 r.drep[3] = 0;
67 r.auth_length = auth_length;
68 r.call_id = call_id;
69 r.u = *u;
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);
86 return NT_STATUS_OK;
89 /**
90 * @brief Decodes a ncacn_packet
92 * @param mem_ctx The memory context on which to allocate the packet
93 * elements
94 * @param blob The blob of data to decode
95 * @param r An empty ncacn_packet, must not be NULL
97 * @return a NTSTATUS error code
99 NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
100 const DATA_BLOB *blob,
101 struct ncacn_packet *r,
102 bool bigendian)
104 enum ndr_err_code ndr_err;
105 struct ndr_pull *ndr;
107 ndr = ndr_pull_init_blob(blob, mem_ctx);
108 if (!ndr) {
109 return NT_STATUS_NO_MEMORY;
111 if (bigendian) {
112 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
115 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, r);
117 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
118 talloc_free(ndr);
119 return ndr_map_error2ntstatus(ndr_err);
121 talloc_free(ndr);
123 if (DEBUGLEVEL >= 10) {
124 NDR_PRINT_DEBUG(ncacn_packet, r);
127 return NT_STATUS_OK;
131 * @brief NDR Encodes a NL_AUTH_MESSAGE
133 * @param mem_ctx The memory context the blob will be allocated on
134 * @param r The NL_AUTH_MESSAGE to encode
135 * @param blob [out] The encoded blob if successful
137 * @return a NTSTATUS error code
139 NTSTATUS dcerpc_push_schannel_bind(TALLOC_CTX *mem_ctx,
140 struct NL_AUTH_MESSAGE *r,
141 DATA_BLOB *blob)
143 enum ndr_err_code ndr_err;
145 ndr_err = ndr_push_struct_blob(blob, mem_ctx, r,
146 (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
147 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
148 return ndr_map_error2ntstatus(ndr_err);
151 if (DEBUGLEVEL >= 10) {
152 NDR_PRINT_DEBUG(NL_AUTH_MESSAGE, r);
155 return NT_STATUS_OK;
159 * @brief NDR Encodes a dcerpc_auth structure
161 * @param mem_ctx The memory context the blob will be allocated on
162 * @param auth_type The DCERPC Authentication Type
163 * @param auth_level The DCERPC Authentication Level
164 * @param auth_pad_length The padding added to the packet this blob will be
165 * appended to.
166 * @param auth_context_id The context id
167 * @param credentials The authentication credentials blob (signature)
168 * @param blob [out] The encoded blob if successful
170 * @return a NTSTATUS error code
172 NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx,
173 enum dcerpc_AuthType auth_type,
174 enum dcerpc_AuthLevel auth_level,
175 uint8_t auth_pad_length,
176 uint32_t auth_context_id,
177 const DATA_BLOB *credentials,
178 DATA_BLOB *blob)
180 struct dcerpc_auth r;
181 enum ndr_err_code ndr_err;
183 r.auth_type = auth_type;
184 r.auth_level = auth_level;
185 r.auth_pad_length = auth_pad_length;
186 r.auth_reserved = 0;
187 r.auth_context_id = auth_context_id;
188 r.credentials = *credentials;
190 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
191 (ndr_push_flags_fn_t)ndr_push_dcerpc_auth);
192 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
193 return ndr_map_error2ntstatus(ndr_err);
196 if (DEBUGLEVEL >= 10) {
197 NDR_PRINT_DEBUG(dcerpc_auth, &r);
200 return NT_STATUS_OK;
204 * @brief Decodes a dcerpc_auth blob
206 * @param mem_ctx The memory context on which to allocate the packet
207 * elements
208 * @param blob The blob of data to decode
209 * @param r An empty dcerpc_auth structure, must not be NULL
211 * @return a NTSTATUS error code
213 NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
214 const DATA_BLOB *blob,
215 struct dcerpc_auth *r,
216 bool bigendian)
218 enum ndr_err_code ndr_err;
219 struct ndr_pull *ndr;
221 ndr = ndr_pull_init_blob(blob, mem_ctx);
222 if (!ndr) {
223 return NT_STATUS_NO_MEMORY;
225 if (bigendian) {
226 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
229 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r);
231 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
232 talloc_free(ndr);
233 return ndr_map_error2ntstatus(ndr_err);
235 talloc_free(ndr);
237 if (DEBUGLEVEL >= 10) {
238 NDR_PRINT_DEBUG(dcerpc_auth, r);
241 return NT_STATUS_OK;
245 * @brief Calculate how much data we can in a packet, including calculating
246 * auth token and pad lengths.
248 * @param auth The pipe_auth_data structure for this pipe.
249 * @param data_left The data left in the send buffer
250 * @param data_to_send The max data we will send in the pdu
251 * @param frag_len The total length of the fragment
252 * @param auth_len The length of the auth trailer
253 * @param pad_len The padding to be applied
255 * @return A NT Error status code.
257 NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
258 size_t data_left, size_t max_xmit_frag,
259 size_t *data_to_send, size_t *frag_len,
260 size_t *auth_len, size_t *pad_len)
262 size_t data_space;
263 size_t max_len;
264 size_t mod_len;
265 struct gse_context *gse_ctx;
266 enum dcerpc_AuthType auth_type;
267 void *auth_ctx;
268 bool seal = false;
269 NTSTATUS status;
271 /* no auth token cases first */
272 switch (auth->auth_level) {
273 case DCERPC_AUTH_LEVEL_NONE:
274 case DCERPC_AUTH_LEVEL_CONNECT:
275 case DCERPC_AUTH_LEVEL_PACKET:
276 data_space = max_xmit_frag - DCERPC_REQUEST_LENGTH;
277 *data_to_send = MIN(data_space, data_left);
278 *pad_len = 0;
279 *auth_len = 0;
280 *frag_len = DCERPC_REQUEST_LENGTH + *data_to_send;
281 return NT_STATUS_OK;
283 case DCERPC_AUTH_LEVEL_PRIVACY:
284 seal = true;
285 break;
287 case DCERPC_AUTH_LEVEL_INTEGRITY:
288 break;
290 default:
291 return NT_STATUS_INVALID_PARAMETER;
295 /* Sign/seal case, calculate auth and pad lengths */
297 max_len = max_xmit_frag
298 - DCERPC_REQUEST_LENGTH
299 - DCERPC_AUTH_TRAILER_LENGTH;
301 /* Treat the same for all authenticated rpc requests. */
302 switch (auth->auth_type) {
303 case DCERPC_AUTH_TYPE_SPNEGO:
304 /* compat for server code */
305 if (auth->spnego_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
306 *auth_len = NTLMSSP_SIG_SIZE;
307 break;
310 status = spnego_get_negotiated_mech(auth->a_u.spnego_state,
311 &auth_type, &auth_ctx);
312 if (!NT_STATUS_IS_OK(status)) {
313 return status;
315 switch (auth_type) {
316 case DCERPC_AUTH_TYPE_NTLMSSP:
317 *auth_len = NTLMSSP_SIG_SIZE;
318 break;
320 case DCERPC_AUTH_TYPE_KRB5:
321 gse_ctx = talloc_get_type(auth_ctx,
322 struct gse_context);
323 if (!gse_ctx) {
324 return NT_STATUS_INVALID_PARAMETER;
326 *auth_len = gse_get_signature_length(gse_ctx,
327 seal, max_len);
328 break;
330 default:
331 return NT_STATUS_INVALID_PARAMETER;
333 break;
335 case DCERPC_AUTH_TYPE_NTLMSSP:
336 *auth_len = NTLMSSP_SIG_SIZE;
337 break;
339 case DCERPC_AUTH_TYPE_SCHANNEL:
340 *auth_len = NL_AUTH_SIGNATURE_SIZE;
341 break;
343 case DCERPC_AUTH_TYPE_KRB5:
344 *auth_len = gse_get_signature_length(auth->a_u.gssapi_state,
345 seal, max_len);
346 break;
348 default:
349 return NT_STATUS_INVALID_PARAMETER;
352 data_space = max_len - *auth_len;
354 *data_to_send = MIN(data_space, data_left);
355 mod_len = *data_to_send % CLIENT_NDR_PADDING_SIZE;
356 if (mod_len) {
357 *pad_len = CLIENT_NDR_PADDING_SIZE - mod_len;
358 } else {
359 *pad_len = 0;
361 *frag_len = DCERPC_REQUEST_LENGTH + *data_to_send + *pad_len
362 + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
364 return NT_STATUS_OK;
367 /*******************************************************************
368 Create and add the NTLMSSP sign/seal auth data.
369 ********************************************************************/
371 static NTSTATUS add_ntlmssp_auth_footer(struct auth_ntlmssp_state *auth_state,
372 enum dcerpc_AuthLevel auth_level,
373 DATA_BLOB *rpc_out)
375 uint16_t data_and_pad_len = rpc_out->length
376 - DCERPC_RESPONSE_LENGTH
377 - DCERPC_AUTH_TRAILER_LENGTH;
378 DATA_BLOB auth_blob;
379 NTSTATUS status;
381 if (!auth_state) {
382 return NT_STATUS_INVALID_PARAMETER;
385 switch (auth_level) {
386 case DCERPC_AUTH_LEVEL_PRIVACY:
387 /* Data portion is encrypted. */
388 status = auth_ntlmssp_seal_packet(auth_state,
389 rpc_out->data,
390 rpc_out->data
391 + DCERPC_RESPONSE_LENGTH,
392 data_and_pad_len,
393 rpc_out->data,
394 rpc_out->length,
395 &auth_blob);
396 if (!NT_STATUS_IS_OK(status)) {
397 return status;
399 break;
401 case DCERPC_AUTH_LEVEL_INTEGRITY:
402 /* Data is signed. */
403 status = auth_ntlmssp_sign_packet(auth_state,
404 rpc_out->data,
405 rpc_out->data
406 + DCERPC_RESPONSE_LENGTH,
407 data_and_pad_len,
408 rpc_out->data,
409 rpc_out->length,
410 &auth_blob);
411 if (!NT_STATUS_IS_OK(status)) {
412 return status;
414 break;
416 default:
417 /* Can't happen. */
418 smb_panic("bad auth level");
419 /* Notreached. */
420 return NT_STATUS_INVALID_PARAMETER;
423 /* Finally attach the blob. */
424 if (!data_blob_append(NULL, rpc_out,
425 auth_blob.data, auth_blob.length)) {
426 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
427 (unsigned int)auth_blob.length));
428 return NT_STATUS_NO_MEMORY;
430 data_blob_free(&auth_blob);
432 return NT_STATUS_OK;
435 /*******************************************************************
436 Check/unseal the NTLMSSP auth data. (Unseal in place).
437 ********************************************************************/
439 static NTSTATUS get_ntlmssp_auth_footer(struct auth_ntlmssp_state *auth_state,
440 enum dcerpc_AuthLevel auth_level,
441 DATA_BLOB *data, DATA_BLOB *full_pkt,
442 DATA_BLOB *auth_token)
444 switch (auth_level) {
445 case DCERPC_AUTH_LEVEL_PRIVACY:
446 /* Data portion is encrypted. */
447 return auth_ntlmssp_unseal_packet(auth_state,
448 data->data,
449 data->length,
450 full_pkt->data,
451 full_pkt->length,
452 auth_token);
454 case DCERPC_AUTH_LEVEL_INTEGRITY:
455 /* Data is signed. */
456 return auth_ntlmssp_check_packet(auth_state,
457 data->data,
458 data->length,
459 full_pkt->data,
460 full_pkt->length,
461 auth_token);
463 default:
464 return NT_STATUS_INVALID_PARAMETER;
468 /*******************************************************************
469 Create and add the schannel sign/seal auth data.
470 ********************************************************************/
472 static NTSTATUS add_schannel_auth_footer(struct schannel_state *sas,
473 enum dcerpc_AuthLevel auth_level,
474 DATA_BLOB *rpc_out)
476 uint8_t *data_p = rpc_out->data + DCERPC_RESPONSE_LENGTH;
477 size_t data_and_pad_len = rpc_out->length
478 - DCERPC_RESPONSE_LENGTH
479 - DCERPC_AUTH_TRAILER_LENGTH;
480 DATA_BLOB auth_blob;
481 NTSTATUS status;
483 if (!sas) {
484 return NT_STATUS_INVALID_PARAMETER;
487 DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n",
488 sas->seq_num));
490 switch (auth_level) {
491 case DCERPC_AUTH_LEVEL_PRIVACY:
492 status = netsec_outgoing_packet(sas,
493 rpc_out->data,
494 true,
495 data_p,
496 data_and_pad_len,
497 &auth_blob);
498 break;
499 case DCERPC_AUTH_LEVEL_INTEGRITY:
500 status = netsec_outgoing_packet(sas,
501 rpc_out->data,
502 false,
503 data_p,
504 data_and_pad_len,
505 &auth_blob);
506 break;
507 default:
508 status = NT_STATUS_INTERNAL_ERROR;
509 break;
512 if (!NT_STATUS_IS_OK(status)) {
513 DEBUG(1,("add_schannel_auth_footer: failed to process packet: %s\n",
514 nt_errstr(status)));
515 return status;
518 if (DEBUGLEVEL >= 10) {
519 dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_blob);
522 /* Finally attach the blob. */
523 if (!data_blob_append(NULL, rpc_out,
524 auth_blob.data, auth_blob.length)) {
525 return NT_STATUS_NO_MEMORY;
527 data_blob_free(&auth_blob);
529 return NT_STATUS_OK;
532 /*******************************************************************
533 Check/unseal the Schannel auth data. (Unseal in place).
534 ********************************************************************/
536 static NTSTATUS get_schannel_auth_footer(TALLOC_CTX *mem_ctx,
537 struct schannel_state *auth_state,
538 enum dcerpc_AuthLevel auth_level,
539 DATA_BLOB *data, DATA_BLOB *full_pkt,
540 DATA_BLOB *auth_token)
542 switch (auth_level) {
543 case DCERPC_AUTH_LEVEL_PRIVACY:
544 /* Data portion is encrypted. */
545 return netsec_incoming_packet(auth_state,
546 mem_ctx, true,
547 data->data,
548 data->length,
549 auth_token);
551 case DCERPC_AUTH_LEVEL_INTEGRITY:
552 /* Data is signed. */
553 return netsec_incoming_packet(auth_state,
554 mem_ctx, false,
555 data->data,
556 data->length,
557 auth_token);
559 default:
560 return NT_STATUS_INVALID_PARAMETER;
564 /*******************************************************************
565 Create and add the gssapi sign/seal auth data.
566 ********************************************************************/
568 static NTSTATUS add_gssapi_auth_footer(struct gse_context *gse_ctx,
569 enum dcerpc_AuthLevel auth_level,
570 DATA_BLOB *rpc_out)
572 DATA_BLOB data;
573 DATA_BLOB auth_blob;
574 NTSTATUS status;
576 if (!gse_ctx) {
577 return NT_STATUS_INVALID_PARAMETER;
580 data.data = rpc_out->data + DCERPC_RESPONSE_LENGTH;
581 data.length = rpc_out->length - DCERPC_RESPONSE_LENGTH
582 - DCERPC_AUTH_TRAILER_LENGTH;
584 switch (auth_level) {
585 case DCERPC_AUTH_LEVEL_PRIVACY:
586 status = gse_seal(talloc_tos(), gse_ctx, &data, &auth_blob);
587 break;
588 case DCERPC_AUTH_LEVEL_INTEGRITY:
589 status = gse_sign(talloc_tos(), gse_ctx, &data, &auth_blob);
590 break;
591 default:
592 status = NT_STATUS_INTERNAL_ERROR;
593 break;
596 if (!NT_STATUS_IS_OK(status)) {
597 DEBUG(1, ("Failed to process packet: %s\n",
598 nt_errstr(status)));
599 return status;
602 /* Finally attach the blob. */
603 if (!data_blob_append(NULL, rpc_out,
604 auth_blob.data, auth_blob.length)) {
605 return NT_STATUS_NO_MEMORY;
608 data_blob_free(&auth_blob);
610 return NT_STATUS_OK;
613 /*******************************************************************
614 Check/unseal the gssapi auth data. (Unseal in place).
615 ********************************************************************/
617 static NTSTATUS get_gssapi_auth_footer(TALLOC_CTX *mem_ctx,
618 struct gse_context *gse_ctx,
619 enum dcerpc_AuthLevel auth_level,
620 DATA_BLOB *data, DATA_BLOB *full_pkt,
621 DATA_BLOB *auth_token)
623 /* TODO: pass in full_pkt when
624 * DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN is set */
625 switch (auth_level) {
626 case DCERPC_AUTH_LEVEL_PRIVACY:
627 /* Data portion is encrypted. */
628 return gse_unseal(mem_ctx, gse_ctx,
629 data, auth_token);
631 case DCERPC_AUTH_LEVEL_INTEGRITY:
632 /* Data is signed. */
633 return gse_sigcheck(mem_ctx, gse_ctx,
634 data, auth_token);
635 default:
636 return NT_STATUS_INVALID_PARAMETER;
640 /*******************************************************************
641 Create and add the spnego-negotiated sign/seal auth data.
642 ********************************************************************/
644 static NTSTATUS add_spnego_auth_footer(struct spnego_context *spnego_ctx,
645 enum dcerpc_AuthLevel auth_level,
646 DATA_BLOB *rpc_out)
648 enum dcerpc_AuthType auth_type;
649 struct gse_context *gse_ctx;
650 struct auth_ntlmssp_state *ntlmssp_ctx;
651 void *auth_ctx;
652 NTSTATUS status;
654 if (!spnego_ctx) {
655 return NT_STATUS_INVALID_PARAMETER;
658 status = spnego_get_negotiated_mech(spnego_ctx,
659 &auth_type, &auth_ctx);
660 if (!NT_STATUS_IS_OK(status)) {
661 return status;
664 switch (auth_type) {
665 case DCERPC_AUTH_TYPE_KRB5:
666 gse_ctx = talloc_get_type(auth_ctx, struct gse_context);
667 if (!gse_ctx) {
668 status = NT_STATUS_INTERNAL_ERROR;
669 break;
671 status = add_gssapi_auth_footer(gse_ctx,
672 auth_level, rpc_out);
673 break;
675 case DCERPC_AUTH_TYPE_NTLMSSP:
676 ntlmssp_ctx = talloc_get_type(auth_ctx,
677 struct auth_ntlmssp_state);
678 if (!ntlmssp_ctx) {
679 status = NT_STATUS_INTERNAL_ERROR;
680 break;
682 status = add_ntlmssp_auth_footer(ntlmssp_ctx,
683 auth_level, rpc_out);
684 break;
686 default:
687 status = NT_STATUS_INTERNAL_ERROR;
688 break;
691 return status;
694 static NTSTATUS get_spnego_auth_footer(TALLOC_CTX *mem_ctx,
695 struct spnego_context *sp_ctx,
696 enum dcerpc_AuthLevel auth_level,
697 DATA_BLOB *data, DATA_BLOB *full_pkt,
698 DATA_BLOB *auth_token)
700 enum dcerpc_AuthType auth_type;
701 struct auth_ntlmssp_state *ntlmssp_ctx;
702 struct gse_context *gse_ctx;
703 void *auth_ctx;
704 NTSTATUS status;
706 status = spnego_get_negotiated_mech(sp_ctx, &auth_type, &auth_ctx);
707 if (!NT_STATUS_IS_OK(status)) {
708 return status;
711 switch (auth_type) {
712 case DCERPC_AUTH_TYPE_KRB5:
713 gse_ctx = talloc_get_type(auth_ctx,
714 struct gse_context);
715 if (!gse_ctx) {
716 return NT_STATUS_INVALID_PARAMETER;
719 DEBUG(10, ("KRB5 auth\n"));
721 return get_gssapi_auth_footer(mem_ctx, gse_ctx,
722 auth_level,
723 data, full_pkt,
724 auth_token);
725 case DCERPC_AUTH_TYPE_NTLMSSP:
726 ntlmssp_ctx = talloc_get_type(auth_ctx,
727 struct auth_ntlmssp_state);
728 if (!ntlmssp_ctx) {
729 return NT_STATUS_INVALID_PARAMETER;
732 DEBUG(10, ("NTLMSSP auth\n"));
734 return get_ntlmssp_auth_footer(ntlmssp_ctx,
735 auth_level,
736 data, full_pkt,
737 auth_token);
738 default:
739 return NT_STATUS_INVALID_PARAMETER;
744 * @brief Append an auth footer according to what is the current mechanism
746 * @param auth The pipe_auth_data associated with the connection
747 * @param pad_len The padding used in the packet
748 * @param rpc_out Packet blob up to and including the auth header
750 * @return A NTSTATUS error code.
752 NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
753 size_t pad_len, DATA_BLOB *rpc_out)
755 char pad[CLIENT_NDR_PADDING_SIZE] = { 0, };
756 DATA_BLOB auth_info;
757 DATA_BLOB auth_blob;
758 NTSTATUS status;
760 if (auth->auth_type == DCERPC_AUTH_TYPE_NONE) {
761 return NT_STATUS_OK;
764 if (pad_len) {
765 /* Copy the sign/seal padding data. */
766 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
767 return NT_STATUS_NO_MEMORY;
771 /* marshall the dcerpc_auth with an actually empty auth_blob.
772 * This is needed because the ntmlssp signature includes the
773 * auth header. We will append the actual blob later. */
774 auth_blob = data_blob_null;
775 status = dcerpc_push_dcerpc_auth(rpc_out->data,
776 auth->auth_type,
777 auth->auth_level,
778 pad_len,
779 1 /* context id. */,
780 &auth_blob,
781 &auth_info);
782 if (!NT_STATUS_IS_OK(status)) {
783 return status;
786 /* append the header */
787 if (!data_blob_append(NULL, rpc_out,
788 auth_info.data, auth_info.length)) {
789 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
790 (unsigned int)auth_info.length));
791 return NT_STATUS_NO_MEMORY;
793 data_blob_free(&auth_info);
795 /* Generate any auth sign/seal and add the auth footer. */
796 switch (auth->auth_type) {
797 case DCERPC_AUTH_TYPE_NONE:
798 status = NT_STATUS_OK;
799 break;
800 case DCERPC_AUTH_TYPE_SPNEGO:
801 if (auth->spnego_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
802 /* compat for server code */
803 return add_ntlmssp_auth_footer(
804 auth->a_u.auth_ntlmssp_state,
805 auth->auth_level,
806 rpc_out);
808 status = add_spnego_auth_footer(auth->a_u.spnego_state,
809 auth->auth_level, rpc_out);
810 break;
811 case DCERPC_AUTH_TYPE_NTLMSSP:
812 status = add_ntlmssp_auth_footer(auth->a_u.auth_ntlmssp_state,
813 auth->auth_level,
814 rpc_out);
815 break;
816 case DCERPC_AUTH_TYPE_SCHANNEL:
817 status = add_schannel_auth_footer(auth->a_u.schannel_auth,
818 auth->auth_level,
819 rpc_out);
820 break;
821 case DCERPC_AUTH_TYPE_KRB5:
822 status = add_gssapi_auth_footer(auth->a_u.gssapi_state,
823 auth->auth_level,
824 rpc_out);
825 break;
826 default:
827 status = NT_STATUS_INVALID_PARAMETER;
828 break;
831 return status;
835 * @brief Check authentication for request/response packets
837 * @param auth The auth data for the connection
838 * @param pkt The actual ncacn_packet
839 * @param pkt_trailer The stub_and_verifier part of the packet
840 * @param header_size The header size
841 * @param raw_pkt The whole raw packet data blob
842 * @param pad_len [out] The padding length used in the packet
844 * @return A NTSTATUS error code
846 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
847 struct ncacn_packet *pkt,
848 DATA_BLOB *pkt_trailer,
849 size_t header_size,
850 DATA_BLOB *raw_pkt,
851 size_t *pad_len)
853 NTSTATUS status;
854 struct dcerpc_auth auth_info;
855 uint32_t auth_length;
856 DATA_BLOB full_pkt;
857 DATA_BLOB data;
859 switch (auth->auth_level) {
860 case DCERPC_AUTH_LEVEL_PRIVACY:
861 DEBUG(10, ("Requested Privacy.\n"));
862 break;
864 case DCERPC_AUTH_LEVEL_INTEGRITY:
865 DEBUG(10, ("Requested Integrity.\n"));
866 break;
868 case DCERPC_AUTH_LEVEL_CONNECT:
869 if (pkt->auth_length != 0) {
870 break;
872 *pad_len = 0;
873 return NT_STATUS_OK;
875 case DCERPC_AUTH_LEVEL_NONE:
876 if (pkt->auth_length != 0) {
877 DEBUG(3, ("Got non-zero auth len on non "
878 "authenticated connection!\n"));
879 return NT_STATUS_INVALID_PARAMETER;
881 *pad_len = 0;
882 return NT_STATUS_OK;
884 default:
885 DEBUG(3, ("Unimplemented Auth Level %d",
886 auth->auth_level));
887 return NT_STATUS_INVALID_PARAMETER;
890 /* Paranioa checks for auth_length. */
891 if (pkt->auth_length > pkt->frag_length) {
892 return NT_STATUS_INFO_LENGTH_MISMATCH;
894 if ((pkt->auth_length
895 + DCERPC_AUTH_TRAILER_LENGTH < pkt->auth_length) ||
896 (pkt->auth_length
897 + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
898 /* Integer wrap attempt. */
899 return NT_STATUS_INFO_LENGTH_MISMATCH;
902 status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
903 &auth_info, &auth_length, false);
904 if (!NT_STATUS_IS_OK(status)) {
905 return status;
908 data = data_blob_const(raw_pkt->data + header_size,
909 pkt_trailer->length - auth_length);
910 full_pkt = data_blob_const(raw_pkt->data,
911 raw_pkt->length - auth_info.credentials.length);
913 switch (auth->auth_type) {
914 case DCERPC_AUTH_TYPE_NONE:
915 return NT_STATUS_OK;
917 case DCERPC_AUTH_TYPE_SPNEGO:
918 if (auth->spnego_type == PIPE_AUTH_TYPE_SPNEGO_NTLMSSP) {
919 /* compat for server code */
920 DEBUG(10, ("NTLMSSP auth\n"));
922 status = get_ntlmssp_auth_footer(
923 auth->a_u.auth_ntlmssp_state,
924 auth->auth_level,
925 &data, &full_pkt,
926 &auth_info.credentials);
927 if (!NT_STATUS_IS_OK(status)) {
928 return status;
930 break;
933 status = get_spnego_auth_footer(pkt, auth->a_u.spnego_state,
934 auth->auth_level,
935 &data, &full_pkt,
936 &auth_info.credentials);
937 if (!NT_STATUS_IS_OK(status)) {
938 return status;
940 break;
942 case DCERPC_AUTH_TYPE_NTLMSSP:
944 DEBUG(10, ("NTLMSSP auth\n"));
946 status = get_ntlmssp_auth_footer(auth->a_u.auth_ntlmssp_state,
947 auth->auth_level,
948 &data, &full_pkt,
949 &auth_info.credentials);
950 if (!NT_STATUS_IS_OK(status)) {
951 return status;
953 break;
955 case DCERPC_AUTH_TYPE_SCHANNEL:
957 DEBUG(10, ("SCHANNEL auth\n"));
959 status = get_schannel_auth_footer(pkt,
960 auth->a_u.schannel_auth,
961 auth->auth_level,
962 &data, &full_pkt,
963 &auth_info.credentials);
964 if (!NT_STATUS_IS_OK(status)) {
965 return status;
967 break;
969 case DCERPC_AUTH_TYPE_KRB5:
971 DEBUG(10, ("KRB5 auth\n"));
973 status = get_gssapi_auth_footer(pkt,
974 auth->a_u.gssapi_state,
975 auth->auth_level,
976 &data, &full_pkt,
977 &auth_info.credentials);
978 if (!NT_STATUS_IS_OK(status)) {
979 return status;
981 break;
983 default:
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;