CVE-2015-5370: librpc/rpc: don't allow pkt->auth_length == 0 in dcerpc_pull_auth_trai...
[kai/samba-autobuild/.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(const struct ncacn_packet *pkt,
87                                   TALLOC_CTX *mem_ctx,
88                                   const 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         uint16_t data_and_pad;
96         uint16_t auth_length;
97         uint32_t tmp_length;
98
99         ZERO_STRUCTP(auth);
100         if (_auth_length != NULL) {
101                 *_auth_length = 0;
102         }
103
104         /* Paranoia checks for auth_length. The caller should check this... */
105         if (pkt->auth_length == 0) {
106                 return NT_STATUS_INTERNAL_ERROR;
107         }
108
109         /* Paranoia checks for auth_length. The caller should check this... */
110         if (pkt->auth_length > pkt->frag_length) {
111                 return NT_STATUS_INTERNAL_ERROR;
112         }
113         tmp_length = DCERPC_NCACN_PAYLOAD_OFFSET;
114         tmp_length += DCERPC_AUTH_TRAILER_LENGTH;
115         tmp_length += pkt->auth_length;
116         if (tmp_length > pkt->frag_length) {
117                 return NT_STATUS_INTERNAL_ERROR;
118         }
119         if (pkt_trailer->length > UINT16_MAX) {
120                 return NT_STATUS_INTERNAL_ERROR;
121         }
122
123         auth_length = DCERPC_AUTH_TRAILER_LENGTH + pkt->auth_length;
124         if (pkt_trailer->length < auth_length) {
125                 return NT_STATUS_RPC_PROTOCOL_ERROR;
126         }
127
128         data_and_pad = pkt_trailer->length - auth_length;
129
130         ndr = ndr_pull_init_blob(pkt_trailer, mem_ctx);
131         if (!ndr) {
132                 return NT_STATUS_NO_MEMORY;
133         }
134
135         if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
136                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
137         }
138
139         ndr_err = ndr_pull_advance(ndr, data_and_pad);
140         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
141                 talloc_free(ndr);
142                 return ndr_map_error2ntstatus(ndr_err);
143         }
144
145         ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, auth);
146         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
147                 talloc_free(ndr);
148                 ZERO_STRUCTP(auth);
149                 return ndr_map_error2ntstatus(ndr_err);
150         }
151
152         if (data_and_pad < auth->auth_pad_length) {
153                 DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
154                           "Calculated %u  got %u\n",
155                           (unsigned)data_and_pad,
156                           (unsigned)auth->auth_pad_length));
157                 talloc_free(ndr);
158                 ZERO_STRUCTP(auth);
159                 return NT_STATUS_RPC_PROTOCOL_ERROR;
160         }
161
162         if (auth_data_only && data_and_pad != auth->auth_pad_length) {
163                 DEBUG(1, (__location__ ": ERROR: pad length mismatch. "
164                           "Calculated %u  got %u\n",
165                           (unsigned)data_and_pad,
166                           (unsigned)auth->auth_pad_length));
167                 talloc_free(ndr);
168                 ZERO_STRUCTP(auth);
169                 return NT_STATUS_RPC_PROTOCOL_ERROR;
170         }
171
172         DEBUG(6,(__location__ ": auth_pad_length %u\n",
173                  (unsigned)auth->auth_pad_length));
174
175         talloc_steal(mem_ctx, auth->credentials.data);
176         talloc_free(ndr);
177
178         if (_auth_length != NULL) {
179                 *_auth_length = auth_length;
180         }
181
182         return NT_STATUS_OK;
183 }
184
185 /**
186 * @brief        Verify the fields in ncacn_packet header.
187 *
188 * @param pkt            - The ncacn_packet strcuture
189 * @param ptype          - The expected PDU type
190 * @param max_auth_info  - The maximum size of a possible auth trailer
191 * @param required_flags - The required flags for the pdu.
192 * @param optional_flags - The possible optional flags for the pdu.
193 *
194 * @return               - A NTSTATUS error code.
195 */
196 NTSTATUS dcerpc_verify_ncacn_packet_header(const struct ncacn_packet *pkt,
197                                            enum dcerpc_pkt_type ptype,
198                                            size_t max_auth_info,
199                                            uint8_t required_flags,
200                                            uint8_t optional_flags)
201 {
202         if (pkt->rpc_vers != 5) {
203                 return NT_STATUS_RPC_PROTOCOL_ERROR;
204         }
205
206         if (pkt->rpc_vers_minor != 0) {
207                 return NT_STATUS_RPC_PROTOCOL_ERROR;
208         }
209
210         if (pkt->auth_length > pkt->frag_length) {
211                 return NT_STATUS_RPC_PROTOCOL_ERROR;
212         }
213
214         if (pkt->ptype != ptype) {
215                 return NT_STATUS_RPC_PROTOCOL_ERROR;
216         }
217
218         if (max_auth_info > UINT16_MAX) {
219                 return NT_STATUS_INTERNAL_ERROR;
220         }
221
222         if (pkt->auth_length > 0) {
223                 size_t max_auth_length;
224
225                 if (max_auth_info <= DCERPC_AUTH_TRAILER_LENGTH) {
226                         return NT_STATUS_RPC_PROTOCOL_ERROR;
227                 }
228                 max_auth_length = max_auth_info - DCERPC_AUTH_TRAILER_LENGTH;
229
230                 if (pkt->auth_length > max_auth_length) {
231                         return NT_STATUS_RPC_PROTOCOL_ERROR;
232                 }
233         }
234
235         if ((pkt->pfc_flags & required_flags) != required_flags) {
236                 return NT_STATUS_RPC_PROTOCOL_ERROR;
237         }
238         if (pkt->pfc_flags & ~(optional_flags|required_flags)) {
239                 return NT_STATUS_RPC_PROTOCOL_ERROR;
240         }
241
242         if (pkt->drep[0] & ~DCERPC_DREP_LE) {
243                 return NT_STATUS_RPC_PROTOCOL_ERROR;
244         }
245         if (pkt->drep[1] != 0) {
246                 return NT_STATUS_RPC_PROTOCOL_ERROR;
247         }
248         if (pkt->drep[2] != 0) {
249                 return NT_STATUS_RPC_PROTOCOL_ERROR;
250         }
251         if (pkt->drep[3] != 0) {
252                 return NT_STATUS_RPC_PROTOCOL_ERROR;
253         }
254
255         return NT_STATUS_OK;
256 }
257
258 struct dcerpc_read_ncacn_packet_state {
259 #if 0
260         struct {
261         } caller;
262 #endif
263         DATA_BLOB buffer;
264         struct ncacn_packet *pkt;
265 };
266
267 static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
268                                                 void *private_data,
269                                                 TALLOC_CTX *mem_ctx,
270                                                 struct iovec **_vector,
271                                                 size_t *_count);
272 static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq);
273
274 struct tevent_req *dcerpc_read_ncacn_packet_send(TALLOC_CTX *mem_ctx,
275                                                  struct tevent_context *ev,
276                                                  struct tstream_context *stream)
277 {
278         struct tevent_req *req;
279         struct dcerpc_read_ncacn_packet_state *state;
280         struct tevent_req *subreq;
281
282         req = tevent_req_create(mem_ctx, &state,
283                                 struct dcerpc_read_ncacn_packet_state);
284         if (req == NULL) {
285                 return NULL;
286         }
287
288         state->buffer = data_blob_const(NULL, 0);
289         state->pkt = talloc(state, struct ncacn_packet);
290         if (tevent_req_nomem(state->pkt, req)) {
291                 goto post;
292         }
293
294         subreq = tstream_readv_pdu_send(state, ev,
295                                         stream,
296                                         dcerpc_read_ncacn_packet_next_vector,
297                                         state);
298         if (tevent_req_nomem(subreq, req)) {
299                 goto post;
300         }
301         tevent_req_set_callback(subreq, dcerpc_read_ncacn_packet_done, req);
302
303         return req;
304  post:
305         tevent_req_post(req, ev);
306         return req;
307 }
308
309 static int dcerpc_read_ncacn_packet_next_vector(struct tstream_context *stream,
310                                                 void *private_data,
311                                                 TALLOC_CTX *mem_ctx,
312                                                 struct iovec **_vector,
313                                                 size_t *_count)
314 {
315         struct dcerpc_read_ncacn_packet_state *state =
316                 talloc_get_type_abort(private_data,
317                 struct dcerpc_read_ncacn_packet_state);
318         struct iovec *vector;
319         off_t ofs = 0;
320
321         if (state->buffer.length == 0) {
322                 /*
323                  * first get enough to read the fragment length
324                  *
325                  * We read the full fixed ncacn_packet header
326                  * in order to make wireshark happy with
327                  * pcap files from socket_wrapper.
328                  */
329                 ofs = 0;
330                 state->buffer.length = DCERPC_NCACN_PAYLOAD_OFFSET;
331                 state->buffer.data = talloc_array(state, uint8_t,
332                                                   state->buffer.length);
333                 if (!state->buffer.data) {
334                         return -1;
335                 }
336         } else if (state->buffer.length == DCERPC_NCACN_PAYLOAD_OFFSET) {
337                 /* now read the fragment length and allocate the full buffer */
338                 size_t frag_len = dcerpc_get_frag_length(&state->buffer);
339
340                 ofs = state->buffer.length;
341
342                 if (frag_len < ofs) {
343                         /*
344                          * something is wrong, let the caller deal with it
345                          */
346                         *_vector = NULL;
347                         *_count = 0;
348                         return 0;
349                 }
350
351                 state->buffer.data = talloc_realloc(state,
352                                                     state->buffer.data,
353                                                     uint8_t, frag_len);
354                 if (!state->buffer.data) {
355                         return -1;
356                 }
357                 state->buffer.length = frag_len;
358         } else {
359                 /* if we reach this we have a full fragment */
360                 *_vector = NULL;
361                 *_count = 0;
362                 return 0;
363         }
364
365         /* now create the vector that we want to be filled */
366         vector = talloc_array(mem_ctx, struct iovec, 1);
367         if (!vector) {
368                 return -1;
369         }
370
371         vector[0].iov_base = (void *) (state->buffer.data + ofs);
372         vector[0].iov_len = state->buffer.length - ofs;
373
374         *_vector = vector;
375         *_count = 1;
376         return 0;
377 }
378
379 static void dcerpc_read_ncacn_packet_done(struct tevent_req *subreq)
380 {
381         struct tevent_req *req = tevent_req_callback_data(subreq,
382                                  struct tevent_req);
383         struct dcerpc_read_ncacn_packet_state *state = tevent_req_data(req,
384                                         struct dcerpc_read_ncacn_packet_state);
385         int ret;
386         int sys_errno;
387         struct ndr_pull *ndr;
388         enum ndr_err_code ndr_err;
389         NTSTATUS status;
390
391         ret = tstream_readv_pdu_recv(subreq, &sys_errno);
392         TALLOC_FREE(subreq);
393         if (ret == -1) {
394                 status = map_nt_error_from_unix_common(sys_errno);
395                 tevent_req_nterror(req, status);
396                 return;
397         }
398
399         ndr = ndr_pull_init_blob(&state->buffer, state->pkt);
400         if (tevent_req_nomem(ndr, req)) {
401                 return;
402         }
403
404         if (!(CVAL(ndr->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
405                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
406         }
407
408         if (CVAL(ndr->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
409                 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
410         }
411
412         ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, state->pkt);
413         TALLOC_FREE(ndr);
414         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
415                 status = ndr_map_error2ntstatus(ndr_err);
416                 tevent_req_nterror(req, status);
417                 return;
418         }
419
420         if (state->pkt->frag_length != state->buffer.length) {
421                 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
422                 return;
423         }
424
425         tevent_req_done(req);
426 }
427
428 NTSTATUS dcerpc_read_ncacn_packet_recv(struct tevent_req *req,
429                                        TALLOC_CTX *mem_ctx,
430                                        struct ncacn_packet **pkt,
431                                        DATA_BLOB *buffer)
432 {
433         struct dcerpc_read_ncacn_packet_state *state = tevent_req_data(req,
434                                         struct dcerpc_read_ncacn_packet_state);
435         NTSTATUS status;
436
437         if (tevent_req_is_nterror(req, &status)) {
438                 tevent_req_received(req);
439                 return status;
440         }
441
442         *pkt = talloc_move(mem_ctx, &state->pkt);
443         if (buffer) {
444                 buffer->data = talloc_move(mem_ctx, &state->buffer.data);
445                 buffer->length = state->buffer.length;
446         }
447
448         tevent_req_received(req);
449         return NT_STATUS_OK;
450 }
451
452 const char *dcerpc_default_transport_endpoint(TALLOC_CTX *mem_ctx,
453                                               enum dcerpc_transport_t transport,
454                                               const struct ndr_interface_table *table)
455 {
456         NTSTATUS status;
457         const char *p = NULL;
458         const char *endpoint = NULL;
459         int i;
460         struct dcerpc_binding *default_binding = NULL;
461         TALLOC_CTX *frame = talloc_stackframe();
462
463         /* Find one of the default pipes for this interface */
464
465         for (i = 0; i < table->endpoints->count; i++) {
466                 enum dcerpc_transport_t dtransport;
467                 const char *dendpoint;
468
469                 status = dcerpc_parse_binding(frame, table->endpoints->names[i],
470                                               &default_binding);
471                 if (!NT_STATUS_IS_OK(status)) {
472                         continue;
473                 }
474
475                 dtransport = dcerpc_binding_get_transport(default_binding);
476                 dendpoint = dcerpc_binding_get_string_option(default_binding,
477                                                              "endpoint");
478                 if (dendpoint == NULL) {
479                         TALLOC_FREE(default_binding);
480                         continue;
481                 }
482
483                 if (transport == NCA_UNKNOWN) {
484                         transport = dtransport;
485                 }
486
487                 if (transport != dtransport) {
488                         TALLOC_FREE(default_binding);
489                         continue;
490                 }
491
492                 p = dendpoint;
493                 break;
494         }
495
496         if (p == NULL) {
497                 goto done;
498         }
499
500         /*
501          * extract the pipe name without \\pipe from for example
502          * ncacn_np:[\\pipe\\epmapper]
503          */
504         if (transport == NCACN_NP) {
505                 if (strncasecmp(p, "\\pipe\\", 6) == 0) {
506                         p += 6;
507                 }
508                 if (strncmp(p, "\\", 1) == 0) {
509                         p += 1;
510                 }
511         }
512
513         endpoint = talloc_strdup(mem_ctx, p);
514
515  done:
516         talloc_free(frame);
517         return endpoint;
518 }
519
520 struct dcerpc_sec_vt_header2 dcerpc_sec_vt_header2_from_ncacn_packet(const struct ncacn_packet *pkt)
521 {
522         struct dcerpc_sec_vt_header2 ret;
523
524         ZERO_STRUCT(ret);
525         ret.ptype = pkt->ptype;
526         memcpy(&ret.drep, pkt->drep, sizeof(ret.drep));
527         ret.call_id = pkt->call_id;
528
529         switch (pkt->ptype) {
530         case DCERPC_PKT_REQUEST:
531                 ret.context_id = pkt->u.request.context_id;
532                 ret.opnum      = pkt->u.request.opnum;
533                 break;
534
535         case DCERPC_PKT_RESPONSE:
536                 ret.context_id = pkt->u.response.context_id;
537                 break;
538
539         case DCERPC_PKT_FAULT:
540                 ret.context_id = pkt->u.fault.context_id;
541                 break;
542
543         default:
544                 break;
545         }
546
547         return ret;
548 }
549
550 bool dcerpc_sec_vt_header2_equal(const struct dcerpc_sec_vt_header2 *v1,
551                                  const struct dcerpc_sec_vt_header2 *v2)
552 {
553         if (v1->ptype != v2->ptype) {
554                 return false;
555         }
556
557         if (memcmp(v1->drep, v2->drep, sizeof(v1->drep)) != 0) {
558                 return false;
559         }
560
561         if (v1->call_id != v2->call_id) {
562                 return false;
563         }
564
565         if (v1->context_id != v2->context_id) {
566                 return false;
567         }
568
569         if (v1->opnum != v2->opnum) {
570                 return false;
571         }
572
573         return true;
574 }
575
576 static bool dcerpc_sec_vt_is_valid(const struct dcerpc_sec_verification_trailer *r)
577 {
578         bool ret = false;
579         TALLOC_CTX *frame = talloc_stackframe();
580         struct bitmap *commands_seen;
581         int i;
582
583         if (r->count.count == 0) {
584                 ret = true;
585                 goto done;
586         }
587
588         if (memcmp(r->magic, DCERPC_SEC_VT_MAGIC, sizeof(r->magic)) != 0) {
589                 goto done;
590         }
591
592         commands_seen = bitmap_talloc(frame, DCERPC_SEC_VT_COMMAND_ENUM + 1);
593         if (commands_seen == NULL) {
594                 goto done;
595         }
596
597         for (i=0; i < r->count.count; i++) {
598                 enum dcerpc_sec_vt_command_enum cmd =
599                         r->commands[i].command & DCERPC_SEC_VT_COMMAND_ENUM;
600
601                 if (bitmap_query(commands_seen, cmd)) {
602                         /* Each command must appear at most once. */
603                         goto done;
604                 }
605                 bitmap_set(commands_seen, cmd);
606
607                 switch (cmd) {
608                 case DCERPC_SEC_VT_COMMAND_BITMASK1:
609                 case DCERPC_SEC_VT_COMMAND_PCONTEXT:
610                 case DCERPC_SEC_VT_COMMAND_HEADER2:
611                         break;
612                 default:
613                         if ((r->commands[i].u._unknown.length % 4) != 0) {
614                                 goto done;
615                         }
616                         break;
617                 }
618         }
619         ret = true;
620 done:
621         TALLOC_FREE(frame);
622         return ret;
623 }
624
625 static bool dcerpc_sec_vt_bitmask_check(const uint32_t *bitmask1,
626                                         struct dcerpc_sec_vt *c)
627 {
628         if (bitmask1 == NULL) {
629                 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
630                         DEBUG(10, ("SEC_VT check Bitmask1 must_process_command "
631                                    "failed\n"));
632                         return false;
633                 }
634
635                 return true;
636         }
637
638         if ((c->u.bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING)
639          && (!(*bitmask1 & DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING))) {
640                 DEBUG(10, ("SEC_VT check Bitmask1 client_header_signing "
641                            "failed\n"));
642                 return false;
643         }
644         return true;
645 }
646
647 static bool dcerpc_sec_vt_pctx_check(const struct dcerpc_sec_vt_pcontext *pcontext,
648                                      struct dcerpc_sec_vt *c)
649 {
650         TALLOC_CTX *mem_ctx;
651         bool ok;
652
653         if (pcontext == NULL) {
654                 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
655                         DEBUG(10, ("SEC_VT check Pcontext must_process_command "
656                                    "failed\n"));
657                         return false;
658                 }
659
660                 return true;
661         }
662
663         mem_ctx = talloc_stackframe();
664         ok = ndr_syntax_id_equal(&pcontext->abstract_syntax,
665                                  &c->u.pcontext.abstract_syntax);
666         if (!ok) {
667                 DEBUG(10, ("SEC_VT check pcontext abstract_syntax failed: "
668                            "%s vs. %s\n",
669                            ndr_syntax_id_to_string(mem_ctx,
670                                         &pcontext->abstract_syntax),
671                            ndr_syntax_id_to_string(mem_ctx,
672                                         &c->u.pcontext.abstract_syntax)));
673                 goto err_ctx_free;
674         }
675         ok = ndr_syntax_id_equal(&pcontext->transfer_syntax,
676                                  &c->u.pcontext.transfer_syntax);
677         if (!ok) {
678                 DEBUG(10, ("SEC_VT check pcontext transfer_syntax failed: "
679                            "%s vs. %s\n",
680                            ndr_syntax_id_to_string(mem_ctx,
681                                         &pcontext->transfer_syntax),
682                            ndr_syntax_id_to_string(mem_ctx,
683                                         &c->u.pcontext.transfer_syntax)));
684                 goto err_ctx_free;
685         }
686
687         ok = true;
688 err_ctx_free:
689         talloc_free(mem_ctx);
690         return ok;
691 }
692
693 static bool dcerpc_sec_vt_hdr2_check(const struct dcerpc_sec_vt_header2 *header2,
694                                      struct dcerpc_sec_vt *c)
695 {
696         if (header2 == NULL) {
697                 if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
698                         DEBUG(10, ("SEC_VT check Header2 must_process_command failed\n"));
699                         return false;
700                 }
701
702                 return true;
703         }
704
705         if (!dcerpc_sec_vt_header2_equal(header2, &c->u.header2)) {
706                 DEBUG(10, ("SEC_VT check Header2 failed\n"));
707                 return false;
708         }
709
710         return true;
711 }
712
713 bool dcerpc_sec_verification_trailer_check(
714                 const struct dcerpc_sec_verification_trailer *vt,
715                 const uint32_t *bitmask1,
716                 const struct dcerpc_sec_vt_pcontext *pcontext,
717                 const struct dcerpc_sec_vt_header2 *header2)
718 {
719         size_t i;
720
721         if (!dcerpc_sec_vt_is_valid(vt)) {
722                 return false;
723         }
724
725         for (i=0; i < vt->count.count; i++) {
726                 bool ok;
727                 struct dcerpc_sec_vt *c = &vt->commands[i];
728
729                 switch (c->command & DCERPC_SEC_VT_COMMAND_ENUM) {
730                 case DCERPC_SEC_VT_COMMAND_BITMASK1:
731                         ok = dcerpc_sec_vt_bitmask_check(bitmask1, c);
732                         if (!ok) {
733                                 return false;
734                         }
735                         break;
736
737                 case DCERPC_SEC_VT_COMMAND_PCONTEXT:
738                         ok = dcerpc_sec_vt_pctx_check(pcontext, c);
739                         if (!ok) {
740                                 return false;
741                         }
742                         break;
743
744                 case DCERPC_SEC_VT_COMMAND_HEADER2: {
745                         ok = dcerpc_sec_vt_hdr2_check(header2, c);
746                         if (!ok) {
747                                 return false;
748                         }
749                         break;
750                 }
751
752                 default:
753                         if (c->command & DCERPC_SEC_VT_MUST_PROCESS) {
754                                 DEBUG(10, ("SEC_VT check Unknown must_process_command failed\n"));
755                                 return false;
756                         }
757
758                         break;
759                 }
760         }
761
762         return true;
763 }
764
765 static const struct ndr_syntax_id dcerpc_bind_time_features_prefix  = {
766         .uuid = {
767                 .time_low = 0x6cb71c2c,
768                 .time_mid = 0x9812,
769                 .time_hi_and_version = 0x4540,
770                 .clock_seq = {0x00, 0x00},
771                 .node = {0x00,0x00,0x00,0x00,0x00,0x00}
772         },
773         .if_version = 1,
774 };
775
776 bool dcerpc_extract_bind_time_features(struct ndr_syntax_id s, uint64_t *_features)
777 {
778         uint8_t values[8];
779         uint64_t features = 0;
780
781         values[0] = s.uuid.clock_seq[0];
782         values[1] = s.uuid.clock_seq[1];
783         values[2] = s.uuid.node[0];
784         values[3] = s.uuid.node[1];
785         values[4] = s.uuid.node[2];
786         values[5] = s.uuid.node[3];
787         values[6] = s.uuid.node[4];
788         values[7] = s.uuid.node[5];
789
790         ZERO_STRUCT(s.uuid.clock_seq);
791         ZERO_STRUCT(s.uuid.node);
792
793         if (!ndr_syntax_id_equal(&s, &dcerpc_bind_time_features_prefix)) {
794                 if (_features != NULL) {
795                         *_features = 0;
796                 }
797                 return false;
798         }
799
800         features = BVAL(values, 0);
801
802         if (_features != NULL) {
803                 *_features = features;
804         }
805
806         return true;
807 }
808
809 struct ndr_syntax_id dcerpc_construct_bind_time_features(uint64_t features)
810 {
811         struct ndr_syntax_id s = dcerpc_bind_time_features_prefix;
812         uint8_t values[8];
813
814         SBVAL(values, 0, features);
815
816         s.uuid.clock_seq[0] = values[0];
817         s.uuid.clock_seq[1] = values[1];
818         s.uuid.node[0]      = values[2];
819         s.uuid.node[1]      = values[3];
820         s.uuid.node[2]      = values[4];
821         s.uuid.node[3]      = values[5];
822         s.uuid.node[4]      = values[6];
823         s.uuid.node[5]      = values[7];
824
825         return s;
826 }