s3-librpc: rename get_ntlmssp_auth_footer to be more generic
[kai/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         struct gse_context *gse_ctx;
272         enum spnego_mech auth_type;
273         void *auth_ctx;
274         bool seal = false;
275         NTSTATUS status;
276
277         /* no auth token cases first */
278         switch (auth->auth_level) {
279         case DCERPC_AUTH_LEVEL_NONE:
280         case DCERPC_AUTH_LEVEL_CONNECT:
281         case DCERPC_AUTH_LEVEL_PACKET:
282                 max_len = max_xmit_frag - header_len;
283                 *data_to_send = MIN(max_len, data_left);
284                 *pad_len = 0;
285                 *auth_len = 0;
286                 *frag_len = header_len + *data_to_send;
287                 return NT_STATUS_OK;
288
289         case DCERPC_AUTH_LEVEL_PRIVACY:
290                 seal = true;
291                 break;
292
293         case DCERPC_AUTH_LEVEL_INTEGRITY:
294                 break;
295
296         default:
297                 return NT_STATUS_INVALID_PARAMETER;
298         }
299
300
301         /* Sign/seal case, calculate auth and pad lengths */
302
303         max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH;
304
305         /* Treat the same for all authenticated rpc requests. */
306         switch (auth->auth_type) {
307         case DCERPC_AUTH_TYPE_SPNEGO:
308                 spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
309                                                    struct spnego_context);
310                 status = spnego_get_negotiated_mech(spnego_ctx,
311                                                     &auth_type, &auth_ctx);
312                 if (!NT_STATUS_IS_OK(status)) {
313                         return status;
314                 }
315                 switch (auth_type) {
316                 case SPNEGO_NTLMSSP:
317                         gensec_security = talloc_get_type_abort(auth_ctx,
318                                                                 struct gensec_security);
319                         *auth_len = gensec_sig_size(gensec_security, max_len);
320                         break;
321
322                 case SPNEGO_KRB5:
323                         gse_ctx = talloc_get_type_abort(auth_ctx,
324                                                         struct gse_context);
325                         if (!gse_ctx) {
326                                 return NT_STATUS_INVALID_PARAMETER;
327                         }
328                         *auth_len = gse_get_signature_length(gse_ctx,
329                                                              seal, max_len);
330                         break;
331
332                 default:
333                         return NT_STATUS_INVALID_PARAMETER;
334                 }
335                 break;
336
337         case DCERPC_AUTH_TYPE_NTLMSSP:
338                 gensec_security = talloc_get_type_abort(auth->auth_ctx,
339                                                         struct gensec_security);
340                 *auth_len = gensec_sig_size(gensec_security, max_len);
341                 break;
342
343         case DCERPC_AUTH_TYPE_SCHANNEL:
344                 schannel_auth = talloc_get_type_abort(auth->auth_ctx,
345                                                       struct schannel_state);
346                 *auth_len = netsec_outgoing_sig_size(schannel_auth);
347                 break;
348
349         case DCERPC_AUTH_TYPE_KRB5:
350                 gse_ctx = talloc_get_type_abort(auth->auth_ctx,
351                                                 struct gse_context);
352                 *auth_len = gse_get_signature_length(gse_ctx,
353                                                      seal, max_len);
354                 break;
355
356         default:
357                 return NT_STATUS_INVALID_PARAMETER;
358         }
359
360         max_len -= *auth_len;
361
362         *data_to_send = MIN(max_len, data_left);
363
364         mod_len = (header_len + *data_to_send) % pad_alignment;
365         if (mod_len) {
366                 *pad_len = pad_alignment - mod_len;
367         } else {
368                 *pad_len = 0;
369         }
370
371         if (*data_to_send + *pad_len > max_len) {
372                 *data_to_send -= pad_alignment;
373         }
374
375         *frag_len = header_len + *data_to_send + *pad_len
376                         + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
377
378         return NT_STATUS_OK;
379 }
380
381 /*******************************************************************
382  Create and add the NTLMSSP sign/seal auth data.
383  ********************************************************************/
384
385 static NTSTATUS add_generic_auth_footer(struct gensec_security *gensec_security,
386                                         enum dcerpc_AuthLevel auth_level,
387                                         DATA_BLOB *rpc_out)
388 {
389         uint16_t data_and_pad_len = rpc_out->length
390                                         - DCERPC_RESPONSE_LENGTH
391                                         - DCERPC_AUTH_TRAILER_LENGTH;
392         DATA_BLOB auth_blob;
393         NTSTATUS status;
394
395         if (!gensec_security) {
396                 return NT_STATUS_INVALID_PARAMETER;
397         }
398
399         switch (auth_level) {
400         case DCERPC_AUTH_LEVEL_PRIVACY:
401                 /* Data portion is encrypted. */
402                 status = gensec_seal_packet(gensec_security,
403                                             rpc_out->data,
404                                             rpc_out->data
405                                             + DCERPC_RESPONSE_LENGTH,
406                                             data_and_pad_len,
407                                             rpc_out->data,
408                                             rpc_out->length,
409                                             &auth_blob);
410                 if (!NT_STATUS_IS_OK(status)) {
411                         return status;
412                 }
413                 break;
414
415         case DCERPC_AUTH_LEVEL_INTEGRITY:
416                 /* Data is signed. */
417                 status = gensec_sign_packet(gensec_security,
418                                             rpc_out->data,
419                                             rpc_out->data
420                                             + DCERPC_RESPONSE_LENGTH,
421                                             data_and_pad_len,
422                                             rpc_out->data,
423                                             rpc_out->length,
424                                             &auth_blob);
425                 if (!NT_STATUS_IS_OK(status)) {
426                         return status;
427                 }
428                 break;
429
430         default:
431                 /* Can't happen. */
432                 smb_panic("bad auth level");
433                 /* Notreached. */
434                 return NT_STATUS_INVALID_PARAMETER;
435         }
436
437         /* Finally attach the blob. */
438         if (!data_blob_append(NULL, rpc_out,
439                                 auth_blob.data, auth_blob.length)) {
440                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
441                           (unsigned int)auth_blob.length));
442                 return NT_STATUS_NO_MEMORY;
443         }
444         data_blob_free(&auth_blob);
445
446         return NT_STATUS_OK;
447 }
448
449 /*******************************************************************
450  Check/unseal the NTLMSSP auth data. (Unseal in place).
451  ********************************************************************/
452
453 static NTSTATUS get_generic_auth_footer(struct gensec_security *gensec_security,
454                                         enum dcerpc_AuthLevel auth_level,
455                                         DATA_BLOB *data, DATA_BLOB *full_pkt,
456                                         DATA_BLOB *auth_token)
457 {
458         switch (auth_level) {
459         case DCERPC_AUTH_LEVEL_PRIVACY:
460                 /* Data portion is encrypted. */
461                 return gensec_unseal_packet(gensec_security,
462                                             data->data,
463                                             data->length,
464                                             full_pkt->data,
465                                             full_pkt->length,
466                                             auth_token);
467
468         case DCERPC_AUTH_LEVEL_INTEGRITY:
469                 /* Data is signed. */
470                 return gensec_check_packet(gensec_security,
471                                            data->data,
472                                            data->length,
473                                            full_pkt->data,
474                                            full_pkt->length,
475                                            auth_token);
476
477         default:
478                 return NT_STATUS_INVALID_PARAMETER;
479         }
480 }
481
482 /*******************************************************************
483  Create and add the schannel sign/seal auth data.
484  ********************************************************************/
485
486 static NTSTATUS add_schannel_auth_footer(struct schannel_state *sas,
487                                         enum dcerpc_AuthLevel auth_level,
488                                         DATA_BLOB *rpc_out)
489 {
490         uint8_t *data_p = rpc_out->data + DCERPC_RESPONSE_LENGTH;
491         size_t data_and_pad_len = rpc_out->length
492                                         - DCERPC_RESPONSE_LENGTH
493                                         - DCERPC_AUTH_TRAILER_LENGTH;
494         DATA_BLOB auth_blob;
495         NTSTATUS status;
496
497         if (!sas) {
498                 return NT_STATUS_INVALID_PARAMETER;
499         }
500
501         DEBUG(10,("add_schannel_auth_footer: SCHANNEL seq_num=%d\n",
502                         sas->seq_num));
503
504         switch (auth_level) {
505         case DCERPC_AUTH_LEVEL_PRIVACY:
506                 status = netsec_outgoing_packet(sas,
507                                                 rpc_out->data,
508                                                 true,
509                                                 data_p,
510                                                 data_and_pad_len,
511                                                 &auth_blob);
512                 break;
513         case DCERPC_AUTH_LEVEL_INTEGRITY:
514                 status = netsec_outgoing_packet(sas,
515                                                 rpc_out->data,
516                                                 false,
517                                                 data_p,
518                                                 data_and_pad_len,
519                                                 &auth_blob);
520                 break;
521         default:
522                 status = NT_STATUS_INTERNAL_ERROR;
523                 break;
524         }
525
526         if (!NT_STATUS_IS_OK(status)) {
527                 DEBUG(1,("add_schannel_auth_footer: failed to process packet: %s\n",
528                         nt_errstr(status)));
529                 return status;
530         }
531
532         if (DEBUGLEVEL >= 10) {
533                 dump_NL_AUTH_SIGNATURE(talloc_tos(), &auth_blob);
534         }
535
536         /* Finally attach the blob. */
537         if (!data_blob_append(NULL, rpc_out,
538                                 auth_blob.data, auth_blob.length)) {
539                 return NT_STATUS_NO_MEMORY;
540         }
541         data_blob_free(&auth_blob);
542
543         return NT_STATUS_OK;
544 }
545
546 /*******************************************************************
547  Check/unseal the Schannel auth data. (Unseal in place).
548  ********************************************************************/
549
550 static NTSTATUS get_schannel_auth_footer(TALLOC_CTX *mem_ctx,
551                                          struct schannel_state *auth_state,
552                                          enum dcerpc_AuthLevel auth_level,
553                                          DATA_BLOB *data, DATA_BLOB *full_pkt,
554                                          DATA_BLOB *auth_token)
555 {
556         switch (auth_level) {
557         case DCERPC_AUTH_LEVEL_PRIVACY:
558                 /* Data portion is encrypted. */
559                 return netsec_incoming_packet(auth_state,
560                                                 true,
561                                                 data->data,
562                                                 data->length,
563                                                 auth_token);
564
565         case DCERPC_AUTH_LEVEL_INTEGRITY:
566                 /* Data is signed. */
567                 return netsec_incoming_packet(auth_state,
568                                                 false,
569                                                 data->data,
570                                                 data->length,
571                                                 auth_token);
572
573         default:
574                 return NT_STATUS_INVALID_PARAMETER;
575         }
576 }
577
578 /*******************************************************************
579  Create and add the gssapi sign/seal auth data.
580  ********************************************************************/
581
582 static NTSTATUS add_gssapi_auth_footer(struct gse_context *gse_ctx,
583                                         enum dcerpc_AuthLevel auth_level,
584                                         DATA_BLOB *rpc_out)
585 {
586         DATA_BLOB data;
587         DATA_BLOB auth_blob;
588         NTSTATUS status;
589
590         if (!gse_ctx) {
591                 return NT_STATUS_INVALID_PARAMETER;
592         }
593
594         data.data = rpc_out->data + DCERPC_RESPONSE_LENGTH;
595         data.length = rpc_out->length - DCERPC_RESPONSE_LENGTH
596                                         - DCERPC_AUTH_TRAILER_LENGTH;
597
598         switch (auth_level) {
599         case DCERPC_AUTH_LEVEL_PRIVACY:
600                 status = gse_seal(talloc_tos(), gse_ctx, &data, &auth_blob);
601                 break;
602         case DCERPC_AUTH_LEVEL_INTEGRITY:
603                 status = gse_sign(talloc_tos(), gse_ctx, &data, &auth_blob);
604                 break;
605         default:
606                 status = NT_STATUS_INTERNAL_ERROR;
607                 break;
608         }
609
610         if (!NT_STATUS_IS_OK(status)) {
611                 DEBUG(1, ("Failed to process packet: %s\n",
612                           nt_errstr(status)));
613                 return status;
614         }
615
616         /* Finally attach the blob. */
617         if (!data_blob_append(NULL, rpc_out,
618                                 auth_blob.data, auth_blob.length)) {
619                 return NT_STATUS_NO_MEMORY;
620         }
621
622         data_blob_free(&auth_blob);
623
624         return NT_STATUS_OK;
625 }
626
627 /*******************************************************************
628  Check/unseal the gssapi auth data. (Unseal in place).
629  ********************************************************************/
630
631 static NTSTATUS get_gssapi_auth_footer(TALLOC_CTX *mem_ctx,
632                                         struct gse_context *gse_ctx,
633                                         enum dcerpc_AuthLevel auth_level,
634                                         DATA_BLOB *data, DATA_BLOB *full_pkt,
635                                         DATA_BLOB *auth_token)
636 {
637         /* TODO: pass in full_pkt when
638          * DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN is set */
639         switch (auth_level) {
640         case DCERPC_AUTH_LEVEL_PRIVACY:
641                 /* Data portion is encrypted. */
642                 return gse_unseal(mem_ctx, gse_ctx,
643                                   data, auth_token);
644
645         case DCERPC_AUTH_LEVEL_INTEGRITY:
646                 /* Data is signed. */
647                 return gse_sigcheck(mem_ctx, gse_ctx,
648                                     data, auth_token);
649         default:
650                 return NT_STATUS_INVALID_PARAMETER;
651         }
652 }
653
654 /*******************************************************************
655  Create and add the spnego-negotiated sign/seal auth data.
656  ********************************************************************/
657
658 static NTSTATUS add_spnego_auth_footer(struct spnego_context *spnego_ctx,
659                                         enum dcerpc_AuthLevel auth_level,
660                                         DATA_BLOB *rpc_out)
661 {
662         DATA_BLOB auth_blob;
663         DATA_BLOB rpc_data;
664         NTSTATUS status;
665
666         if (!spnego_ctx) {
667                 return NT_STATUS_INVALID_PARAMETER;
668         }
669
670         rpc_data = data_blob_const(rpc_out->data
671                                         + DCERPC_RESPONSE_LENGTH,
672                                    rpc_out->length
673                                         - DCERPC_RESPONSE_LENGTH
674                                         - DCERPC_AUTH_TRAILER_LENGTH);
675
676         switch (auth_level) {
677         case DCERPC_AUTH_LEVEL_PRIVACY:
678                 /* Data portion is encrypted. */
679                 status = spnego_seal(rpc_out->data, spnego_ctx,
680                                      &rpc_data, rpc_out, &auth_blob);
681                 break;
682
683                 if (!NT_STATUS_IS_OK(status)) {
684                         return status;
685                 }
686                 break;
687
688         case DCERPC_AUTH_LEVEL_INTEGRITY:
689                 /* Data is signed. */
690                 status = spnego_sign(rpc_out->data, spnego_ctx,
691                                      &rpc_data, rpc_out, &auth_blob);
692                 break;
693
694                 if (!NT_STATUS_IS_OK(status)) {
695                         return status;
696                 }
697                 break;
698
699         default:
700                 /* Can't happen. */
701                 smb_panic("bad auth level");
702                 /* Notreached. */
703                 return NT_STATUS_INVALID_PARAMETER;
704         }
705
706         /* Finally attach the blob. */
707         if (!data_blob_append(NULL, rpc_out,
708                                 auth_blob.data, auth_blob.length)) {
709                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
710                           (unsigned int)auth_blob.length));
711                 return NT_STATUS_NO_MEMORY;
712         }
713         data_blob_free(&auth_blob);
714
715         return NT_STATUS_OK;
716 }
717
718 static NTSTATUS get_spnego_auth_footer(TALLOC_CTX *mem_ctx,
719                                         struct spnego_context *sp_ctx,
720                                         enum dcerpc_AuthLevel auth_level,
721                                         DATA_BLOB *data, DATA_BLOB *full_pkt,
722                                         DATA_BLOB *auth_token)
723 {
724         switch (auth_level) {
725         case DCERPC_AUTH_LEVEL_PRIVACY:
726                 /* Data portion is encrypted. */
727                 return spnego_unseal(mem_ctx, sp_ctx,
728                                      data, full_pkt, auth_token);
729
730         case DCERPC_AUTH_LEVEL_INTEGRITY:
731                 /* Data is signed. */
732                 return spnego_sigcheck(mem_ctx, sp_ctx,
733                                        data, full_pkt, auth_token);
734
735         default:
736                 return NT_STATUS_INVALID_PARAMETER;
737         }
738 }
739
740 /**
741 * @brief   Append an auth footer according to what is the current mechanism
742 *
743 * @param auth           The pipe_auth_data associated with the connection
744 * @param pad_len        The padding used in the packet
745 * @param rpc_out        Packet blob up to and including the auth header
746 *
747 * @return A NTSTATUS error code.
748 */
749 NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
750                                 size_t pad_len, DATA_BLOB *rpc_out)
751 {
752         struct schannel_state *schannel_auth;
753         struct gensec_security *gensec_security;
754         struct spnego_context *spnego_ctx;
755         struct gse_context *gse_ctx;
756         char pad[CLIENT_NDR_PADDING_SIZE] = { 0, };
757         DATA_BLOB auth_info;
758         DATA_BLOB auth_blob;
759         NTSTATUS status;
760
761         if (auth->auth_type == DCERPC_AUTH_TYPE_NONE ||
762             auth->auth_type == DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM) {
763                 return NT_STATUS_OK;
764         }
765
766         if (pad_len) {
767                 /* Copy the sign/seal padding data. */
768                 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
769                         return NT_STATUS_NO_MEMORY;
770                 }
771         }
772
773         /* marshall the dcerpc_auth with an actually empty auth_blob.
774          * This is needed because the ntmlssp signature includes the
775          * auth header. We will append the actual blob later. */
776         auth_blob = data_blob_null;
777         status = dcerpc_push_dcerpc_auth(rpc_out->data,
778                                          auth->auth_type,
779                                          auth->auth_level,
780                                          pad_len,
781                                          1 /* context id. */,
782                                          &auth_blob,
783                                          &auth_info);
784         if (!NT_STATUS_IS_OK(status)) {
785                 return status;
786         }
787
788         /* append the header */
789         if (!data_blob_append(NULL, rpc_out,
790                                 auth_info.data, auth_info.length)) {
791                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
792                           (unsigned int)auth_info.length));
793                 return NT_STATUS_NO_MEMORY;
794         }
795         data_blob_free(&auth_info);
796
797         /* Generate any auth sign/seal and add the auth footer. */
798         switch (auth->auth_type) {
799         case DCERPC_AUTH_TYPE_NONE:
800         case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
801                 status = NT_STATUS_OK;
802                 break;
803         case DCERPC_AUTH_TYPE_SPNEGO:
804                 spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
805                                                    struct spnego_context);
806                 status = add_spnego_auth_footer(spnego_ctx,
807                                                 auth->auth_level, rpc_out);
808                 break;
809         case DCERPC_AUTH_TYPE_NTLMSSP:
810                 gensec_security = talloc_get_type_abort(auth->auth_ctx,
811                                                 struct gensec_security);
812                 status = add_generic_auth_footer(gensec_security,
813                                                  auth->auth_level,
814                                                  rpc_out);
815                 break;
816         case DCERPC_AUTH_TYPE_SCHANNEL:
817                 schannel_auth = talloc_get_type_abort(auth->auth_ctx,
818                                                       struct schannel_state);
819                 status = add_schannel_auth_footer(schannel_auth,
820                                                   auth->auth_level,
821                                                   rpc_out);
822                 break;
823         case DCERPC_AUTH_TYPE_KRB5:
824                 gse_ctx = talloc_get_type_abort(auth->auth_ctx,
825                                                 struct gse_context);
826                 status = add_gssapi_auth_footer(gse_ctx,
827                                                 auth->auth_level,
828                                                 rpc_out);
829                 break;
830         default:
831                 status = NT_STATUS_INVALID_PARAMETER;
832                 break;
833         }
834
835         return status;
836 }
837
838 /**
839 * @brief Check authentication for request/response packets
840 *
841 * @param auth           The auth data for the connection
842 * @param pkt            The actual ncacn_packet
843 * @param pkt_trailer    The stub_and_verifier part of the packet
844 * @param header_size    The header size
845 * @param raw_pkt        The whole raw packet data blob
846 * @param pad_len        [out] The padding length used in the packet
847 *
848 * @return A NTSTATUS error code
849 */
850 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
851                            struct ncacn_packet *pkt,
852                            DATA_BLOB *pkt_trailer,
853                            size_t header_size,
854                            DATA_BLOB *raw_pkt,
855                            size_t *pad_len)
856 {
857         struct schannel_state *schannel_auth;
858         struct gensec_security *gensec_security;
859         struct spnego_context *spnego_ctx;
860         struct gse_context *gse_ctx;
861         NTSTATUS status;
862         struct dcerpc_auth auth_info;
863         uint32_t auth_length;
864         DATA_BLOB full_pkt;
865         DATA_BLOB data;
866
867         switch (auth->auth_level) {
868         case DCERPC_AUTH_LEVEL_PRIVACY:
869                 DEBUG(10, ("Requested Privacy.\n"));
870                 break;
871
872         case DCERPC_AUTH_LEVEL_INTEGRITY:
873                 DEBUG(10, ("Requested Integrity.\n"));
874                 break;
875
876         case DCERPC_AUTH_LEVEL_CONNECT:
877                 if (pkt->auth_length != 0) {
878                         break;
879                 }
880                 *pad_len = 0;
881                 return NT_STATUS_OK;
882
883         case DCERPC_AUTH_LEVEL_NONE:
884                 if (pkt->auth_length != 0) {
885                         DEBUG(3, ("Got non-zero auth len on non "
886                                   "authenticated connection!\n"));
887                         return NT_STATUS_INVALID_PARAMETER;
888                 }
889                 *pad_len = 0;
890                 return NT_STATUS_OK;
891
892         default:
893                 DEBUG(3, ("Unimplemented Auth Level %d",
894                           auth->auth_level));
895                 return NT_STATUS_INVALID_PARAMETER;
896         }
897
898         /* Paranioa checks for auth_length. */
899         if (pkt->auth_length > pkt->frag_length) {
900                 return NT_STATUS_INFO_LENGTH_MISMATCH;
901         }
902         if (((unsigned int)pkt->auth_length
903              + DCERPC_AUTH_TRAILER_LENGTH < (unsigned int)pkt->auth_length) ||
904             ((unsigned int)pkt->auth_length
905              + DCERPC_AUTH_TRAILER_LENGTH < DCERPC_AUTH_TRAILER_LENGTH)) {
906                 /* Integer wrap attempt. */
907                 return NT_STATUS_INFO_LENGTH_MISMATCH;
908         }
909
910         status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
911                                           &auth_info, &auth_length, false);
912         if (!NT_STATUS_IS_OK(status)) {
913                 return status;
914         }
915
916         data = data_blob_const(raw_pkt->data + header_size,
917                                 pkt_trailer->length - auth_length);
918         full_pkt = data_blob_const(raw_pkt->data,
919                                 raw_pkt->length - auth_info.credentials.length);
920
921         switch (auth->auth_type) {
922         case DCERPC_AUTH_TYPE_NONE:
923         case DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM:
924                 return NT_STATUS_OK;
925
926         case DCERPC_AUTH_TYPE_SPNEGO:
927                 spnego_ctx = talloc_get_type_abort(auth->auth_ctx,
928                                                    struct spnego_context);
929                 status = get_spnego_auth_footer(pkt, spnego_ctx,
930                                                 auth->auth_level,
931                                                 &data, &full_pkt,
932                                                 &auth_info.credentials);
933                 if (!NT_STATUS_IS_OK(status)) {
934                         return status;
935                 }
936                 break;
937
938         case DCERPC_AUTH_TYPE_NTLMSSP:
939
940                 DEBUG(10, ("GENSEC auth\n"));
941
942                 gensec_security = talloc_get_type_abort(auth->auth_ctx,
943                                                 struct gensec_security);
944                 status = get_generic_auth_footer(gensec_security,
945                                                  auth->auth_level,
946                                                  &data, &full_pkt,
947                                                  &auth_info.credentials);
948                 if (!NT_STATUS_IS_OK(status)) {
949                         return status;
950                 }
951                 break;
952
953         case DCERPC_AUTH_TYPE_SCHANNEL:
954
955                 DEBUG(10, ("SCHANNEL auth\n"));
956
957                 schannel_auth = talloc_get_type_abort(auth->auth_ctx,
958                                                       struct schannel_state);
959                 status = get_schannel_auth_footer(pkt, schannel_auth,
960                                                   auth->auth_level,
961                                                   &data, &full_pkt,
962                                                   &auth_info.credentials);
963                 if (!NT_STATUS_IS_OK(status)) {
964                         return status;
965                 }
966                 break;
967
968         case DCERPC_AUTH_TYPE_KRB5:
969
970                 DEBUG(10, ("KRB5 auth\n"));
971
972                 gse_ctx = talloc_get_type_abort(auth->auth_ctx,
973                                                 struct gse_context);
974                 status = get_gssapi_auth_footer(pkt, gse_ctx,
975                                                 auth->auth_level,
976                                                 &data, &full_pkt,
977                                                 &auth_info.credentials);
978                 if (!NT_STATUS_IS_OK(status)) {
979                         return status;
980                 }
981                 break;
982
983         default:
984                 DEBUG(0, ("process_request_pdu: "
985                           "unknown auth type %u set.\n",
986                           (unsigned int)auth->auth_type));
987                 return NT_STATUS_INVALID_PARAMETER;
988         }
989
990         /* TODO: remove later
991          * this is still needed because in the server code the
992          * pkt_trailer actually has a copy of the raw data, and they
993          * are still both used in later calls */
994         if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
995                 memcpy(pkt_trailer->data, data.data, data.length);
996         }
997
998         *pad_len = auth_info.auth_pad_length;
999         data_blob_free(&auth_info.credentials);
1000         return NT_STATUS_OK;
1001 }
1002