librpc/rpc: finally maintain only the object guid
[amitay/samba.git] / librpc / rpc / dcerpc_util.c
1 /*
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Andrew Tridgell 2003-2005
6    Copyright (C) Jelmer Vernooij 2004-2005
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 3 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22 #include "includes.h"
23 #include "system/network.h"
24 #include <tevent.h>
25 #include "lib/tsocket/tsocket.h"
26 #include "lib/util/tevent_ntstatus.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "rpc_common.h"
30 #include "lib/util/bitmap.h"
31
32 /* we need to be able to get/set the fragment length without doing a full
33    decode */
34 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
35 {
36         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
37                 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
38         } else {
39                 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
40         }
41 }
42
43 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
44 {
45         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
46                 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
47         } else {
48                 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
49         }
50 }
51
52 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
53 {
54         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
55                 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
56         } else {
57                 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
58         }
59 }
60
61 uint8_t dcerpc_get_endian_flag(DATA_BLOB *blob)
62 {
63         return blob->data[DCERPC_DREP_OFFSET];
64 }
65
66
67 /**
68 * @brief        Pull a dcerpc_auth structure, taking account of any auth
69 *               padding in the blob. For request/response packets we pass
70 *               the whole data blob, so auth_data_only must be set to false
71 *               as the blob contains data+pad+auth and no just pad+auth.
72 *
73 * @param pkt            - The ncacn_packet strcuture
74 * @param mem_ctx        - The mem_ctx used to allocate dcerpc_auth elements
75 * @param pkt_trailer    - The packet trailer data, usually the trailing
76 *                         auth_info blob, but in the request/response case
77 *                         this is the stub_and_verifier blob.
78 * @param auth           - A preallocated dcerpc_auth *empty* structure
79 * @param auth_length    - The length of the auth trail, sum of auth header
80 *                         lenght and pkt->auth_length
81 * @param auth_data_only - Whether the pkt_trailer includes only the auth_blob
82 *                         (+ padding) or also other data.
83 *
84 * @return               - A NTSTATUS error code.
85 */
86 NTSTATUS dcerpc_pull_auth_trailer(struct ncacn_packet *pkt,
87                                   TALLOC_CTX *mem_ctx,
88                                   DATA_BLOB *pkt_trailer,
89                                   struct dcerpc_auth *auth,
90                                   uint32_t *auth_length,
91                                   bool auth_data_only)
92 {
93         struct ndr_pull *ndr;
94         enum ndr_err_code ndr_err;
95         uint32_t data_and_pad;
96
97         data_and_pad = pkt_trailer->length
98                         - (DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length);
99
100         /* paranoia check for pad size. This would be caught anyway by
101            the ndr_pull_advance() a few lines down, but it scared
102            Jeremy enough for him to call me, so we might as well check
103            it now, just to prevent someone posting a bogus YouTube
104            video in the future.
105         */
106         if (data_and_pad > pkt_trailer->length) {
107                 return NT_STATUS_INFO_LENGTH_MISMATCH;
108         }
109
110         *auth_length = pkt_trailer->length - data_and_pad;
111
112         ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx);
113         if (!ndr) {
114                 return NT_STATUS_NO_MEMORY;
115         }
116
117         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
118                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
119         }
120
121         ndr_err = ndr_pull_advance(ndr, data_and_pad);
122         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
123                 talloc_free(ndr);
124                 return ndr_map_error2ntstatus(ndr_err);
125         }
126
127         ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
128         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
129                 talloc_free(ndr);
130                 return ndr_map_error2ntstatus(ndr_err);
131         }
132
133         if (auth_data_only && data_and_pad != auth->auth_pad_length) {
134                 DEBUG(1, (__location__ ": WARNING: pad length mismatch. "
135                           "Calculated %u  got %u\n",
136                           (unsigned)data_and_pad,
137                           (unsigned)auth->auth_pad_length));
138         }
139
140         DEBUG(6,(__location__ ": auth_pad_length %u\n",
141                  (unsigned)auth->auth_pad_length));
142
143         talloc_steal(mem_ctx, auth->credentials.data);
144         talloc_free(ndr);
145
146         return NT_STATUS_OK;
147 }
148
149 struct dcerpc_read_ncacn_packet_state {
150 #if 0
151         struct {
152         } caller;
153 #endif
154         DATA_BLOB buffer;
155         struct ncacn_packet *pkt;
156 };
157
158 static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
159                                                 void *private_data,
160                                                 TALLOC_CTX *mem_ctx,
161                                                 struct iovec **_vector,
162                                                 size_t *_count);
163 static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq);
164
165 struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
166                                                  struct tevent_context *ev,
167                                                  struct tstream_context *stream)
168 {
169         struct tevent_req *req;
170         struct dcerpc_read_ncacn_packet_state *state;
171         struct tevent_req *subreq;
172
173         req = tevent_req_create(mem_ctx, &state,
174                                 struct dcerpc_read_ncacn_packet_state);
175         if (req == NULL) {
176                 return NULL;
177         }
178
179         state->buffer = data_blob_const(NULL, 0);
180         state->pkt = talloc(state, struct ncacn_packet);
181         if (tevent_req_nomem(state->pkt, req)) {
182                 goto post;
183         }
184
185         subreq = tstream_readv_pdu_send(state, ev,
186                                         stream,
187                                         dcerpc_read_ncacn_packet_next_vector,
188                                         state);
189         if (tevent_req_nomem(subreq, req)) {
190                 goto post;
191         }
192         tevent_req_set_callback(subreq, dcerpc_read_ncacn_packet_done, req);
193
194         return req;
195  post:
196         tevent_req_post(req, ev);
197         return req;
198 }
199
200 static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
201                                                 void *private_data,
202                                                 TALLOC_CTX *mem_ctx,
203                                                 struct iovec **_vector,
204                                                 size_t *_count)
205 {
206         struct dcerpc_read_ncacn_packet_state *state =
207                 talloc_get_type_abort(private_data,
208                 struct dcerpc_read_ncacn_packet_state);
209         struct iovec *vector;
210         off_t ofs = 0;
211
212         if (state->buffer.length == 0) {
213                 /*
214                  * first get enough to read the fragment length
215                  *
216                  * We read the full fixed ncacn_packet header
217                  * in order to make wireshark happy with
218                  * pcap files from socket_wrapper.
219                  */
220                 ofs = 0;
221                 state->buffer.length = DCERPC_NCACN_PAYLOAD_OFFSET;
222                 state->buffer.data = talloc_array(state, uint8_t,
223                                                   state->buffer.length);
224                 if (!state->buffer.data) {
225                         return -1;
226                 }
227         } else if (state->buffer.length == DCERPC_NCACN_PAYLOAD_OFFSET) {
228                 /* now read the fragment length and allocate the full buffer */
229                 size_t frag_len = dcerpc_get_frag_length(&state->buffer);
230
231                 ofs = state->buffer.length;
232
233                 if (frag_len < ofs) {
234                         /*
235                          * something is wrong, let the caller deal with it
236                          */
237                         *_vector = NULL;
238                         *_count = 0;
239                         return 0;
240                 }
241
242                 state->buffer.data = talloc_realloc(state,
243                                                     state->buffer.data,
244                                                     uint8_t, frag_len);
245                 if (!state->buffer.data) {
246                         return -1;
247                 }
248                 state->buffer.length = frag_len;
249         } else {
250                 /* if we reach this we have a full fragment */
251                 *_vector = NULL;
252                 *_count = 0;
253                 return 0;
254         }
255
256         /* now create the vector that we want to be filled */
257         vector = talloc_array(mem_ctx, struct iovec, 1);
258         if (!vector) {
259                 return -1;
260         }
261
262         vector[0].iov_base = (void *) (state->buffer.data + ofs);
263         vector[0].iov_len = state->buffer.length - ofs;
264
265         *_vector = vector;
266         *_count = 1;
267         return 0;
268 }
269
270 static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq)
271 {
272         struct tevent_req *req = tevent_req_callback_data(subreq,
273                                  struct tevent_req);
274         struct dcerpc_read_ncacn_packet_state *state = tevent_req_data(req,
275                                         struct dcerpc_read_ncacn_packet_state);
276         int ret;
277         int sys_errno;
278         struct ndr_pull *ndr;
279         enum ndr_err_code ndr_err;
280         NTSTATUS status;
281
282         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
283         TALLOC_FREE(subreq);
284         if (ret == -1) {
285                 status = map_nt_error_from_unix_common(sys_errno);
286                 tevent_req_nterror(req, status);
287                 return;
288         }
289
290         ndr = ndr_pull_init_blob(&state->buffer, state->pkt);
291         if (tevent_req_nomem(ndr, req)) {
292                 return;
293         }
294
295         if (!(CVAL(ndr->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
296                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
297         }
298
299         if (CVAL(ndr->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
300                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
301         }
302
303         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, state->pkt);
304         TALLOC_FREE(ndr);
305         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
306                 status = ndr_map_error2ntstatus(ndr_err);
307                 tevent_req_nterror(req, status);
308                 return;
309         }
310
311         if (state->pkt->frag_length != state->buffer.length) {
312                 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
313                 return;
314         }
315
316         tevent_req_done(req);
317 }
318
319 NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
320                                        TALLOC_CTX *mem_ctx,
321                                        struct ncacn_packet **pkt,
322                                        DATA_BLOB *buffer)
323 {
324         struct dcerpc_read_ncacn_packet_state *state = tevent_req_data(req,
325                                         struct dcerpc_read_ncacn_packet_state);
326         NTSTATUS status;
327
328         if (tevent_req_is_nterror(req, &status)) {
329                 tevent_req_received(req);
330                 return status;
331         }
332
333         *pkt = talloc_move(mem_ctx, &state->pkt);
334         if (buffer) {
335                 buffer->data = talloc_move(mem_ctx, &state->buffer.data);
336                 buffer->length = state->buffer.length;
337         }
338
339         tevent_req_received(req);
340         return NT_STATUS_OK;
341 }
342
343 const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx,
344                                               enum dcerpc_transport_t transport,
345                                               const struct ndr_interface_table *table)
346 {
347         NTSTATUS status;
348         const char *p = NULL;
349         const char *endpoint = NULL;
350         int i;
351         struct dcerpc_binding *default_binding = NULL;
352         TALLOC_CTX *frame = talloc_stackframe();
353
354         /* Find one of the default pipes for this interface */
355
356         for (i = 0; i < table->endpoints->count; i++) {
357                 enum dcerpc_transport_t dtransport;
358                 const char *dendpoint;
359
360                 status = dcerpc_parse_binding(frame, table->endpoints->names[i],
361                                               &default_binding);
362                 if (!NT_STATUS_IS_OK(status)) {
363                         continue;
364                 }
365
366                 dtransport = dcerpc_binding_get_transport(default_binding);
367                 dendpoint = dcerpc_binding_get_string_option(default_binding,
368                                                              "endpoint");
369                 if (dendpoint == NULL) {
370                         TALLOC_FREE(default_binding);
371                         continue;
372                 }
373
374                 if (transport == NCA_UNKNOWN) {
375                         transport = dtransport;
376                 }
377
378                 if (transport != dtransport) {
379                         TALLOC_FREE(default_binding);
380                         continue;
381                 }
382
383                 p = dendpoint;
384                 break;
385         }
386
387         if (p == NULL) {
388                 goto done;
389         }
390
391         /*
392          * extract the pipe name without \\pipe from for example
393          * ncacn_np:[\\pipe\\epmapper]
394          */
395         if (transport == NCACN_NP) {
396                 if (strncasecmp(p, "\\pipe\\", 6) == 0) {
397                         p += 6;
398                 }
399                 if (strncmp(p, "\\", 1) == 0) {
400                         p += 1;
401                 }
402         }
403
404         endpoint = talloc_strdup(mem_ctx, p);
405
406  done:
407         talloc_free(frame);
408         return endpoint;
409 }
410
411 struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struct ncacn_packet *pkt)
412 {
413         struct dcerpc_sec_vt_header2 ret;
414
415         ZERO_STRUCT(ret);
416         ret.ptype = pkt->ptype;
417         memcpy(&ret.drep, pkt->drep, sizeof(ret.drep));
418         ret.call_id = pkt->call_id;
419
420         switch (pkt->ptype) {
421         case DCERPC_PKT_REQUEST:
422                 ret.context_id = pkt->u.request.context_id;
423                 ret.opnum      = pkt->u.request.opnum;
424                 break;
425
426         case DCERPC_PKT_RESPONSE:
427                 ret.context_id = pkt->u.response.context_id;
428                 break;
429
430         case DCERPC_PKT_FAULT:
431                 ret.context_id = pkt->u.fault.context_id;
432                 break;
433
434         default:
435                 break;
436         }
437
438         return ret;
439 }
440
441 bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
442                                  const struct dcerpc_sec_vt_header2 *v2)
443 {
444         if (v1->ptype != v2->ptype) {
445                 return false;
446         }
447
448         if (memcmp(v1->drep, v2->drep, sizeof(v1->drep)) != 0) {
449                 return false;
450         }
451
452         if (v1->call_id != v2->call_id) {
453                 return false;
454         }
455
456         if (v1->context_id != v2->context_id) {
457                 return false;
458         }
459
460         if (v1->opnum != v2->opnum) {
461                 return false;
462         }
463
464         return true;
465 }
466
467 static bool dcerpc_sec_vt_is_valid(const struct dcerpc_sec_verification_trailer *r)
468 {
469         bool ret = false;
470         TALLOC_CTX *frame = talloc_stackframe();
471         struct bitmap *commands_seen;
472         int i;
473
474         if (r->count.count == 0) {
475                 ret = true;
476                 goto done;
477         }
478
479         if (memcmp(r->magic, DCERPC_SEC_VT_MAGIC, sizeof(r->magic)) != 0) {
480                 goto done;
481         }
482
483         commands_seen = bitmap_talloc(frame, DCERPC_SEC_VT_COMMAND_ENUM + 1);
484         if (commands_seen == NULL) {
485                 goto done;
486         }
487
488         for (i=0; i < r->count.count; i++) {
489                 enum dcerpc_sec_vt_command_enum cmd =
490                         r->commands[i].command & DCERPC_SEC_VT_COMMAND_ENUM;
491
492                 if (bitmap_query(commands_seen, cmd)) {
493                         /* Each command must appear at most once. */
494                         goto done;
495                 }
496                 bitmap_set(commands_seen, cmd);
497
498                 switch (cmd) {
499                 case DCERPC_SEC_VT_COMMAND_BITMASK1:
500                 case DCERPC_SEC_VT_COMMAND_PCONTEXT:
501                 case DCERPC_SEC_VT_COMMAND_HEADER2:
502                         break;
503                 default:
504                         if ((r->commands[i].u._unknown.length % 4) != 0) {
505                                 goto done;
506                         }
507                         break;
508                 }
509         }
510         ret = true;
511 done:
512         TALLOC_FREE(frame);
513         return ret;
514 }
515
516 static bool dcerpc_sec_vt_bitmask_check(const uint32_t *bitmask1,
517                                         struct dcerpc_sec_vt *c)
518 {
519         if (bitmask1 == NULL) {
520                 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
521                         DEBUG(10, ("SEC_VT check Bitmask1 must_process_command "
522                                    "failed\n"));
523                         return false;
524                 }
525
526                 return true;
527         }
528
529         if ((c->u.bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING)
530          && (!(*bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING))) {
531                 DEBUG(10, ("SEC_VT check Bitmask1 client_header_signing "
532                            "failed\n"));
533                 return false;
534         }
535         return true;
536 }
537
538 static bool dcerpc_sec_vt_pctx_check(const struct dcerpc_sec_vt_pcontext *pcontext,
539                                      struct dcerpc_sec_vt *c)
540 {
541         TALLOC_CTX *mem_ctx;
542         bool ok;
543
544         if (pcontext == NULL) {
545                 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
546                         DEBUG(10, ("SEC_VT check Pcontext must_process_command "
547                                    "failed\n"));
548                         return false;
549                 }
550
551                 return true;
552         }
553
554         mem_ctx = talloc_stackframe();
555         ok = ndr_syntax_id_equal(&pcontext->abstract_syntax,
556                                  &c->u.pcontext.abstract_syntax);
557         if (!ok) {
558                 DEBUG(10, ("SEC_VT check pcontext abstract_syntax failed: "
559                            "%s vs. %s\n",
560                            ndr_syntax_id_to_string(mem_ctx,
561                                         &pcontext->abstract_syntax),
562                            ndr_syntax_id_to_string(mem_ctx,
563                                         &c->u.pcontext.abstract_syntax)));
564                 goto err_ctx_free;
565         }
566         ok = ndr_syntax_id_equal(&pcontext->transfer_syntax,
567                                  &c->u.pcontext.transfer_syntax);
568         if (!ok) {
569                 DEBUG(10, ("SEC_VT check pcontext transfer_syntax failed: "
570                            "%s vs. %s\n",
571                            ndr_syntax_id_to_string(mem_ctx,
572                                         &pcontext->transfer_syntax),
573                            ndr_syntax_id_to_string(mem_ctx,
574                                         &c->u.pcontext.transfer_syntax)));
575                 goto err_ctx_free;
576         }
577
578         ok = true;
579 err_ctx_free:
580         talloc_free(mem_ctx);
581         return ok;
582 }
583
584 static bool dcerpc_sec_vt_hdr2_check(const struct dcerpc_sec_vt_header2 *header2,
585                                      struct dcerpc_sec_vt *c)
586 {
587         if (header2 == NULL) {
588                 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
589                         DEBUG(10, ("SEC_VT check Header2 must_process_command failed\n"));
590                         return false;
591                 }
592
593                 return true;
594         }
595
596         if (!dcerpc_sec_vt_header2_equal(header2, &c->u.header2)) {
597                 DEBUG(10, ("SEC_VT check Header2 failed\n"));
598                 return false;
599         }
600
601         return true;
602 }
603
604 bool dcerpc_sec_verification_trailer_check(
605                 const struct dcerpc_sec_verification_trailer *vt,
606                 const uint32_t *bitmask1,
607                 const struct dcerpc_sec_vt_pcontext *pcontext,
608                 const struct dcerpc_sec_vt_header2 *header2)
609 {
610         size_t i;
611
612         if (!dcerpc_sec_vt_is_valid(vt)) {
613                 return false;
614         }
615
616         for (i=0; i < vt->count.count; i++) {
617                 bool ok;
618                 struct dcerpc_sec_vt *c = &vt->commands[i];
619
620                 switch (c->command & DCERPC_SEC_VT_COMMAND_ENUM) {
621                 case DCERPC_SEC_VT_COMMAND_BITMASK1:
622                         ok = dcerpc_sec_vt_bitmask_check(bitmask1, c);
623                         if (!ok) {
624                                 return false;
625                         }
626                         break;
627
628                 case DCERPC_SEC_VT_COMMAND_PCONTEXT:
629                         ok = dcerpc_sec_vt_pctx_check(pcontext, c);
630                         if (!ok) {
631                                 return false;
632                         }
633                         break;
634
635                 case DCERPC_SEC_VT_COMMAND_HEADER2: {
636                         ok = dcerpc_sec_vt_hdr2_check(header2, c);
637                         if (!ok) {
638                                 return false;
639                         }
640                         break;
641                 }
642
643                 default:
644                         if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
645                                 DEBUG(10, ("SEC_VT check Unknown must_process_command failed\n"));
646                                 return false;
647                         }
648
649                         break;
650                 }
651         }
652
653         return true;
654 }