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