s3:librpc: move NDR_PRINT_DEBUG() into the caller of dcerpc_pull_ncacn_packet()
[kamenim/samba-autobuild/.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/crypto/gse.h"
25 #include "auth/gensec/gensec.h"
26
27 #undef DBGC_CLASS
28 #define DBGC_CLASS DBGC_RPC_PARSE
29
30 /**
31 * @brief NDR Encodes a ncacn_packet
32 *
33 * @param mem_ctx        The memory context the blob will be allocated on
34 * @param ptype          The DCERPC packet type
35 * @param pfc_flags      The DCERPC PFC Falgs
36 * @param auth_length    The length of the trailing auth blob
37 * @param call_id        The call ID
38 * @param u              The payload of the packet
39 * @param blob [out]     The encoded blob if successful
40 *
41 * @return an NTSTATUS error code
42 */
43 NTSTATUS dcerpc_push_ncacn_packet(TALLOC_CTX *mem_ctx,
44                                   enum dcerpc_pkt_type ptype,
45                                   uint8_t pfc_flags,
46                                   uint16_t auth_length,
47                                   uint32_t call_id,
48                                   union dcerpc_payload *u,
49                                   DATA_BLOB *blob)
50 {
51         struct ncacn_packet r;
52         enum ndr_err_code ndr_err;
53
54         r.rpc_vers              = 5;
55         r.rpc_vers_minor        = 0;
56         r.ptype                 = ptype;
57         r.pfc_flags             = pfc_flags;
58         r.drep[0]               = DCERPC_DREP_LE;
59         r.drep[1]               = 0;
60         r.drep[2]               = 0;
61         r.drep[3]               = 0;
62         r.auth_length           = auth_length;
63         r.call_id               = call_id;
64         r.u                     = *u;
65
66         ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
67                 (ndr_push_flags_fn_t)ndr_push_ncacn_packet);
68         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
69                 return ndr_map_error2ntstatus(ndr_err);
70         }
71
72         dcerpc_set_frag_length(blob, blob->length);
73
74
75         if (DEBUGLEVEL >= 10) {
76                 /* set frag len for print function */
77                 r.frag_length = blob->length;
78                 NDR_PRINT_DEBUG(ncacn_packet, &r);
79         }
80
81         return NT_STATUS_OK;
82 }
83
84 /**
85 * @brief Decodes a ncacn_packet
86 *
87 * @param mem_ctx        The memory context on which to allocate the packet
88 *                       elements
89 * @param blob           The blob of data to decode
90 * @param r              An empty ncacn_packet, must not be NULL
91 *
92 * @return a NTSTATUS error code
93 */
94 NTSTATUS dcerpc_pull_ncacn_packet(TALLOC_CTX *mem_ctx,
95                                   const DATA_BLOB *blob,
96                                   struct ncacn_packet *r)
97 {
98         enum ndr_err_code ndr_err;
99         struct ndr_pull *ndr;
100
101         ndr = ndr_pull_init_blob(blob, mem_ctx);
102         if (!ndr) {
103                 return NT_STATUS_NO_MEMORY;
104         }
105
106         if (!(CVAL(ndr->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
107                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
108         }
109
110         if (CVAL(ndr->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
111                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
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 (r->frag_length != blob->length) {
123                 return NT_STATUS_RPC_PROTOCOL_ERROR;
124         }
125
126         return NT_STATUS_OK;
127 }
128
129 /**
130 * @brief NDR Encodes a dcerpc_auth structure
131 *
132 * @param mem_ctx          The memory context the blob will be allocated on
133 * @param auth_type        The DCERPC Authentication Type
134 * @param auth_level       The DCERPC Authentication Level
135 * @param auth_pad_length  The padding added to the packet this blob will be
136 *                          appended to.
137 * @param auth_context_id  The context id
138 * @param credentials      The authentication credentials blob (signature)
139 * @param blob [out]       The encoded blob if successful
140 *
141 * @return a NTSTATUS error code
142 */
143 NTSTATUS dcerpc_push_dcerpc_auth(TALLOC_CTX *mem_ctx,
144                                  enum dcerpc_AuthType auth_type,
145                                  enum dcerpc_AuthLevel auth_level,
146                                  uint8_t auth_pad_length,
147                                  uint32_t auth_context_id,
148                                  const DATA_BLOB *credentials,
149                                  DATA_BLOB *blob)
150 {
151         struct dcerpc_auth r;
152         enum ndr_err_code ndr_err;
153
154         r.auth_type             = auth_type;
155         r.auth_level            = auth_level;
156         r.auth_pad_length       = auth_pad_length;
157         r.auth_reserved         = 0;
158         r.auth_context_id       = auth_context_id;
159         r.credentials           = *credentials;
160
161         ndr_err = ndr_push_struct_blob(blob, mem_ctx, &r,
162                 (ndr_push_flags_fn_t)ndr_push_dcerpc_auth);
163         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
164                 return ndr_map_error2ntstatus(ndr_err);
165         }
166
167         if (DEBUGLEVEL >= 10) {
168                 NDR_PRINT_DEBUG(dcerpc_auth, &r);
169         }
170
171         return NT_STATUS_OK;
172 }
173
174 /**
175 * @brief Calculate how much data we can in a packet, including calculating
176 *        auth token and pad lengths.
177 *
178 * @param auth           The pipe_auth_data structure for this pipe.
179 * @param header_len     The length of the packet header
180 * @param data_left      The data left in the send buffer
181 * @param max_xmit_frag  The max fragment size.
182 * @param data_to_send   [out] The max data we will send in the pdu
183 * @param frag_len       [out] The total length of the fragment
184 * @param auth_len       [out] The length of the auth trailer
185 * @param pad_len        [out] The padding to be applied
186 *
187 * @return A NT Error status code.
188 */
189 NTSTATUS dcerpc_guess_sizes(struct pipe_auth_data *auth,
190                             size_t header_len, size_t data_left,
191                             size_t max_xmit_frag,
192                             size_t *data_to_send, size_t *frag_len,
193                             size_t *auth_len, size_t *pad_len)
194 {
195         size_t max_len;
196         size_t mod_len;
197         struct gensec_security *gensec_security;
198
199         /* no auth token cases first */
200         switch (auth->auth_level) {
201         case DCERPC_AUTH_LEVEL_NONE:
202         case DCERPC_AUTH_LEVEL_CONNECT:
203         case DCERPC_AUTH_LEVEL_PACKET:
204                 max_len = max_xmit_frag - header_len;
205                 *data_to_send = MIN(max_len, data_left);
206                 *pad_len = 0;
207                 *auth_len = 0;
208                 *frag_len = header_len + *data_to_send;
209                 return NT_STATUS_OK;
210
211         case DCERPC_AUTH_LEVEL_PRIVACY:
212                 break;
213
214         case DCERPC_AUTH_LEVEL_INTEGRITY:
215                 break;
216
217         default:
218                 return NT_STATUS_INVALID_PARAMETER;
219         }
220
221
222         /* Sign/seal case, calculate auth and pad lengths */
223
224         max_len = max_xmit_frag - header_len - DCERPC_AUTH_TRAILER_LENGTH;
225
226         /* Treat the same for all authenticated rpc requests. */
227         switch (auth->auth_type) {
228         case DCERPC_AUTH_TYPE_SPNEGO:
229         case DCERPC_AUTH_TYPE_NTLMSSP:
230         case DCERPC_AUTH_TYPE_KRB5:
231         case DCERPC_AUTH_TYPE_SCHANNEL:
232                 gensec_security = auth->auth_ctx;
233                 mod_len = (max_len % DCERPC_AUTH_PAD_ALIGNMENT);
234                 *auth_len = gensec_sig_size(gensec_security, max_len - mod_len);
235                 if (*auth_len == 0) {
236                         return NT_STATUS_INTERNAL_ERROR;
237                 }
238                 break;
239         default:
240                 return NT_STATUS_INVALID_PARAMETER;
241         }
242
243         max_len -= *auth_len;
244         mod_len = (max_len % DCERPC_AUTH_PAD_ALIGNMENT);
245         max_len -= mod_len;
246
247         *data_to_send = MIN(max_len, data_left);
248
249         *pad_len = DCERPC_AUTH_PAD_LENGTH(*data_to_send);
250
251         *frag_len = header_len + *data_to_send + *pad_len
252                         + DCERPC_AUTH_TRAILER_LENGTH + *auth_len;
253
254         return NT_STATUS_OK;
255 }
256
257 /*******************************************************************
258  Create and add the NTLMSSP sign/seal auth data.
259  ********************************************************************/
260
261 static NTSTATUS add_generic_auth_footer(struct gensec_security *gensec_security,
262                                         enum dcerpc_AuthLevel auth_level,
263                                         DATA_BLOB *rpc_out)
264 {
265         uint16_t data_and_pad_len = rpc_out->length
266                                         - DCERPC_RESPONSE_LENGTH
267                                         - DCERPC_AUTH_TRAILER_LENGTH;
268         DATA_BLOB auth_blob;
269         NTSTATUS status;
270
271         if (!gensec_security) {
272                 return NT_STATUS_INVALID_PARAMETER;
273         }
274
275         switch (auth_level) {
276         case DCERPC_AUTH_LEVEL_PRIVACY:
277                 /* Data portion is encrypted. */
278                 status = gensec_seal_packet(gensec_security,
279                                             rpc_out->data,
280                                             rpc_out->data
281                                             + DCERPC_RESPONSE_LENGTH,
282                                             data_and_pad_len,
283                                             rpc_out->data,
284                                             rpc_out->length,
285                                             &auth_blob);
286                 if (!NT_STATUS_IS_OK(status)) {
287                         return status;
288                 }
289                 break;
290
291         case DCERPC_AUTH_LEVEL_INTEGRITY:
292                 /* Data is signed. */
293                 status = gensec_sign_packet(gensec_security,
294                                             rpc_out->data,
295                                             rpc_out->data
296                                             + DCERPC_RESPONSE_LENGTH,
297                                             data_and_pad_len,
298                                             rpc_out->data,
299                                             rpc_out->length,
300                                             &auth_blob);
301                 if (!NT_STATUS_IS_OK(status)) {
302                         return status;
303                 }
304                 break;
305
306         default:
307                 /* Can't happen. */
308                 smb_panic("bad auth level");
309                 /* Notreached. */
310                 return NT_STATUS_INVALID_PARAMETER;
311         }
312
313         /* Finally attach the blob. */
314         if (!data_blob_append(NULL, rpc_out,
315                                 auth_blob.data, auth_blob.length)) {
316                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
317                           (unsigned int)auth_blob.length));
318                 return NT_STATUS_NO_MEMORY;
319         }
320         data_blob_free(&auth_blob);
321
322         return NT_STATUS_OK;
323 }
324
325 /*******************************************************************
326  Check/unseal the NTLMSSP auth data. (Unseal in place).
327  ********************************************************************/
328
329 static NTSTATUS get_generic_auth_footer(struct gensec_security *gensec_security,
330                                         enum dcerpc_AuthLevel auth_level,
331                                         DATA_BLOB *data, DATA_BLOB *full_pkt,
332                                         DATA_BLOB *auth_token)
333 {
334         if (gensec_security == NULL) {
335                 return NT_STATUS_INVALID_PARAMETER;
336         }
337
338         switch (auth_level) {
339         case DCERPC_AUTH_LEVEL_PRIVACY:
340                 /* Data portion is encrypted. */
341                 return gensec_unseal_packet(gensec_security,
342                                             data->data,
343                                             data->length,
344                                             full_pkt->data,
345                                             full_pkt->length,
346                                             auth_token);
347
348         case DCERPC_AUTH_LEVEL_INTEGRITY:
349                 /* Data is signed. */
350                 return gensec_check_packet(gensec_security,
351                                            data->data,
352                                            data->length,
353                                            full_pkt->data,
354                                            full_pkt->length,
355                                            auth_token);
356
357         default:
358                 return NT_STATUS_INVALID_PARAMETER;
359         }
360 }
361
362 /**
363 * @brief   Append an auth footer according to what is the current mechanism
364 *
365 * @param auth           The pipe_auth_data associated with the connection
366 * @param pad_len        The padding used in the packet
367 * @param rpc_out        Packet blob up to and including the auth header
368 *
369 * @return A NTSTATUS error code.
370 */
371 NTSTATUS dcerpc_add_auth_footer(struct pipe_auth_data *auth,
372                                 size_t pad_len, DATA_BLOB *rpc_out)
373 {
374         struct gensec_security *gensec_security;
375         const char pad[DCERPC_AUTH_PAD_ALIGNMENT] = { 0, };
376         DATA_BLOB auth_info;
377         DATA_BLOB auth_blob;
378         NTSTATUS status;
379
380         if (auth->auth_type == DCERPC_AUTH_TYPE_NONE) {
381                 return NT_STATUS_OK;
382         }
383
384         if (pad_len) {
385                 SMB_ASSERT(pad_len <= ARRAY_SIZE(pad));
386
387                 /* Copy the sign/seal padding data. */
388                 if (!data_blob_append(NULL, rpc_out, pad, pad_len)) {
389                         return NT_STATUS_NO_MEMORY;
390                 }
391         }
392
393         /* marshall the dcerpc_auth with an actually empty auth_blob.
394          * This is needed because the ntmlssp signature includes the
395          * auth header. We will append the actual blob later. */
396         auth_blob = data_blob_null;
397         status = dcerpc_push_dcerpc_auth(rpc_out->data,
398                                          auth->auth_type,
399                                          auth->auth_level,
400                                          pad_len,
401                                          auth->auth_context_id,
402                                          &auth_blob,
403                                          &auth_info);
404         if (!NT_STATUS_IS_OK(status)) {
405                 return status;
406         }
407
408         /* append the header */
409         if (!data_blob_append(NULL, rpc_out,
410                                 auth_info.data, auth_info.length)) {
411                 DEBUG(0, ("Failed to add %u bytes auth blob.\n",
412                           (unsigned int)auth_info.length));
413                 return NT_STATUS_NO_MEMORY;
414         }
415         data_blob_free(&auth_info);
416
417         /* Generate any auth sign/seal and add the auth footer. */
418         switch (auth->auth_type) {
419         case DCERPC_AUTH_TYPE_NONE:
420                 status = NT_STATUS_OK;
421                 break;
422         default:
423                 gensec_security = auth->auth_ctx;
424                 status = add_generic_auth_footer(gensec_security,
425                                                  auth->auth_level,
426                                                  rpc_out);
427                 break;
428         }
429
430         return status;
431 }
432
433 /**
434 * @brief Check authentication for request/response packets
435 *
436 * @param auth           The auth data for the connection
437 * @param pkt            The actual ncacn_packet
438 * @param pkt_trailer [in][out]  The stub_and_verifier part of the packet,
439 *                       the auth_trailer and padding will be removed.
440 * @param header_size    The header size
441 * @param raw_pkt        The whole raw packet data blob
442 *
443 * @return A NTSTATUS error code
444 */
445 NTSTATUS dcerpc_check_auth(struct pipe_auth_data *auth,
446                            struct ncacn_packet *pkt,
447                            DATA_BLOB *pkt_trailer,
448                            uint8_t header_size,
449                            DATA_BLOB *raw_pkt)
450 {
451         struct gensec_security *gensec_security;
452         NTSTATUS status;
453         struct dcerpc_auth auth_info;
454         uint32_t auth_length;
455         DATA_BLOB full_pkt;
456         DATA_BLOB data;
457
458         /*
459          * These check should be done in the caller.
460          */
461         SMB_ASSERT(raw_pkt->length == pkt->frag_length);
462         SMB_ASSERT(header_size <= pkt->frag_length);
463         SMB_ASSERT(pkt_trailer->length < pkt->frag_length);
464         SMB_ASSERT((pkt_trailer->length + header_size) <= pkt->frag_length);
465
466         switch (auth->auth_level) {
467         case DCERPC_AUTH_LEVEL_PRIVACY:
468                 DEBUG(10, ("Requested Privacy.\n"));
469                 break;
470
471         case DCERPC_AUTH_LEVEL_INTEGRITY:
472                 DEBUG(10, ("Requested Integrity.\n"));
473                 break;
474
475         case DCERPC_AUTH_LEVEL_CONNECT:
476                 if (pkt->auth_length != 0) {
477                         break;
478                 }
479                 return NT_STATUS_OK;
480
481         case DCERPC_AUTH_LEVEL_NONE:
482                 if (pkt->auth_length != 0) {
483                         DEBUG(3, ("Got non-zero auth len on non "
484                                   "authenticated connection!\n"));
485                         return NT_STATUS_INVALID_PARAMETER;
486                 }
487                 return NT_STATUS_OK;
488
489         default:
490                 DEBUG(3, ("Unimplemented Auth Level %d",
491                           auth->auth_level));
492                 return NT_STATUS_INVALID_PARAMETER;
493         }
494
495         if (pkt->auth_length == 0) {
496                 return NT_STATUS_INVALID_PARAMETER;
497         }
498
499         status = dcerpc_pull_auth_trailer(pkt, pkt, pkt_trailer,
500                                           &auth_info, &auth_length, false);
501         if (!NT_STATUS_IS_OK(status)) {
502                 return status;
503         }
504
505         if (auth_info.auth_type != auth->auth_type) {
506                 return NT_STATUS_INVALID_PARAMETER;
507         }
508
509         if (auth_info.auth_level != auth->auth_level) {
510                 return NT_STATUS_INVALID_PARAMETER;
511         }
512
513         if (auth_info.auth_context_id != auth->auth_context_id) {
514                 return NT_STATUS_INVALID_PARAMETER;
515         }
516
517         pkt_trailer->length -= auth_length;
518         data = data_blob_const(raw_pkt->data + header_size,
519                                pkt_trailer->length);
520         full_pkt = data_blob_const(raw_pkt->data, raw_pkt->length);
521         full_pkt.length -= auth_info.credentials.length;
522
523         switch (auth->auth_type) {
524         case DCERPC_AUTH_TYPE_NONE:
525                 return NT_STATUS_OK;
526
527         default:
528                 DEBUG(10, ("GENSEC auth\n"));
529
530                 gensec_security = auth->auth_ctx;
531                 status = get_generic_auth_footer(gensec_security,
532                                                  auth->auth_level,
533                                                  &data, &full_pkt,
534                                                  &auth_info.credentials);
535                 if (!NT_STATUS_IS_OK(status)) {
536                         return status;
537                 }
538                 break;
539         }
540
541         /* TODO: remove later
542          * this is still needed because in the server code the
543          * pkt_trailer actually has a copy of the raw data, and they
544          * are still both used in later calls */
545         if (auth->auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
546                 if (pkt_trailer->length != data.length) {
547                         return NT_STATUS_INVALID_PARAMETER;
548                 }
549                 memcpy(pkt_trailer->data, data.data, data.length);
550         }
551
552         pkt_trailer->length -= auth_info.auth_pad_length;
553         data_blob_free(&auth_info.credentials);
554         return NT_STATUS_OK;
555 }
556