2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003
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 2 of the License, or
11 (at your option) any later version.
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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* initialise a dcerpc pipe. This currently assumes a SMB named pipe
27 struct dcerpc_pipe *dcerpc_pipe_init(struct cli_tree *tree)
29 struct dcerpc_pipe *p;
31 TALLOC_CTX *mem_ctx = talloc_init("dcerpc_tree");
35 p = talloc(mem_ctx, sizeof(*p));
37 talloc_destroy(mem_ctx);
41 p->reference_count = 0;
44 p->tree->reference_count++;
51 /* close down a dcerpc over SMB pipe */
52 void dcerpc_pipe_close(struct dcerpc_pipe *p)
56 if (p->reference_count <= 0) {
57 cli_tree_close(p->tree);
58 talloc_destroy(p->mem_ctx);
62 #define BLOB_CHECK_BOUNDS(blob, offset, len) do { \
63 if ((offset) > blob->length || (blob->length - (offset) < (len))) { \
64 return NT_STATUS_INVALID_PARAMETER; \
68 #define DCERPC_ALIGN(offset, n) do { \
69 (offset) = ((offset) + ((n)-1)) & ~((n)-1); \
73 pull a wire format uuid into a string. This will consume 16 bytes
75 static char *dcerpc_pull_uuid(char *data, TALLOC_CTX *mem_ctx)
78 uint16 time_mid, time_hi_and_version;
79 uint8 clock_seq_hi_and_reserved;
84 time_low = IVAL(data, 0);
85 time_mid = SVAL(data, 4);
86 time_hi_and_version = SVAL(data, 6);
87 clock_seq_hi_and_reserved = CVAL(data, 8);
88 clock_seq_low = CVAL(data, 9);
90 node[i] = CVAL(data, 10 + i);
93 return talloc_asprintf(mem_ctx,
94 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
95 time_low, time_mid, time_hi_and_version,
96 clock_seq_hi_and_reserved, clock_seq_low,
97 node[0], node[1], node[2], node[3], node[4], node[5]);
101 push a uuid_str into wire format. It will consume 16 bytes
103 static NTSTATUS push_uuid_str(char *data, const char *uuid_str)
106 uint32 time_mid, time_hi_and_version;
107 uint32 clock_seq_hi_and_reserved;
108 uint32 clock_seq_low;
112 if (11 != sscanf(uuid_str, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
113 &time_low, &time_mid, &time_hi_and_version,
114 &clock_seq_hi_and_reserved, &clock_seq_low,
115 &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) {
116 return NT_STATUS_INVALID_PARAMETER;
119 SIVAL(data, 0, time_low);
120 SSVAL(data, 4, time_mid);
121 SSVAL(data, 6, time_hi_and_version);
122 SCVAL(data, 8, clock_seq_hi_and_reserved);
123 SCVAL(data, 9, clock_seq_low);
125 SCVAL(data, 10 + i, node[i]);
132 pull a dcerpc syntax id from a blob
134 static NTSTATUS dcerpc_pull_syntax_id(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
136 struct dcerpc_syntax_id *syntax)
138 syntax->uuid_str = dcerpc_pull_uuid(blob->data + (*offset), mem_ctx);
139 if (!syntax->uuid_str) {
140 return NT_STATUS_NO_MEMORY;
143 syntax->if_version = IVAL(blob->data, *offset);
149 push a syntax id onto the wire. It will consume 20 bytes
151 static NTSTATUS push_syntax_id(char *data, const struct dcerpc_syntax_id *syntax)
155 status = push_uuid_str(data, syntax->uuid_str);
156 SIVAL(data, 16, syntax->if_version);
162 pull an auth verifier from a packet
164 static NTSTATUS dcerpc_pull_auth_verifier(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
166 struct dcerpc_hdr *hdr,
169 if (hdr->auth_length == 0) {
173 BLOB_CHECK_BOUNDS(blob, *offset, hdr->auth_length);
174 *auth = data_blob_talloc(mem_ctx, blob->data + (*offset), hdr->auth_length);
176 return NT_STATUS_NO_MEMORY;
178 (*offset) += hdr->auth_length;
183 parse a struct dcerpc_response
185 static NTSTATUS dcerpc_pull_response(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
187 struct dcerpc_hdr *hdr,
188 struct dcerpc_response *pkt)
192 BLOB_CHECK_BOUNDS(blob, *offset, 8);
194 pkt->alloc_hint = IVAL(blob->data, (*offset) + 0);
195 pkt->context_id = SVAL(blob->data, (*offset) + 4);
196 pkt->cancel_count = CVAL(blob->data, (*offset) + 6);
200 stub_len = blob->length - ((*offset) + hdr->auth_length);
201 BLOB_CHECK_BOUNDS(blob, *offset, stub_len);
202 pkt->stub_data = data_blob_talloc(mem_ctx, blob->data + (*offset), stub_len);
203 if (stub_len != 0 && !pkt->stub_data.data) {
204 return NT_STATUS_NO_MEMORY;
206 (*offset) += stub_len;
208 return dcerpc_pull_auth_verifier(blob, mem_ctx, offset, hdr, &pkt->auth_verifier);
213 parse a struct bind_ack
215 static NTSTATUS dcerpc_pull_bind_ack(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
217 struct dcerpc_hdr *hdr,
218 struct dcerpc_bind_ack *pkt)
223 BLOB_CHECK_BOUNDS(blob, *offset, 10);
224 pkt->max_xmit_frag = SVAL(blob->data, (*offset) + 0);
225 pkt->max_recv_frag = SVAL(blob->data, (*offset) + 2);
226 pkt->assoc_group_id = IVAL(blob->data, (*offset) + 4);
227 len = SVAL(blob->data, (*offset) + 8);
231 BLOB_CHECK_BOUNDS(blob, *offset, len);
232 pkt->secondary_address = talloc_strndup(mem_ctx, blob->data + (*offset), len);
233 if (!pkt->secondary_address) {
234 return NT_STATUS_NO_MEMORY;
239 DCERPC_ALIGN(*offset, 4);
240 BLOB_CHECK_BOUNDS(blob, *offset, 4);
241 pkt->num_results = CVAL(blob->data, *offset);
244 if (pkt->num_results > 0) {
245 pkt->ctx_list = talloc(mem_ctx, sizeof(pkt->ctx_list[0]) * pkt->num_results);
246 if (!pkt->ctx_list) {
247 return NT_STATUS_NO_MEMORY;
251 for (i=0;i<pkt->num_results;i++) {
254 BLOB_CHECK_BOUNDS(blob, *offset, 24);
255 pkt->ctx_list[i].result = SVAL(blob->data, *offset);
256 pkt->ctx_list[i].reason = SVAL(blob->data, 2 + *offset);
258 status = dcerpc_pull_syntax_id(blob, mem_ctx, offset, &pkt->ctx_list[i].syntax);
259 if (!NT_STATUS_IS_OK(status)) {
264 return dcerpc_pull_auth_verifier(blob, mem_ctx, offset, hdr, &pkt->auth_verifier);
269 parse a dcerpc header
271 static NTSTATUS dcerpc_pull_hdr(DATA_BLOB *blob, uint32 *offset, struct dcerpc_hdr *hdr)
273 BLOB_CHECK_BOUNDS(blob, *offset, 16);
275 hdr->rpc_vers = CVAL(blob->data, (*offset) + 0);
276 hdr->rpc_vers_minor = CVAL(blob->data, (*offset) + 1);
277 hdr->ptype = CVAL(blob->data, (*offset) + 2);
278 hdr->pfc_flags = CVAL(blob->data, (*offset) + 3);
279 memcpy(hdr->drep, blob->data + (*offset) + 4, 4);
280 hdr->frag_length = SVAL(blob->data, (*offset) + 8);
281 hdr->auth_length = SVAL(blob->data, (*offset) + 10);
282 hdr->call_id = IVAL(blob->data, (*offset) + 12);
290 parse a dcerpc header. It consumes 16 bytes
292 static void dcerpc_push_hdr(char *data, struct dcerpc_hdr *hdr)
294 SCVAL(data, 0, hdr->rpc_vers);
295 SCVAL(data, 1, hdr->rpc_vers_minor);
296 SCVAL(data, 2, hdr->ptype);
297 SCVAL(data, 3, hdr->pfc_flags);
298 memcpy(data + 4, hdr->drep, 4);
299 SSVAL(data, 8, hdr->frag_length);
300 SSVAL(data, 12, hdr->call_id);
306 parse a data blob into a dcerpc_packet structure. This handles both
307 input and output packets
309 NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
314 status = dcerpc_pull_hdr(blob, &offset, &pkt->hdr);
315 if (!NT_STATUS_IS_OK(status)) {
319 switch (pkt->hdr.ptype) {
320 case DCERPC_PKT_BIND_ACK:
321 status = dcerpc_pull_bind_ack(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.bind_ack);
322 if (!NT_STATUS_IS_OK(status)) {
327 case DCERPC_PKT_RESPONSE:
328 status = dcerpc_pull_response(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.response);
329 if (!NT_STATUS_IS_OK(status)) {
335 return NT_STATUS_NET_WRITE_FAULT;
343 push a dcerpc_bind into a blob
345 static NTSTATUS dcerpc_push_bind(DATA_BLOB *blob, uint32 *offset,
346 struct dcerpc_hdr *hdr,
347 struct dcerpc_bind *pkt)
351 SSVAL(blob->data, (*offset) + 0, pkt->max_xmit_frag);
352 SSVAL(blob->data, (*offset) + 2, pkt->max_recv_frag);
353 SIVAL(blob->data, (*offset) + 4, pkt->assoc_group_id);
354 SCVAL(blob->data, (*offset) + 8, pkt->num_contexts);
357 for (i=0;i<pkt->num_contexts;i++) {
360 SSVAL(blob->data, (*offset) + 0, pkt->ctx_list[i].context_id);
361 SCVAL(blob->data, (*offset) + 2, pkt->ctx_list[i].num_transfer_syntaxes);
362 status = push_syntax_id(blob->data + (*offset) + 4, &pkt->ctx_list[i].abstract_syntax);
363 if (!NT_STATUS_IS_OK(status)) {
367 for (j=0;j<pkt->ctx_list[i].num_transfer_syntaxes;j++) {
368 status = push_syntax_id(blob->data + (*offset),
369 &pkt->ctx_list[i].transfer_syntaxes[j]);
370 if (!NT_STATUS_IS_OK(status)) {
381 push a dcerpc_request into a blob
383 static NTSTATUS dcerpc_push_request(DATA_BLOB *blob, uint32 *offset,
384 struct dcerpc_hdr *hdr,
385 struct dcerpc_request *pkt)
387 SIVAL(blob->data, (*offset) + 0, pkt->alloc_hint);
388 SSVAL(blob->data, (*offset) + 4, pkt->context_id);
389 SSVAL(blob->data, (*offset) + 6, pkt->opnum);
393 memcpy(blob->data + (*offset), pkt->stub_data.data, pkt->stub_data.length);
394 (*offset) += pkt->stub_data.length;
396 memcpy(blob->data + (*offset), pkt->auth_verifier.data, pkt->auth_verifier.length);
397 (*offset) += pkt->auth_verifier.length;
404 work out the wire size of a dcerpc packet
406 static uint32 dcerpc_wire_size(struct dcerpc_packet *pkt)
411 size += 16; /* header */
413 switch (pkt->hdr.ptype) {
414 case DCERPC_PKT_REQUEST:
416 size += pkt->in.request.stub_data.length;
417 size += pkt->in.request.auth_verifier.length;
420 case DCERPC_PKT_RESPONSE:
422 size += pkt->out.response.stub_data.length;
423 size += pkt->hdr.auth_length;
426 case DCERPC_PKT_BIND:
428 for (i=0;i<pkt->in.bind.num_contexts;i++) {
430 size += pkt->in.bind.ctx_list[i].num_transfer_syntaxes * 20;
432 size += pkt->hdr.auth_length;
435 case DCERPC_PKT_BIND_ACK:
437 if (pkt->out.bind_ack.secondary_address) {
438 size += strlen(pkt->out.bind_ack.secondary_address) + 1;
441 size += pkt->out.bind_ack.num_results * 24;
442 size += pkt->hdr.auth_length;
450 push a dcerpc_packet into a blob. This handles both input and
453 NTSTATUS dcerpc_push(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
459 /* work out how big the packet will be on the wire */
460 wire_size = dcerpc_wire_size(pkt);
462 (*blob) = data_blob_talloc(mem_ctx, NULL, wire_size);
464 return NT_STATUS_NO_MEMORY;
467 pkt->hdr.frag_length = wire_size;
469 dcerpc_push_hdr(blob->data + offset, &pkt->hdr);
472 switch (pkt->hdr.ptype) {
473 case DCERPC_PKT_BIND:
474 status = dcerpc_push_bind(blob, &offset, &pkt->hdr, &pkt->in.bind);
477 case DCERPC_PKT_REQUEST:
478 status = dcerpc_push_request(blob, &offset, &pkt->hdr, &pkt->in.request);
482 status = NT_STATUS_NET_WRITE_FAULT;
492 fill in the fixed values in a dcerpc header
494 static void init_dcerpc_hdr(struct dcerpc_hdr *hdr)
497 hdr->rpc_vers_minor = 0;
498 hdr->drep[0] = 0x10; /* Little endian */
506 perform a bind using the given syntax
508 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
509 const struct dcerpc_syntax_id *syntax,
510 const struct dcerpc_syntax_id *transfer_syntax)
513 struct dcerpc_packet pkt;
518 mem_ctx = talloc_init("dcerpc_bind");
520 return NT_STATUS_NO_MEMORY;
523 init_dcerpc_hdr(&pkt.hdr);
525 pkt.hdr.ptype = DCERPC_PKT_BIND;
526 pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
527 pkt.hdr.call_id = p->call_id++;
528 pkt.hdr.auth_length = 0;
530 pkt.in.bind.max_xmit_frag = 0x2000;
531 pkt.in.bind.max_recv_frag = 0x2000;
532 pkt.in.bind.assoc_group_id = 0;
533 pkt.in.bind.num_contexts = 1;
534 pkt.in.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.in.bind.ctx_list[0]));
535 if (!pkt.in.bind.ctx_list) {
536 talloc_destroy(mem_ctx);
537 return NT_STATUS_NO_MEMORY;
539 pkt.in.bind.ctx_list[0].context_id = 0;
540 pkt.in.bind.ctx_list[0].num_transfer_syntaxes = 1;
541 pkt.in.bind.ctx_list[0].abstract_syntax = *syntax;
542 pkt.in.bind.ctx_list[0].transfer_syntaxes = transfer_syntax;
544 pkt.in.bind.auth_verifier = data_blob(NULL, 0);
546 status = dcerpc_push(&blob, mem_ctx, &pkt);
547 if (!NT_STATUS_IS_OK(status)) {
548 talloc_destroy(mem_ctx);
552 status = dcerpc_raw_packet(p, mem_ctx, &blob, &blob_out);
553 if (!NT_STATUS_IS_OK(status)) {
554 talloc_destroy(mem_ctx);
558 status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
559 if (!NT_STATUS_IS_OK(status)) {
560 talloc_destroy(mem_ctx);
564 if (pkt.hdr.ptype != DCERPC_PKT_BIND_ACK ||
565 pkt.out.bind_ack.num_results == 0 ||
566 pkt.out.bind_ack.ctx_list[0].result != 0) {
567 status = NT_STATUS_UNSUCCESSFUL;
570 p->srv_max_xmit_frag = pkt.out.bind_ack.max_xmit_frag;
571 p->srv_max_recv_frag = pkt.out.bind_ack.max_recv_frag;
573 talloc_destroy(mem_ctx);
578 /* Perform a bind using the given UUID and version */
579 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
580 const char *uuid, unsigned version)
582 struct dcerpc_syntax_id syntax;
583 struct dcerpc_syntax_id transfer_syntax;
585 syntax.uuid_str = uuid;
586 syntax.if_version = version;
588 transfer_syntax.uuid_str = "8a885d04-1ceb-11c9-9fe8-08002b104860";
589 transfer_syntax.if_version = 2;
591 return dcerpc_bind(p, &syntax, &transfer_syntax);
595 perform a full request/response pair on a dcerpc pipe
597 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
600 DATA_BLOB *stub_data_in,
601 DATA_BLOB *stub_data_out)
604 struct dcerpc_packet pkt;
606 DATA_BLOB blob_in, blob_out, payload;
607 uint32 remaining, chunk_size;
609 init_dcerpc_hdr(&pkt.hdr);
611 remaining = stub_data_in->length;
613 /* we can write a full max_recv_frag size, minus the dcerpc
614 request header size */
615 chunk_size = p->srv_max_recv_frag - 24;
617 pkt.hdr.ptype = DCERPC_PKT_REQUEST;
618 pkt.hdr.call_id = p->call_id++;
619 pkt.hdr.auth_length = 0;
620 pkt.in.request.alloc_hint = remaining;
621 pkt.in.request.context_id = 0;
622 pkt.in.request.opnum = opnum;
623 pkt.in.request.auth_verifier = data_blob(NULL, 0);
625 /* we send a series of pdus without waiting for a reply until
627 while (remaining > chunk_size) {
628 if (remaining == stub_data_in->length) {
629 pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST;
631 pkt.hdr.pfc_flags = 0;
634 pkt.in.request.stub_data.data = stub_data_in->data +
635 (stub_data_in->length - remaining);
636 pkt.in.request.stub_data.length = chunk_size;
638 status = dcerpc_push(&blob_in, mem_ctx, &pkt);
639 if (!NT_STATUS_IS_OK(status)) {
643 status = dcerpc_raw_packet_initial(p, mem_ctx, &blob_in);
644 if (!NT_STATUS_IS_OK(status)) {
648 remaining -= chunk_size;
651 /* now we send a pdu with LAST_FRAG sent and get the first
653 if (remaining == stub_data_in->length) {
654 pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
656 pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_LAST;
658 pkt.in.request.stub_data.data = stub_data_in->data +
659 (stub_data_in->length - remaining);
660 pkt.in.request.stub_data.length = remaining;
662 status = dcerpc_push(&blob_in, mem_ctx, &pkt);
663 if (!NT_STATUS_IS_OK(status)) {
667 /* send the pdu and get the initial response pdu */
668 status = dcerpc_raw_packet(p, mem_ctx, &blob_in, &blob_out);
670 status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
671 if (!NT_STATUS_IS_OK(status)) {
675 if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) {
676 return NT_STATUS_UNSUCCESSFUL;
679 if (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
680 /* something is badly wrong! */
681 return NT_STATUS_UNSUCCESSFUL;
684 payload = pkt.out.response.stub_data;
686 /* continue receiving fragments */
687 while (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
690 status = dcerpc_raw_packet_secondary(p, mem_ctx, &blob_out);
691 if (!NT_STATUS_IS_OK(status)) {
695 status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
696 if (!NT_STATUS_IS_OK(status)) {
700 if (pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
701 /* start of another packet!? */
702 return NT_STATUS_UNSUCCESSFUL;
705 if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) {
706 return NT_STATUS_UNSUCCESSFUL;
709 length = pkt.out.response.stub_data.length;
711 payload.data = talloc_realloc(mem_ctx,
713 payload.length + length);
715 return NT_STATUS_NO_MEMORY;
718 memcpy(payload.data + payload.length,
719 pkt.out.response.stub_data.data,
722 payload.length += length;
726 *stub_data_out = payload;
734 this is a paranoid NDR validator. For every packet we push onto the wire
735 we pull it back again, then push it again. Then we compare the raw NDR data
736 for that to the NDR we initially generated. If they don't match then we know
737 we must have a bug in either the pull or push side of our code
739 static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
742 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
743 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
746 struct ndr_pull *pull;
747 struct ndr_push *push;
751 st = talloc(mem_ctx, struct_size);
753 return NT_STATUS_NO_MEMORY;
756 pull = ndr_pull_init_blob(&blob, mem_ctx);
758 return NT_STATUS_NO_MEMORY;
761 status = ndr_pull(pull, NDR_IN, st);
762 if (!NT_STATUS_IS_OK(status)) {
763 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
764 "failed input validation pull - %s",
768 push = ndr_push_init_ctx(mem_ctx);
770 return NT_STATUS_NO_MEMORY;
773 status = ndr_push(push, NDR_IN, st);
774 if (!NT_STATUS_IS_OK(status)) {
775 return ndr_push_error(push, NDR_ERR_VALIDATE,
776 "failed input validation push - %s",
780 blob2 = ndr_push_blob(push);
782 if (!data_blob_equal(&blob, &blob2)) {
783 DEBUG(3,("original:\n"));
784 dump_data(3, blob.data, blob.length);
785 DEBUG(3,("secondary:\n"));
786 dump_data(3, blob2.data, blob2.length);
787 return ndr_push_error(push, NDR_ERR_VALIDATE,
788 "failed input validation data - %s",
796 this is a paranoid NDR input validator. For every packet we pull
797 from the wire we push it back again then pull and push it
798 again. Then we compare the raw NDR data for that to the NDR we
799 initially generated. If they don't match then we know we must have a
800 bug in either the pull or push side of our code
802 static NTSTATUS dcerpc_ndr_validate_out(TALLOC_CTX *mem_ctx,
805 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
806 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
809 struct ndr_pull *pull;
810 struct ndr_push *push;
812 DATA_BLOB blob, blob2;
814 st = talloc(mem_ctx, struct_size);
816 return NT_STATUS_NO_MEMORY;
818 memcpy(st, struct_ptr, struct_size);
820 push = ndr_push_init_ctx(mem_ctx);
822 return NT_STATUS_NO_MEMORY;
825 status = ndr_push(push, NDR_OUT, struct_ptr);
826 if (!NT_STATUS_IS_OK(status)) {
827 return ndr_push_error(push, NDR_ERR_VALIDATE,
828 "failed output validation push - %s",
832 blob = ndr_push_blob(push);
834 pull = ndr_pull_init_blob(&blob, mem_ctx);
836 return NT_STATUS_NO_MEMORY;
839 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
840 status = ndr_pull(pull, NDR_OUT, st);
841 if (!NT_STATUS_IS_OK(status)) {
842 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
843 "failed output validation pull - %s",
847 push = ndr_push_init_ctx(mem_ctx);
849 return NT_STATUS_NO_MEMORY;
852 status = ndr_push(push, NDR_OUT, st);
853 if (!NT_STATUS_IS_OK(status)) {
854 return ndr_push_error(push, NDR_ERR_VALIDATE,
855 "failed output validation push2 - %s",
859 blob2 = ndr_push_blob(push);
861 if (!data_blob_equal(&blob, &blob2)) {
862 DEBUG(3,("original:\n"));
863 dump_data(3, blob.data, blob.length);
864 DEBUG(3,("secondary:\n"));
865 dump_data(3, blob2.data, blob2.length);
866 return ndr_push_error(push, NDR_ERR_VALIDATE,
867 "failed output validation data - %s",
875 a useful helper function for synchronous rpc requests
877 this can be used when you have ndr push/pull functions in the
880 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
883 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
884 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
888 struct ndr_push *push;
889 struct ndr_pull *pull;
891 DATA_BLOB request, response;
893 /* setup for a ndr_push_* call */
894 push = ndr_push_init();
896 talloc_destroy(mem_ctx);
897 return NT_STATUS_NO_MEMORY;
900 /* push the structure into a blob */
901 status = ndr_push(push, NDR_IN, struct_ptr);
902 if (!NT_STATUS_IS_OK(status)) {
906 /* retrieve the blob */
907 request = ndr_push_blob(push);
909 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
910 status = dcerpc_ndr_validate_in(mem_ctx, request, struct_size,
912 if (!NT_STATUS_IS_OK(status)) {
917 DEBUG(10,("rpc request data:\n"));
918 dump_data(10, request.data, request.length);
920 /* make the actual dcerpc request */
921 status = dcerpc_request(p, opnum, mem_ctx, &request, &response);
922 if (!NT_STATUS_IS_OK(status)) {
926 /* prepare for ndr_pull_* */
927 pull = ndr_pull_init_blob(&response, mem_ctx);
932 DEBUG(10,("rpc reply data:\n"));
933 dump_data(10, pull->data, pull->data_size);
935 /* pull the structure from the blob */
936 status = ndr_pull(pull, NDR_OUT, struct_ptr);
937 if (!NT_STATUS_IS_OK(status)) {
941 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
942 status = dcerpc_ndr_validate_out(mem_ctx, struct_ptr, struct_size,
944 if (!NT_STATUS_IS_OK(status)) {
949 if (pull->offset != pull->data_size) {
950 DEBUG(0,("Warning! %d unread bytes\n", pull->data_size - pull->offset));
951 status = NT_STATUS_INFO_LENGTH_MISMATCH;
962 a useful function for retrieving the server name we connected to
964 const char *dcerpc_server_name(struct dcerpc_pipe *p)
966 return p->tree->session->transport->called.name;