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