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