source: trunk/server/source3/librpc/rpc/dcerpc_helpers.c

Last change on this file was 920, checked in by Silvan Scherrer, 9 years ago

Samba Server: apply latest security patches to trunk

File size: 24.9 KB
Line 
1/*
2 * DCERPC Helper routines
3 * GÃŒnther Deschner <gd@samba.org> 2010.
4 * Simo Sorce <idra@samba.org> 2010.
5 *
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.
10 *
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.
15 *
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/>.
18 */
19
20
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/crypto/gse.h"
30#include "librpc/crypto/spnego.h"
31
32#undef DBGC_CLASS
33#define DBGC_CLASS DBGC_RPC_PARSE
34
35/**
36* @brief NDR Encodes a ncacn_packet
37*
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
45*
46* @return an NTSTATUS error code
47*/
48NTSTATUS 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)
55{
56 struct ncacn_packet r;
57 enum ndr_err_code ndr_err;
58
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;
70
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);
75 }
76
77 dcerpc_set_frag_length(blob, blob->length);
78
79
80 if (DEBUGLEVEL >= 10) {
81 /* set frag len for print function */
82 r.frag_length = blob->length;
83 NDR_PRINT_DEBUG(ncacn_packet, &r);
84 }
85
86 return NT_STATUS_OK;
87}
88
89/**
90* @brief Decodes a ncacn_packet
91*
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
96* @param bigendian Whether the packet is bignedian encoded
97*
98* @return a NTSTATUS error code
99*/
100NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
101 const DATA_BLOB *blob,
102 struct ncacn_packet *r,
103 bool bigendian)
104{
105 enum ndr_err_code ndr_err;
106 struct ndr_pull *ndr;
107
108 ndr = ndr_pull_init_blob(blob, mem_ctx);
109 if (!ndr) {
110 return NT_STATUS_NO_MEMORY;
111 }
112 if (bigendian) {
113 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
114 }
115
116 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
117 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
118 }
119
120 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, r);
121
122 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
123 talloc_free(ndr);
124 return ndr_map_error2ntstatus(ndr_err);
125 }
126 talloc_free(ndr);
127
128 if (DEBUGLEVEL >= 10) {
129 NDR_PRINT_DEBUG(ncacn_packet, r);
130 }
131
132 if (r->frag_length != blob->length) {
133 return NT_STATUS_RPC_PROTOCOL_ERROR;
134 }
135
136 return NT_STATUS_OK;
137}
138
139/**
140* @brief NDR Encodes a NL_AUTH_MESSAGE
141*
142* @param mem_ctx The memory context the blob will be allocated on
143* @param r The NL_AUTH_MESSAGE to encode
144* @param blob [out] The encoded blob if successful
145*
146* @return a NTSTATUS error code
147*/
148NTSTATUS dcerpc_push_schannel_bind(TALLOC_CTX *mem_ctx,
149 struct NL_AUTH_MESSAGE *r,
150 DATA_BLOB *blob)
151{
152 enum ndr_err_code ndr_err;
153
154 ndr_err = ndr_push_struct_blob(blob, mem_ctx, r,
155 (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
156 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
157 return ndr_map_error2ntstatus(ndr_err);
158 }
159
160 if (DEBUGLEVEL >= 10) {
161 NDR_PRINT_DEBUG(NL_AUTH_MESSAGE, r);
162 }
163
164 return NT_STATUS_OK;
165}
166
167/**
168* @brief NDR Encodes a dcerpc_auth structure
169*
170* @param mem_ctx The memory context the blob will be allocated on
171* @param auth_type The DCERPC Authentication Type
172* @param auth_level The DCERPC Authentication Level
173* @param auth_pad_length The padding added to the packet this blob will be
174* appended to.
175* @param auth_context_id The context id
176* @param credentials The authentication credentials blob (signature)
177* @param blob [out] The encoded blob if successful
178*
179* @return a NTSTATUS error code
180*/
181NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx,
182 enum dcerpc_AuthType auth_type,
183 enum dcerpc_AuthLevel auth_level,
184 uint8_t auth_pad_length,
185 uint32_t auth_context_id,
186 const DATA_BLOB *credentials,
187 DATA_BLOB *blob)
188{
189 struct dcerpc_auth r;
190 enum ndr_err_code ndr_err;
191
192 r.auth_type = auth_type;
193 r.auth_level = auth_level;
194 r.auth_pad_length = auth_pad_length;
195 r.auth_reserved = 0;
196 r.auth_context_id = auth_context_id;
197 r.credentials = *credentials;
198
199 ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
200 (ndr_push_flags_fn_t)ndr_push_dcerpc_auth);
201 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
202 return ndr_map_error2ntstatus(ndr_err);
203 }
204
205 if (DEBUGLEVEL >= 10) {
206 NDR_PRINT_DEBUG(dcerpc_auth, &r);
207 }
208
209 return NT_STATUS_OK;
210}
211
212/**
213* @brief Calculate how much data we can in a packet, including calculating
214* auth token and pad lengths.
215*
216* @param auth The pipe_auth_data structure for this pipe.
217* @param header_len The length of the packet header
218* @param data_left The data left in the send buffer
219* @param max_xmit_frag The max fragment size.
220* @param pad_alignment The NDR padding size.
221* @param data_to_send [out] The max data we will send in the pdu
222* @param frag_len [out] The total length of the fragment
223* @param auth_len [out] The length of the auth trailer
224* @param pad_len [out] The padding to be applied
225*
226* @return A NT Error status code.
227*/
228NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
229 size_t header_len, size_t data_left,
230 size_t max_xmit_frag, size_t pad_alignment,
231 size_t *data_to_send, size_t *frag_len,
232 size_t *auth_len, size_t *pad_len)
233{
234 size_t max_len;
235 size_t mod_len;
236 struct schannel_state *schannel_auth;
237 struct spnego_context *spnego_ctx;
238 struct gse_context *gse_ctx;
239 enum spnego_mech auth_type;
240 void *auth_ctx;
241 bool seal = false;
242 NTSTATUS status;
243
244 /* no auth token cases first */
245 switch (auth->auth_level) {
246 case DCERPC_AUTH_LEVEL_NONE:
247 case DCERPC_AUTH_LEVEL_CONNECT:
248 case DCERPC_AUTH_LEVEL_PACKET:
249 max_len = max_xmit_frag - header_len;
250 *data_to_send = MIN(max_len, data_left);
251 *pad_len = 0;
252 *auth_len = 0;
253 *frag_len = header_len + *data_to_send;
254 return NT_STATUS_OK;
255
256 case DCERPC_AUTH_LEVEL_PRIVACY:
257 seal = true;
258 break;
259
260 case DCERPC_AUTH_LEVEL_INTEGRITY:
261 break;
262
263 default:
264 return NT_STATUS_INVALID_PARAMETER;
265 }
266
267
268 /* Sign/seal case, calculate auth and pad lengths */
269
270 max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH;
271
272 /* Treat the same for all authenticated rpc requests. */
273 switch (auth->auth_type) {
274 case DCERPC_AUTH_TYPE_SPNEGO:
275 spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
276 struct spnego_context);
277 status = spnego_get_negotiated_mech(spnego_ctx,
278 &auth_type, &auth_ctx);
279 if (!NT_STATUS_IS_OK(status)) {
280 return status;
281 }
282 switch (auth_type) {
283 case SPNEGO_NTLMSSP:
284 *auth_len = NTLMSSP_SIG_SIZE;
285 break;
286
287 case SPNEGO_KRB5:
288 gse_ctx = talloc_get_type_abort(auth_ctx,
289 struct gse_context);
290 if (!gse_ctx) {
291 return NT_STATUS_INVALID_PARAMETER;
292 }
293 *auth_len = gse_get_signature_length(gse_ctx,
294 seal, max_len);
295 break;
296
297 default:
298 return NT_STATUS_INVALID_PARAMETER;
299 }
300 break;
301
302 case DCERPC_AUTH_TYPE_NTLMSSP:
303 *auth_len = NTLMSSP_SIG_SIZE;
304 break;
305
306 case DCERPC_AUTH_TYPE_SCHANNEL:
307 schannel_auth = talloc_get_type_abort(auth->auth_ctx,
308 struct schannel_state);
309 *auth_len = netsec_outgoing_sig_size(schannel_auth);
310 break;
311
312 case DCERPC_AUTH_TYPE_KRB5:
313 gse_ctx = talloc_get_type_abort(auth->auth_ctx,
314 struct gse_context);
315 *auth_len = gse_get_signature_length(gse_ctx,
316 seal, max_len);
317 break;
318
319 default:
320 return NT_STATUS_INVALID_PARAMETER;
321 }
322
323 max_len -= *auth_len;
324
325 *data_to_send = MIN(max_len, data_left);
326
327 mod_len = (header_len + *data_to_send) % pad_alignment;
328 if (mod_len) {
329 *pad_len = pad_alignment - mod_len;
330 } else {
331 *pad_len = 0;
332 }
333
334 if (*data_to_send + *pad_len > max_len) {
335 *data_to_send -= pad_alignment;
336 }
337
338 *frag_len = header_len + *data_to_send + *pad_len
339 + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
340
341 return NT_STATUS_OK;
342}
343
344/*******************************************************************
345 Create and add the NTLMSSP sign/seal auth data.
346 ********************************************************************/
347
348static NTSTATUS add_ntlmssp_auth_footer(struct auth_ntlmssp_state *auth_state,
349 enum dcerpc_AuthLevel auth_level,
350 DATA_BLOB *rpc_out)
351{
352 uint16_t data_and_pad_len = rpc_out->length
353 - DCERPC_RESPONSE_LENGTH
354 - DCERPC_AUTH_TRAILER_LENGTH;
355 DATA_BLOB auth_blob;
356 NTSTATUS status;
357
358 if (!auth_state) {
359 return NT_STATUS_INVALID_PARAMETER;
360 }
361
362 switch (auth_level) {
363 case DCERPC_AUTH_LEVEL_PRIVACY:
364 /* Data portion is encrypted. */
365 status = auth_ntlmssp_seal_packet(auth_state,
366 rpc_out->data,
367 rpc_out->data
368 + DCERPC_RESPONSE_LENGTH,
369 data_and_pad_len,
370 rpc_out->data,
371 rpc_out->length,
372 &auth_blob);
373 if (!NT_STATUS_IS_OK(status)) {
374 return status;
375 }
376 break;
377
378 case DCERPC_AUTH_LEVEL_INTEGRITY:
379 /* Data is signed. */
380 status = auth_ntlmssp_sign_packet(auth_state,
381 rpc_out->data,
382 rpc_out->data
383 + DCERPC_RESPONSE_LENGTH,
384 data_and_pad_len,
385 rpc_out->data,
386 rpc_out->length,
387 &auth_blob);
388 if (!NT_STATUS_IS_OK(status)) {
389 return status;
390 }
391 break;
392
393 default:
394 /* Can't happen. */
395 smb_panic("bad auth level");
396 /* Notreached. */
397 return NT_STATUS_INVALID_PARAMETER;
398 }
399
400 /* Finally attach the blob. */
401 if (!data_blob_append(NULL, rpc_out,
402 auth_blob.data, auth_blob.length)) {
403 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
404 (unsigned int)auth_blob.length));
405 return NT_STATUS_NO_MEMORY;
406 }
407 data_blob_free(&auth_blob);
408
409 return NT_STATUS_OK;
410}
411
412/*******************************************************************
413 Check/unseal the NTLMSSP auth data. (Unseal in place).
414 ********************************************************************/
415
416static NTSTATUS get_ntlmssp_auth_footer(struct auth_ntlmssp_state *auth_state,
417 enum dcerpc_AuthLevel auth_level,
418 DATA_BLOB *data, DATA_BLOB *full_pkt,
419 DATA_BLOB *auth_token)
420{
421 switch (auth_level) {
422 case DCERPC_AUTH_LEVEL_PRIVACY:
423 /* Data portion is encrypted. */
424 return auth_ntlmssp_unseal_packet(auth_state,
425 data->data,
426 data->length,
427 full_pkt->data,
428 full_pkt->length,
429 auth_token);
430
431 case DCERPC_AUTH_LEVEL_INTEGRITY:
432 /* Data is signed. */
433 return auth_ntlmssp_check_packet(auth_state,
434 data->data,
435 data->length,
436 full_pkt->data,
437 full_pkt->length,
438 auth_token);
439
440 default:
441 return NT_STATUS_INVALID_PARAMETER;
442 }
443}
444
445/*******************************************************************
446 Create and add the schannel sign/seal auth data.
447 ********************************************************************/
448
449static NTSTATUS add_schannel_auth_footer(struct schannel_state *sas,
450 enum dcerpc_AuthLevel auth_level,
451 DATA_BLOB *rpc_out)
452{
453 uint8_t *data_p = rpc_out->data + DCERPC_RESPONSE_LENGTH;
454 size_t data_and_pad_len = rpc_out->length
455 - DCERPC_RESPONSE_LENGTH
456 - DCERPC_AUTH_TRAILER_LENGTH;
457 DATA_BLOB auth_blob;
458 NTSTATUS status;
459
460 if (!sas) {
461 return NT_STATUS_INVALID_PARAMETER;
462 }
463
464 DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n",
465 sas->seq_num));
466
467 switch (auth_level) {
468 case DCERPC_AUTH_LEVEL_PRIVACY:
469 status = netsec_outgoing_packet(sas,
470 rpc_out->data,
471 true,
472 data_p,
473 data_and_pad_len,
474 &auth_blob);
475 break;
476 case DCERPC_AUTH_LEVEL_INTEGRITY:
477 status = netsec_outgoing_packet(sas,
478 rpc_out->data,
479 false,
480 data_p,
481 data_and_pad_len,
482 &auth_blob);
483 break;
484 default:
485 status = NT_STATUS_INTERNAL_ERROR;
486 break;
487 }
488
489 if (!NT_STATUS_IS_OK(status)) {
490 DEBUG(1,("add_schannel_auth_footer: failed to process packet: %s\n",
491 nt_errstr(status)));
492 return status;
493 }
494
495 if (DEBUGLEVEL >= 10) {
496 dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_blob);
497 }
498
499 /* Finally attach the blob. */
500 if (!data_blob_append(NULL, rpc_out,
501 auth_blob.data, auth_blob.length)) {
502 return NT_STATUS_NO_MEMORY;
503 }
504 data_blob_free(&auth_blob);
505
506 return NT_STATUS_OK;
507}
508
509/*******************************************************************
510 Check/unseal the Schannel auth data. (Unseal in place).
511 ********************************************************************/
512
513static NTSTATUS get_schannel_auth_footer(TALLOC_CTX *mem_ctx,
514 struct schannel_state *auth_state,
515 enum dcerpc_AuthLevel auth_level,
516 DATA_BLOB *data, DATA_BLOB *full_pkt,
517 DATA_BLOB *auth_token)
518{
519 switch (auth_level) {
520 case DCERPC_AUTH_LEVEL_PRIVACY:
521 /* Data portion is encrypted. */
522 return netsec_incoming_packet(auth_state,
523 mem_ctx, true,
524 data->data,
525 data->length,
526 auth_token);
527
528 case DCERPC_AUTH_LEVEL_INTEGRITY:
529 /* Data is signed. */
530 return netsec_incoming_packet(auth_state,
531 mem_ctx, false,
532 data->data,
533 data->length,
534 auth_token);
535
536 default:
537 return NT_STATUS_INVALID_PARAMETER;
538 }
539}
540
541/*******************************************************************
542 Create and add the gssapi sign/seal auth data.
543 ********************************************************************/
544
545static NTSTATUS add_gssapi_auth_footer(struct gse_context *gse_ctx,
546 enum dcerpc_AuthLevel auth_level,
547 DATA_BLOB *rpc_out)
548{
549 DATA_BLOB data;
550 DATA_BLOB auth_blob;
551 NTSTATUS status;
552
553 if (!gse_ctx) {
554 return NT_STATUS_INVALID_PARAMETER;
555 }
556
557 data.data = rpc_out->data + DCERPC_RESPONSE_LENGTH;
558 data.length = rpc_out->length - DCERPC_RESPONSE_LENGTH
559 - DCERPC_AUTH_TRAILER_LENGTH;
560
561 switch (auth_level) {
562 case DCERPC_AUTH_LEVEL_PRIVACY:
563 status = gse_seal(talloc_tos(), gse_ctx, &data, &auth_blob);
564 break;
565 case DCERPC_AUTH_LEVEL_INTEGRITY:
566 status = gse_sign(talloc_tos(), gse_ctx, &data, &auth_blob);
567 break;
568 default:
569 status = NT_STATUS_INTERNAL_ERROR;
570 break;
571 }
572
573 if (!NT_STATUS_IS_OK(status)) {
574 DEBUG(1, ("Failed to process packet: %s\n",
575 nt_errstr(status)));
576 return status;
577 }
578
579 /* Finally attach the blob. */
580 if (!data_blob_append(NULL, rpc_out,
581 auth_blob.data, auth_blob.length)) {
582 return NT_STATUS_NO_MEMORY;
583 }
584
585 data_blob_free(&auth_blob);
586
587 return NT_STATUS_OK;
588}
589
590/*******************************************************************
591 Check/unseal the gssapi auth data. (Unseal in place).
592 ********************************************************************/
593
594static NTSTATUS get_gssapi_auth_footer(TALLOC_CTX *mem_ctx,
595 struct gse_context *gse_ctx,
596 enum dcerpc_AuthLevel auth_level,
597 DATA_BLOB *data, DATA_BLOB *full_pkt,
598 DATA_BLOB *auth_token)
599{
600 /* TODO: pass in full_pkt when
601 * DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN is set */
602 switch (auth_level) {
603 case DCERPC_AUTH_LEVEL_PRIVACY:
604 /* Data portion is encrypted. */
605 return gse_unseal(mem_ctx, gse_ctx,
606 data, auth_token);
607
608 case DCERPC_AUTH_LEVEL_INTEGRITY:
609 /* Data is signed. */
610 return gse_sigcheck(mem_ctx, gse_ctx,
611 data, auth_token);
612 default:
613 return NT_STATUS_INVALID_PARAMETER;
614 }
615}
616
617/*******************************************************************
618 Create and add the spnego-negotiated sign/seal auth data.
619 ********************************************************************/
620
621static NTSTATUS add_spnego_auth_footer(struct spnego_context *spnego_ctx,
622 enum dcerpc_AuthLevel auth_level,
623 DATA_BLOB *rpc_out)
624{
625 DATA_BLOB auth_blob;
626 DATA_BLOB rpc_data;
627 NTSTATUS status;
628
629 if (!spnego_ctx) {
630 return NT_STATUS_INVALID_PARAMETER;
631 }
632
633 rpc_data = data_blob_const(rpc_out->data
634 + DCERPC_RESPONSE_LENGTH,
635 rpc_out->length
636 - DCERPC_RESPONSE_LENGTH
637 - DCERPC_AUTH_TRAILER_LENGTH);
638
639 switch (auth_level) {
640 case DCERPC_AUTH_LEVEL_PRIVACY:
641 /* Data portion is encrypted. */
642 status = spnego_seal(rpc_out->data, spnego_ctx,
643 &rpc_data, rpc_out, &auth_blob);
644 break;
645
646 if (!NT_STATUS_IS_OK(status)) {
647 return status;
648 }
649 break;
650
651 case DCERPC_AUTH_LEVEL_INTEGRITY:
652 /* Data is signed. */
653 status = spnego_sign(rpc_out->data, spnego_ctx,
654 &rpc_data, rpc_out, &auth_blob);
655 break;
656
657 if (!NT_STATUS_IS_OK(status)) {
658 return status;
659 }
660 break;
661
662 default:
663 /* Can't happen. */
664 smb_panic("bad auth level");
665 /* Notreached. */
666 return NT_STATUS_INVALID_PARAMETER;
667 }
668
669 /* Finally attach the blob. */
670 if (!data_blob_append(NULL, rpc_out,
671 auth_blob.data, auth_blob.length)) {
672 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
673 (unsigned int)auth_blob.length));
674 return NT_STATUS_NO_MEMORY;
675 }
676 data_blob_free(&auth_blob);
677
678 return NT_STATUS_OK;
679}
680
681static NTSTATUS get_spnego_auth_footer(TALLOC_CTX *mem_ctx,
682 struct spnego_context *sp_ctx,
683 enum dcerpc_AuthLevel auth_level,
684 DATA_BLOB *data, DATA_BLOB *full_pkt,
685 DATA_BLOB *auth_token)
686{
687 switch (auth_level) {
688 case DCERPC_AUTH_LEVEL_PRIVACY:
689 /* Data portion is encrypted. */
690 return spnego_unseal(mem_ctx, sp_ctx,
691 data, full_pkt, auth_token);
692
693 case DCERPC_AUTH_LEVEL_INTEGRITY:
694 /* Data is signed. */
695 return spnego_sigcheck(mem_ctx, sp_ctx,
696 data, full_pkt, auth_token);
697
698 default:
699 return NT_STATUS_INVALID_PARAMETER;
700 }
701}
702
703/**
704* @brief Append an auth footer according to what is the current mechanism
705*
706* @param auth The pipe_auth_data associated with the connection
707* @param pad_len The padding used in the packet
708* @param rpc_out Packet blob up to and including the auth header
709*
710* @return A NTSTATUS error code.
711*/
712NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
713 size_t pad_len, DATA_BLOB *rpc_out)
714{
715 struct schannel_state *schannel_auth;
716 struct auth_ntlmssp_state *ntlmssp_ctx;
717 struct spnego_context *spnego_ctx;
718 struct gse_context *gse_ctx;
719 char pad[CLIENT_NDR_PADDING_SIZE] = { 0, };
720 DATA_BLOB auth_info;
721 DATA_BLOB auth_blob;
722 NTSTATUS status;
723
724 if (auth->auth_type == DCERPC_AUTH_TYPE_NONE ||
725 auth->auth_type == DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM) {
726 return NT_STATUS_OK;
727 }
728
729 if (pad_len) {
730 /* Copy the sign/seal padding data. */
731 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
732 return NT_STATUS_NO_MEMORY;
733 }
734 }
735
736 /* marshall the dcerpc_auth with an actually empty auth_blob.
737 * This is needed because the ntmlssp signature includes the
738 * auth header. We will append the actual blob later. */
739 auth_blob = data_blob_null;
740 status = dcerpc_push_dcerpc_auth(rpc_out->data,
741 auth->auth_type,
742 auth->auth_level,
743 pad_len,
744 auth->auth_context_id,
745 &auth_blob,
746 &auth_info);
747 if (!NT_STATUS_IS_OK(status)) {
748 return status;
749 }
750
751 /* append the header */
752 if (!data_blob_append(NULL, rpc_out,
753 auth_info.data, auth_info.length)) {
754 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
755 (unsigned int)auth_info.length));
756 return NT_STATUS_NO_MEMORY;
757 }
758 data_blob_free(&auth_info);
759
760 /* Generate any auth sign/seal and add the auth footer. */
761 switch (auth->auth_type) {
762 case DCERPC_AUTH_TYPE_NONE:
763 case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
764 status = NT_STATUS_OK;
765 break;
766 case DCERPC_AUTH_TYPE_SPNEGO:
767 spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
768 struct spnego_context);
769 status = add_spnego_auth_footer(spnego_ctx,
770 auth->auth_level, rpc_out);
771 break;
772 case DCERPC_AUTH_TYPE_NTLMSSP:
773 ntlmssp_ctx = talloc_get_type_abort(auth->auth_ctx,
774 struct auth_ntlmssp_state);
775 status = add_ntlmssp_auth_footer(ntlmssp_ctx,
776 auth->auth_level,
777 rpc_out);
778 break;
779 case DCERPC_AUTH_TYPE_SCHANNEL:
780 schannel_auth = talloc_get_type_abort(auth->auth_ctx,
781 struct schannel_state);
782 status = add_schannel_auth_footer(schannel_auth,
783 auth->auth_level,
784 rpc_out);
785 break;
786 case DCERPC_AUTH_TYPE_KRB5:
787 gse_ctx = talloc_get_type_abort(auth->auth_ctx,
788 struct gse_context);
789 status = add_gssapi_auth_footer(gse_ctx,
790 auth->auth_level,
791 rpc_out);
792 break;
793 default:
794 status = NT_STATUS_INVALID_PARAMETER;
795 break;
796 }
797
798 return status;
799}
800
801/**
802* @brief Check authentication for request/response packets
803*
804* @param auth The auth data for the connection
805* @param pkt The actual ncacn_packet
806* @param pkt_trailer [in][out] The stub_and_verifier part of the packet,
807* the auth_trailer and padding will be removed.
808* @param header_size The header size
809* @param raw_pkt The whole raw packet data blob
810*
811* @return A NTSTATUS error code
812*/
813NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
814 struct ncacn_packet *pkt,
815 DATA_BLOB *pkt_trailer,
816 uint8_t header_size,
817 DATA_BLOB *raw_pkt)
818{
819 struct schannel_state *schannel_auth;
820 struct auth_ntlmssp_state *ntlmssp_ctx;
821 struct spnego_context *spnego_ctx;
822 struct gse_context *gse_ctx;
823 NTSTATUS status;
824 struct dcerpc_auth auth_info;
825 uint32_t auth_length;
826 DATA_BLOB full_pkt;
827 DATA_BLOB data;
828
829 /*
830 * These check should be done in the caller.
831 */
832 SMB_ASSERT(raw_pkt->length == pkt->frag_length);
833 SMB_ASSERT(header_size <= pkt->frag_length);
834 SMB_ASSERT(pkt_trailer->length < pkt->frag_length);
835 SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length);
836
837 switch (auth->auth_level) {
838 case DCERPC_AUTH_LEVEL_PRIVACY:
839 DEBUG(10, ("Requested Privacy.\n"));
840 break;
841
842 case DCERPC_AUTH_LEVEL_INTEGRITY:
843 DEBUG(10, ("Requested Integrity.\n"));
844 break;
845
846 case DCERPC_AUTH_LEVEL_CONNECT:
847 if (pkt->auth_length != 0) {
848 break;
849 }
850 return NT_STATUS_OK;
851
852 case DCERPC_AUTH_LEVEL_NONE:
853 if (pkt->auth_length != 0) {
854 DEBUG(3, ("Got non-zero auth len on non "
855 "authenticated connection!\n"));
856 return NT_STATUS_INVALID_PARAMETER;
857 }
858 return NT_STATUS_OK;
859
860 default:
861 DEBUG(3, ("Unimplemented Auth Level %d",
862 auth->auth_level));
863 return NT_STATUS_INVALID_PARAMETER;
864 }
865
866 if (pkt->auth_length == 0) {
867 return NT_STATUS_INVALID_PARAMETER;
868 }
869
870 status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
871 &auth_info, &auth_length, false);
872 if (!NT_STATUS_IS_OK(status)) {
873 return status;
874 }
875
876 if (auth_info.auth_type != auth->auth_type) {
877 return NT_STATUS_INVALID_PARAMETER;
878 }
879
880 if (auth_info.auth_level != auth->auth_level) {
881 return NT_STATUS_INVALID_PARAMETER;
882 }
883
884 if (auth_info.auth_context_id != auth->auth_context_id) {
885 return NT_STATUS_INVALID_PARAMETER;
886 }
887
888 pkt_trailer->length -= auth_length;
889 data = data_blob_const(raw_pkt->data + header_size,
890 pkt_trailer->length);
891 full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length);
892 full_pkt.length -= auth_info.credentials.length;
893
894 switch (auth->auth_type) {
895 case DCERPC_AUTH_TYPE_NONE:
896 case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
897 return NT_STATUS_OK;
898
899 case DCERPC_AUTH_TYPE_SPNEGO:
900 spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
901 struct spnego_context);
902 status = get_spnego_auth_footer(pkt, spnego_ctx,
903 auth->auth_level,
904 &data, &full_pkt,
905 &auth_info.credentials);
906 if (!NT_STATUS_IS_OK(status)) {
907 return status;
908 }
909 break;
910
911 case DCERPC_AUTH_TYPE_NTLMSSP:
912
913 DEBUG(10, ("NTLMSSP auth\n"));
914
915 ntlmssp_ctx = talloc_get_type_abort(auth->auth_ctx,
916 struct auth_ntlmssp_state);
917 status = get_ntlmssp_auth_footer(ntlmssp_ctx,
918 auth->auth_level,
919 &data, &full_pkt,
920 &auth_info.credentials);
921 if (!NT_STATUS_IS_OK(status)) {
922 return status;
923 }
924 break;
925
926 case DCERPC_AUTH_TYPE_SCHANNEL:
927
928 DEBUG(10, ("SCHANNEL auth\n"));
929
930 schannel_auth = talloc_get_type_abort(auth->auth_ctx,
931 struct schannel_state);
932 status = get_schannel_auth_footer(pkt, schannel_auth,
933 auth->auth_level,
934 &data, &full_pkt,
935 &auth_info.credentials);
936 if (!NT_STATUS_IS_OK(status)) {
937 return status;
938 }
939 break;
940
941 case DCERPC_AUTH_TYPE_KRB5:
942
943 DEBUG(10, ("KRB5 auth\n"));
944
945 gse_ctx = talloc_get_type_abort(auth->auth_ctx,
946 struct gse_context);
947 status = get_gssapi_auth_footer(pkt, gse_ctx,
948 auth->auth_level,
949 &data, &full_pkt,
950 &auth_info.credentials);
951 if (!NT_STATUS_IS_OK(status)) {
952 return status;
953 }
954 break;
955
956 default:
957 DEBUG(0, ("process_request_pdu: "
958 "unknown auth type %u set.\n",
959 (unsigned int)auth->auth_type));
960 return NT_STATUS_INVALID_PARAMETER;
961 }
962
963 /* TODO: remove later
964 * this is still needed because in the server code the
965 * pkt_trailer actually has a copy of the raw data, and they
966 * are still both used in later calls */
967 if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
968 if (pkt_trailer->length != data.length) {
969 return NT_STATUS_INVALID_PARAMETER;
970 }
971 memcpy(pkt_trailer->data, data.data, data.length);
972 }
973
974 pkt_trailer->length -= auth_info.auth_pad_length;
975 data_blob_free(&auth_info.credentials);
976 return NT_STATUS_OK;
977}
978
Note: See TracBrowser for help on using the repository browser.