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