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