s3-librpc Call SPENGO/GSSAPI via the auth_generic layer and gensec
[tridge/samba.git] / source3 / librpc / rpc / dcerpc_helpers.c
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 "librpc/crypto/gse.h"
28 #include "librpc/crypto/spnego.h"
29 #include "auth/gensec/gensec.h"
30
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_RPC_PARSE
33
34 /**
35 * @brief NDR Encodes a ncacn_packet
36 *
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
44 *
45 * @return an NTSTATUS error code
46 */
47 NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx,
48                                   enum dcerpc_pkt_type ptype,
49                                   uint8_t pfc_flags,
50                                   uint16_t auth_length,
51                                   uint32_t call_id,
52                                   union dcerpc_payload *u,
53                                   DATA_BLOB *blob)
54 {
55         struct ncacn_packet r;
56         enum ndr_err_code ndr_err;
57
58         r.rpc_vers              = 5;
59         r.rpc_vers_minor        = 0;
60         r.ptype                 = ptype;
61         r.pfc_flags             = pfc_flags;
62         r.drep[0]               = DCERPC_DREP_LE;
63         r.drep[1]               = 0;
64         r.drep[2]               = 0;
65         r.drep[3]               = 0;
66         r.auth_length           = auth_length;
67         r.call_id               = call_id;
68         r.u                     = *u;
69
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);
74         }
75
76         dcerpc_set_frag_length(blob, blob->length);
77
78
79         if (DEBUGLEVEL >= 10) {
80                 /* set frag len for print function */
81                 r.frag_length = blob->length;
82                 NDR_PRINT_DEBUG(ncacn_packet, &r);
83         }
84
85         return NT_STATUS_OK;
86 }
87
88 /**
89 * @brief Decodes a ncacn_packet
90 *
91 * @param mem_ctx        The memory context on which to allocate the packet
92 *                       elements
93 * @param blob           The blob of data to decode
94 * @param r              An empty ncacn_packet, must not be NULL
95 * @param bigendian      Whether the packet is bignedian encoded
96 *
97 * @return a NTSTATUS error code
98 */
99 NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
100                                   const DATA_BLOB *blob,
101                                   struct ncacn_packet *r,
102                                   bool bigendian)
103 {
104         enum ndr_err_code ndr_err;
105         struct ndr_pull *ndr;
106
107         ndr = ndr_pull_init_blob(blob, mem_ctx);
108         if (!ndr) {
109                 return NT_STATUS_NO_MEMORY;
110         }
111         if (bigendian) {
112                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
113         }
114
115         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, r);
116
117         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
118                 talloc_free(ndr);
119                 return ndr_map_error2ntstatus(ndr_err);
120         }
121         talloc_free(ndr);
122
123         if (DEBUGLEVEL >= 10) {
124                 NDR_PRINT_DEBUG(ncacn_packet, r);
125         }
126
127         return NT_STATUS_OK;
128 }
129
130 /**
131 * @brief NDR Encodes a NL_AUTH_MESSAGE
132 *
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
136 *
137 * @return a NTSTATUS error code
138 */
139 NTSTATUS dcerpc_push_schannel_bind(TALLOC_CTX *mem_ctx,
140                                    struct NL_AUTH_MESSAGE *r,
141                                    DATA_BLOB *blob)
142 {
143         enum ndr_err_code ndr_err;
144
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);
149         }
150
151         if (DEBUGLEVEL >= 10) {
152                 NDR_PRINT_DEBUG(NL_AUTH_MESSAGE, r);
153         }
154
155         return NT_STATUS_OK;
156 }
157
158 /**
159 * @brief NDR Encodes a dcerpc_auth structure
160 *
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
169 *
170 * @return a NTSTATUS error code
171 */
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)
179 {
180         struct dcerpc_auth r;
181         enum ndr_err_code ndr_err;
182
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;
189
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);
194         }
195
196         if (DEBUGLEVEL >= 10) {
197                 NDR_PRINT_DEBUG(dcerpc_auth, &r);
198         }
199
200         return NT_STATUS_OK;
201 }
202
203 /**
204 * @brief Decodes a dcerpc_auth blob
205 *
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
210 *
211 * @return a NTSTATUS error code
212 */
213 NTSTATUS dcerpc_pull_dcerpc_auth(TALLOC_CTX *mem_ctx,
214                                  const DATA_BLOB *blob,
215                                  struct dcerpc_auth *r,
216                                  bool bigendian)
217 {
218         enum ndr_err_code ndr_err;
219         struct ndr_pull *ndr;
220
221         ndr = ndr_pull_init_blob(blob, mem_ctx);
222         if (!ndr) {
223                 return NT_STATUS_NO_MEMORY;
224         }
225         if (bigendian) {
226                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
227         }
228
229         ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, r);
230
231         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
232                 talloc_free(ndr);
233                 return ndr_map_error2ntstatus(ndr_err);
234         }
235         talloc_free(ndr);
236
237         if (DEBUGLEVEL >= 10) {
238                 NDR_PRINT_DEBUG(dcerpc_auth, r);
239         }
240
241         return NT_STATUS_OK;
242 }
243
244 /**
245 * @brief Calculate how much data we can in a packet, including calculating
246 *        auth token and pad lengths.
247 *
248 * @param auth           The pipe_auth_data structure for this pipe.
249 * @param header_len     The length of the packet header
250 * @param data_left      The data left in the send buffer
251 * @param max_xmit_frag  The max fragment size.
252 * @param pad_alignment  The NDR padding size.
253 * @param data_to_send   [out] The max data we will send in the pdu
254 * @param frag_len       [out] The total length of the fragment
255 * @param auth_len       [out] The length of the auth trailer
256 * @param pad_len        [out] The padding to be applied
257 *
258 * @return A NT Error status code.
259 */
260 NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
261                             size_t header_len, size_t data_left,
262                             size_t max_xmit_frag, size_t pad_alignment,
263                             size_t *data_to_send, size_t *frag_len,
264                             size_t *auth_len, size_t *pad_len)
265 {
266         size_t max_len;
267         size_t mod_len;
268         struct gensec_security *gensec_security;
269         struct schannel_state *schannel_auth;
270         struct spnego_context *spnego_ctx;
271         enum spnego_mech auth_type;
272         NTSTATUS status;
273
274         /* no auth token cases first */
275         switch (auth->auth_level) {
276         case DCERPC_AUTH_LEVEL_NONE:
277         case DCERPC_AUTH_LEVEL_CONNECT:
278         case DCERPC_AUTH_LEVEL_PACKET:
279                 max_len = max_xmit_frag - header_len;
280                 *data_to_send = MIN(max_len, data_left);
281                 *pad_len = 0;
282                 *auth_len = 0;
283                 *frag_len = header_len + *data_to_send;
284                 return NT_STATUS_OK;
285
286         case DCERPC_AUTH_LEVEL_PRIVACY:
287                 break;
288
289         case DCERPC_AUTH_LEVEL_INTEGRITY:
290                 break;
291
292         default:
293                 return NT_STATUS_INVALID_PARAMETER;
294         }
295
296
297         /* Sign/seal case, calculate auth and pad lengths */
298
299         max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH;
300
301         /* Treat the same for all authenticated rpc requests. */
302         switch (auth->auth_type) {
303         case DCERPC_AUTH_TYPE_SPNEGO:
304                 spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
305                                                    struct spnego_context);
306                 status = spnego_get_negotiated_mech(spnego_ctx,
307                                                     &auth_type, &gensec_security);
308                 if (!NT_STATUS_IS_OK(status)) {
309                         return status;
310                 }
311                 *auth_len = gensec_sig_size(gensec_security, max_len);
312                 break;
313
314         case DCERPC_AUTH_TYPE_NTLMSSP:
315         case DCERPC_AUTH_TYPE_KRB5:
316                 gensec_security = talloc_get_type_abort(auth->auth_ctx,
317                                                         struct gensec_security);
318                 *auth_len = gensec_sig_size(gensec_security, max_len);
319                 break;
320
321         case DCERPC_AUTH_TYPE_SCHANNEL:
322                 schannel_auth = talloc_get_type_abort(auth->auth_ctx,
323                                                       struct schannel_state);
324                 *auth_len = netsec_outgoing_sig_size(schannel_auth);
325                 break;
326         default:
327                 return NT_STATUS_INVALID_PARAMETER;
328         }
329
330         max_len -= *auth_len;
331
332         *data_to_send = MIN(max_len, data_left);
333
334         mod_len = (header_len + *data_to_send) % pad_alignment;
335         if (mod_len) {
336                 *pad_len = pad_alignment - mod_len;
337         } else {
338                 *pad_len = 0;
339         }
340
341         if (*data_to_send + *pad_len > max_len) {
342                 *data_to_send -= pad_alignment;
343         }
344
345         *frag_len = header_len + *data_to_send + *pad_len
346                         + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
347
348         return NT_STATUS_OK;
349 }
350
351 /*******************************************************************
352  Create and add the NTLMSSP sign/seal auth data.
353  ********************************************************************/
354
355 static NTSTATUS add_generic_auth_footer(struct gensec_security *gensec_security,
356                                         enum dcerpc_AuthLevel auth_level,
357                                         DATA_BLOB *rpc_out)
358 {
359         uint16_t data_and_pad_len = rpc_out->length
360                                         - DCERPC_RESPONSE_LENGTH
361                                         - DCERPC_AUTH_TRAILER_LENGTH;
362         DATA_BLOB auth_blob;
363         NTSTATUS status;
364
365         if (!gensec_security) {
366                 return NT_STATUS_INVALID_PARAMETER;
367         }
368
369         switch (auth_level) {
370         case DCERPC_AUTH_LEVEL_PRIVACY:
371                 /* Data portion is encrypted. */
372                 status = gensec_seal_packet(gensec_security,
373                                             rpc_out->data,
374                                             rpc_out->data
375                                             + DCERPC_RESPONSE_LENGTH,
376                                             data_and_pad_len,
377                                             rpc_out->data,
378                                             rpc_out->length,
379                                             &auth_blob);
380                 if (!NT_STATUS_IS_OK(status)) {
381                         return status;
382                 }
383                 break;
384
385         case DCERPC_AUTH_LEVEL_INTEGRITY:
386                 /* Data is signed. */
387                 status = gensec_sign_packet(gensec_security,
388                                             rpc_out->data,
389                                             rpc_out->data
390                                             + DCERPC_RESPONSE_LENGTH,
391                                             data_and_pad_len,
392                                             rpc_out->data,
393                                             rpc_out->length,
394                                             &auth_blob);
395                 if (!NT_STATUS_IS_OK(status)) {
396                         return status;
397                 }
398                 break;
399
400         default:
401                 /* Can't happen. */
402                 smb_panic("bad auth level");
403                 /* Notreached. */
404                 return NT_STATUS_INVALID_PARAMETER;
405         }
406
407         /* Finally attach the blob. */
408         if (!data_blob_append(NULL, rpc_out,
409                                 auth_blob.data, auth_blob.length)) {
410                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
411                           (unsigned int)auth_blob.length));
412                 return NT_STATUS_NO_MEMORY;
413         }
414         data_blob_free(&auth_blob);
415
416         return NT_STATUS_OK;
417 }
418
419 /*******************************************************************
420  Check/unseal the NTLMSSP auth data. (Unseal in place).
421  ********************************************************************/
422
423 static NTSTATUS get_generic_auth_footer(struct gensec_security *gensec_security,
424                                         enum dcerpc_AuthLevel auth_level,
425                                         DATA_BLOB *data, DATA_BLOB *full_pkt,
426                                         DATA_BLOB *auth_token)
427 {
428         switch (auth_level) {
429         case DCERPC_AUTH_LEVEL_PRIVACY:
430                 /* Data portion is encrypted. */
431                 return gensec_unseal_packet(gensec_security,
432                                             data->data,
433                                             data->length,
434                                             full_pkt->data,
435                                             full_pkt->length,
436                                             auth_token);
437
438         case DCERPC_AUTH_LEVEL_INTEGRITY:
439                 /* Data is signed. */
440                 return gensec_check_packet(gensec_security,
441                                            data->data,
442                                            data->length,
443                                            full_pkt->data,
444                                            full_pkt->length,
445                                            auth_token);
446
447         default:
448                 return NT_STATUS_INVALID_PARAMETER;
449         }
450 }
451
452 /*******************************************************************
453  Create and add the schannel sign/seal auth data.
454  ********************************************************************/
455
456 static NTSTATUS add_schannel_auth_footer(struct schannel_state *sas,
457                                         enum dcerpc_AuthLevel auth_level,
458                                         DATA_BLOB *rpc_out)
459 {
460         uint8_t *data_p = rpc_out->data + DCERPC_RESPONSE_LENGTH;
461         size_t data_and_pad_len = rpc_out->length
462                                         - DCERPC_RESPONSE_LENGTH
463                                         - DCERPC_AUTH_TRAILER_LENGTH;
464         DATA_BLOB auth_blob;
465         NTSTATUS status;
466
467         if (!sas) {
468                 return NT_STATUS_INVALID_PARAMETER;
469         }
470
471         DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n",
472                         sas->seq_num));
473
474         switch (auth_level) {
475         case DCERPC_AUTH_LEVEL_PRIVACY:
476                 status = netsec_outgoing_packet(sas,
477                                                 rpc_out->data,
478                                                 true,
479                                                 data_p,
480                                                 data_and_pad_len,
481                                                 &auth_blob);
482                 break;
483         case DCERPC_AUTH_LEVEL_INTEGRITY:
484                 status = netsec_outgoing_packet(sas,
485                                                 rpc_out->data,
486                                                 false,
487                                                 data_p,
488                                                 data_and_pad_len,
489                                                 &auth_blob);
490                 break;
491         default:
492                 status = NT_STATUS_INTERNAL_ERROR;
493                 break;
494         }
495
496         if (!NT_STATUS_IS_OK(status)) {
497                 DEBUG(1,("add_schannel_auth_footer: failed to process packet: %s\n",
498                         nt_errstr(status)));
499                 return status;
500         }
501
502         if (DEBUGLEVEL >= 10) {
503                 dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_blob);
504         }
505
506         /* Finally attach the blob. */
507         if (!data_blob_append(NULL, rpc_out,
508                                 auth_blob.data, auth_blob.length)) {
509                 return NT_STATUS_NO_MEMORY;
510         }
511         data_blob_free(&auth_blob);
512
513         return NT_STATUS_OK;
514 }
515
516 /*******************************************************************
517  Check/unseal the Schannel auth data. (Unseal in place).
518  ********************************************************************/
519
520 static NTSTATUS get_schannel_auth_footer(TALLOC_CTX *mem_ctx,
521                                          struct schannel_state *auth_state,
522                                          enum dcerpc_AuthLevel auth_level,
523                                          DATA_BLOB *data, DATA_BLOB *full_pkt,
524                                          DATA_BLOB *auth_token)
525 {
526         switch (auth_level) {
527         case DCERPC_AUTH_LEVEL_PRIVACY:
528                 /* Data portion is encrypted. */
529                 return netsec_incoming_packet(auth_state,
530                                                 true,
531                                                 data->data,
532                                                 data->length,
533                                                 auth_token);
534
535         case DCERPC_AUTH_LEVEL_INTEGRITY:
536                 /* Data is signed. */
537                 return netsec_incoming_packet(auth_state,
538                                                 false,
539                                                 data->data,
540                                                 data->length,
541                                                 auth_token);
542
543         default:
544                 return NT_STATUS_INVALID_PARAMETER;
545         }
546 }
547
548 /*******************************************************************
549  Create and add the spnego-negotiated sign/seal auth data.
550  ********************************************************************/
551
552 static NTSTATUS add_spnego_auth_footer(struct spnego_context *spnego_ctx,
553                                         enum dcerpc_AuthLevel auth_level,
554                                         DATA_BLOB *rpc_out)
555 {
556         DATA_BLOB auth_blob;
557         DATA_BLOB rpc_data;
558         NTSTATUS status;
559
560         if (!spnego_ctx) {
561                 return NT_STATUS_INVALID_PARAMETER;
562         }
563
564         rpc_data = data_blob_const(rpc_out->data
565                                         + DCERPC_RESPONSE_LENGTH,
566                                    rpc_out->length
567                                         - DCERPC_RESPONSE_LENGTH
568                                         - DCERPC_AUTH_TRAILER_LENGTH);
569
570         switch (auth_level) {
571         case DCERPC_AUTH_LEVEL_PRIVACY:
572                 /* Data portion is encrypted. */
573                 status = spnego_seal(rpc_out->data, spnego_ctx,
574                                      &rpc_data, rpc_out, &auth_blob);
575                 break;
576
577                 if (!NT_STATUS_IS_OK(status)) {
578                         return status;
579                 }
580                 break;
581
582         case DCERPC_AUTH_LEVEL_INTEGRITY:
583                 /* Data is signed. */
584                 status = spnego_sign(rpc_out->data, spnego_ctx,
585                                      &rpc_data, rpc_out, &auth_blob);
586                 break;
587
588                 if (!NT_STATUS_IS_OK(status)) {
589                         return status;
590                 }
591                 break;
592
593         default:
594                 /* Can't happen. */
595                 smb_panic("bad auth level");
596                 /* Notreached. */
597                 return NT_STATUS_INVALID_PARAMETER;
598         }
599
600         /* Finally attach the blob. */
601         if (!data_blob_append(NULL, rpc_out,
602                                 auth_blob.data, auth_blob.length)) {
603                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
604                           (unsigned int)auth_blob.length));
605                 return NT_STATUS_NO_MEMORY;
606         }
607         data_blob_free(&auth_blob);
608
609         return NT_STATUS_OK;
610 }
611
612 static NTSTATUS get_spnego_auth_footer(TALLOC_CTX *mem_ctx,
613                                         struct spnego_context *sp_ctx,
614                                         enum dcerpc_AuthLevel auth_level,
615                                         DATA_BLOB *data, DATA_BLOB *full_pkt,
616                                         DATA_BLOB *auth_token)
617 {
618         switch (auth_level) {
619         case DCERPC_AUTH_LEVEL_PRIVACY:
620                 /* Data portion is encrypted. */
621                 return spnego_unseal(mem_ctx, sp_ctx,
622                                      data, full_pkt, auth_token);
623
624         case DCERPC_AUTH_LEVEL_INTEGRITY:
625                 /* Data is signed. */
626                 return spnego_sigcheck(mem_ctx, sp_ctx,
627                                        data, full_pkt, auth_token);
628
629         default:
630                 return NT_STATUS_INVALID_PARAMETER;
631         }
632 }
633
634 /**
635 * @brief   Append an auth footer according to what is the current mechanism
636 *
637 * @param auth           The pipe_auth_data associated with the connection
638 * @param pad_len        The padding used in the packet
639 * @param rpc_out        Packet blob up to and including the auth header
640 *
641 * @return A NTSTATUS error code.
642 */
643 NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
644                                 size_t pad_len, DATA_BLOB *rpc_out)
645 {
646         struct schannel_state *schannel_auth;
647         struct gensec_security *gensec_security;
648         struct spnego_context *spnego_ctx;
649         char pad[CLIENT_NDR_PADDING_SIZE] = { 0, };
650         DATA_BLOB auth_info;
651         DATA_BLOB auth_blob;
652         NTSTATUS status;
653
654         if (auth->auth_type == DCERPC_AUTH_TYPE_NONE ||
655             auth->auth_type == DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM) {
656                 return NT_STATUS_OK;
657         }
658
659         if (pad_len) {
660                 /* Copy the sign/seal padding data. */
661                 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
662                         return NT_STATUS_NO_MEMORY;
663                 }
664         }
665
666         /* marshall the dcerpc_auth with an actually empty auth_blob.
667          * This is needed because the ntmlssp signature includes the
668          * auth header. We will append the actual blob later. */
669         auth_blob = data_blob_null;
670         status = dcerpc_push_dcerpc_auth(rpc_out->data,
671                                          auth->auth_type,
672                                          auth->auth_level,
673                                          pad_len,
674                                          1 /* context id. */,
675                                          &auth_blob,
676                                          &auth_info);
677         if (!NT_STATUS_IS_OK(status)) {
678                 return status;
679         }
680
681         /* append the header */
682         if (!data_blob_append(NULL, rpc_out,
683                                 auth_info.data, auth_info.length)) {
684                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
685                           (unsigned int)auth_info.length));
686                 return NT_STATUS_NO_MEMORY;
687         }
688         data_blob_free(&auth_info);
689
690         /* Generate any auth sign/seal and add the auth footer. */
691         switch (auth->auth_type) {
692         case DCERPC_AUTH_TYPE_NONE:
693         case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
694                 status = NT_STATUS_OK;
695                 break;
696         case DCERPC_AUTH_TYPE_SPNEGO:
697                 spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
698                                                    struct spnego_context);
699                 status = add_spnego_auth_footer(spnego_ctx,
700                                                 auth->auth_level, rpc_out);
701                 break;
702         case DCERPC_AUTH_TYPE_KRB5:
703         case DCERPC_AUTH_TYPE_NTLMSSP:
704                 gensec_security = talloc_get_type_abort(auth->auth_ctx,
705                                                 struct gensec_security);
706                 status = add_generic_auth_footer(gensec_security,
707                                                  auth->auth_level,
708                                                  rpc_out);
709                 break;
710         case DCERPC_AUTH_TYPE_SCHANNEL:
711                 schannel_auth = talloc_get_type_abort(auth->auth_ctx,
712                                                       struct schannel_state);
713                 status = add_schannel_auth_footer(schannel_auth,
714                                                   auth->auth_level,
715                                                   rpc_out);
716                 break;
717         default:
718                 status = NT_STATUS_INVALID_PARAMETER;
719                 break;
720         }
721
722         return status;
723 }
724
725 /**
726 * @brief Check authentication for request/response packets
727 *
728 * @param auth           The auth data for the connection
729 * @param pkt            The actual ncacn_packet
730 * @param pkt_trailer    The stub_and_verifier part of the packet
731 * @param header_size    The header size
732 * @param raw_pkt        The whole raw packet data blob
733 * @param pad_len        [out] The padding length used in the packet
734 *
735 * @return A NTSTATUS error code
736 */
737 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
738                            struct ncacn_packet *pkt,
739                            DATA_BLOB *pkt_trailer,
740                            size_t header_size,
741                            DATA_BLOB *raw_pkt,
742                            size_t *pad_len)
743 {
744         struct schannel_state *schannel_auth;
745         struct gensec_security *gensec_security;
746         struct spnego_context *spnego_ctx;
747         NTSTATUS status;
748         struct dcerpc_auth auth_info;
749         uint32_t auth_length;
750         DATA_BLOB full_pkt;
751         DATA_BLOB data;
752
753         switch (auth->auth_level) {
754         case DCERPC_AUTH_LEVEL_PRIVACY:
755                 DEBUG(10, ("Requested Privacy.\n"));
756                 break;
757
758         case DCERPC_AUTH_LEVEL_INTEGRITY:
759                 DEBUG(10, ("Requested Integrity.\n"));
760                 break;
761
762         case DCERPC_AUTH_LEVEL_CONNECT:
763                 if (pkt->auth_length != 0) {
764                         break;
765                 }
766                 *pad_len = 0;
767                 return NT_STATUS_OK;
768
769         case DCERPC_AUTH_LEVEL_NONE:
770                 if (pkt->auth_length != 0) {
771                         DEBUG(3, ("Got non-zero auth len on non "
772                                   "authenticated connection!\n"));
773                         return NT_STATUS_INVALID_PARAMETER;
774                 }
775                 *pad_len = 0;
776                 return NT_STATUS_OK;
777
778         default:
779                 DEBUG(3, ("Unimplemented Auth Level %d",
780                           auth->auth_level));
781                 return NT_STATUS_INVALID_PARAMETER;
782         }
783
784         /* Paranioa checks for auth_length. */
785         if (pkt->auth_length > pkt->frag_length) {
786                 return NT_STATUS_INFO_LENGTH_MISMATCH;
787         }
788         if (((unsigned int)pkt->auth_length
789              + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) ||
790             ((unsigned int)pkt->auth_length
791              + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
792                 /* Integer wrap attempt. */
793                 return NT_STATUS_INFO_LENGTH_MISMATCH;
794         }
795
796         status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
797                                           &auth_info, &auth_length, false);
798         if (!NT_STATUS_IS_OK(status)) {
799                 return status;
800         }
801
802         data = data_blob_const(raw_pkt->data + header_size,
803                                 pkt_trailer->length - auth_length);
804         full_pkt = data_blob_const(raw_pkt->data,
805                                 raw_pkt->length - auth_info.credentials.length);
806
807         switch (auth->auth_type) {
808         case DCERPC_AUTH_TYPE_NONE:
809         case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
810                 return NT_STATUS_OK;
811
812         case DCERPC_AUTH_TYPE_SPNEGO:
813                 spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
814                                                    struct spnego_context);
815                 status = get_spnego_auth_footer(pkt, spnego_ctx,
816                                                 auth->auth_level,
817                                                 &data, &full_pkt,
818                                                 &auth_info.credentials);
819                 if (!NT_STATUS_IS_OK(status)) {
820                         return status;
821                 }
822                 break;
823
824         case DCERPC_AUTH_TYPE_KRB5:
825         case DCERPC_AUTH_TYPE_NTLMSSP:
826
827                 DEBUG(10, ("GENSEC auth\n"));
828
829                 gensec_security = talloc_get_type_abort(auth->auth_ctx,
830                                                 struct gensec_security);
831                 status = get_generic_auth_footer(gensec_security,
832                                                  auth->auth_level,
833                                                  &data, &full_pkt,
834                                                  &auth_info.credentials);
835                 if (!NT_STATUS_IS_OK(status)) {
836                         return status;
837                 }
838                 break;
839
840         case DCERPC_AUTH_TYPE_SCHANNEL:
841
842                 DEBUG(10, ("SCHANNEL auth\n"));
843
844                 schannel_auth = talloc_get_type_abort(auth->auth_ctx,
845                                                       struct schannel_state);
846                 status = get_schannel_auth_footer(pkt, schannel_auth,
847                                                   auth->auth_level,
848                                                   &data, &full_pkt,
849                                                   &auth_info.credentials);
850                 if (!NT_STATUS_IS_OK(status)) {
851                         return status;
852                 }
853                 break;
854
855         default:
856                 DEBUG(0, ("process_request_pdu: "
857                           "unknown auth type %u set.\n",
858                           (unsigned int)auth->auth_type));
859                 return NT_STATUS_INVALID_PARAMETER;
860         }
861
862         /* TODO: remove later
863          * this is still needed because in the server code the
864          * pkt_trailer actually has a copy of the raw data, and they
865          * are still both used in later calls */
866         if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
867                 memcpy(pkt_trailer->data, data.data, data.length);
868         }
869
870         *pad_len = auth_info.auth_pad_length;
871         data_blob_free(&auth_info.credentials);
872         return NT_STATUS_OK;
873 }
874