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(void)
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;
45 p->security_state = NULL;
47 p->srv_max_xmit_frag = 0;
48 p->srv_max_recv_frag = 0;
53 /* close down a dcerpc over SMB pipe */
54 void dcerpc_pipe_close(struct dcerpc_pipe *p)
58 if (p->reference_count <= 0) {
59 if (p->security_state) {
60 p->security_state->security_end(p->security_state);
62 p->transport.shutdown_pipe(p);
63 talloc_destroy(p->mem_ctx);
67 /* we need to be able to get/set the fragment length without doing a full
69 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16 v)
71 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
72 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
74 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
78 uint16 dcerpc_get_frag_length(const DATA_BLOB *blob)
80 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
81 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
83 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
87 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16 v)
89 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
90 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
92 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
98 parse a data blob into a dcerpc_packet structure. This handles both
99 input and output packets
101 static NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
102 struct dcerpc_packet *pkt)
104 struct ndr_pull *ndr;
106 ndr = ndr_pull_init_blob(blob, mem_ctx);
108 return NT_STATUS_NO_MEMORY;
111 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
112 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
115 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
119 parse a possibly signed blob into a dcerpc request packet structure
121 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
122 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
123 struct dcerpc_packet *pkt)
125 struct ndr_pull *ndr;
127 struct dcerpc_auth auth;
130 /* non-signed packets are simpler */
131 if (!p->auth_info || !p->security_state) {
132 return dcerpc_pull(blob, mem_ctx, pkt);
135 ndr = ndr_pull_init_blob(blob, mem_ctx);
137 return NT_STATUS_NO_MEMORY;
140 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
141 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
144 /* pull the basic packet */
145 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
146 if (!NT_STATUS_IS_OK(status)) {
150 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
154 auth_blob.length = 8 + pkt->auth_length;
156 /* check for a valid length */
157 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
158 return NT_STATUS_INFO_LENGTH_MISMATCH;
162 pkt->u.response.stub_and_verifier.data +
163 pkt->u.response.stub_and_verifier.length - auth_blob.length;
164 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
166 /* pull the auth structure */
167 ndr = ndr_pull_init_blob(&auth_blob, mem_ctx);
169 return NT_STATUS_NO_MEMORY;
172 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
173 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
176 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
177 if (!NT_STATUS_IS_OK(status)) {
182 /* check signature or unseal the packet */
183 switch (p->auth_info->auth_level) {
184 case DCERPC_AUTH_LEVEL_PRIVACY:
185 status = p->security_state->unseal_packet(p->security_state,
187 pkt->u.response.stub_and_verifier.data,
188 pkt->u.response.stub_and_verifier.length,
192 case DCERPC_AUTH_LEVEL_INTEGRITY:
193 status = p->security_state->check_packet(p->security_state,
195 pkt->u.response.stub_and_verifier.data,
196 pkt->u.response.stub_and_verifier.length,
200 case DCERPC_AUTH_LEVEL_NONE:
204 status = NT_STATUS_INVALID_LEVEL;
208 /* remove the indicated amount of paddiing */
209 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
210 return NT_STATUS_INFO_LENGTH_MISMATCH;
212 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
219 push a dcerpc request packet into a blob, possibly signing it.
221 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
222 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
223 struct dcerpc_packet *pkt)
226 struct ndr_push *ndr;
228 /* non-signed packets are simpler */
229 if (!p->auth_info || !p->security_state) {
230 return dcerpc_push_auth(blob, mem_ctx, pkt, p->auth_info);
233 ndr = ndr_push_init_ctx(mem_ctx);
235 return NT_STATUS_NO_MEMORY;
238 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
239 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
242 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
243 if (!NT_STATUS_IS_OK(status)) {
247 /* pad to 8 byte multiple */
248 p->auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
249 ndr_push_zero(ndr, p->auth_info->auth_pad_length);
251 /* sign or seal the packet */
252 switch (p->auth_info->auth_level) {
253 case DCERPC_AUTH_LEVEL_PRIVACY:
254 status = p->security_state->seal_packet(p->security_state,
256 ndr->data + DCERPC_REQUEST_LENGTH,
257 ndr->offset - DCERPC_REQUEST_LENGTH,
258 &p->auth_info->credentials);
261 case DCERPC_AUTH_LEVEL_INTEGRITY:
262 status = p->security_state->sign_packet(p->security_state,
264 ndr->data + DCERPC_REQUEST_LENGTH,
265 ndr->offset - DCERPC_REQUEST_LENGTH,
266 &p->auth_info->credentials);
269 case DCERPC_AUTH_LEVEL_NONE:
270 p->auth_info->credentials = data_blob(NULL, 0);
274 status = NT_STATUS_INVALID_LEVEL;
278 if (!NT_STATUS_IS_OK(status)) {
282 /* add the auth verifier */
283 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->auth_info);
284 if (!NT_STATUS_IS_OK(status)) {
288 /* extract the whole packet as a blob */
289 *blob = ndr_push_blob(ndr);
291 /* fill in the fragment length and auth_length, we can't fill
292 in these earlier as we don't know the signature length (it
293 could be variable length) */
294 dcerpc_set_frag_length(blob, blob->length);
295 dcerpc_set_auth_length(blob, p->auth_info->credentials.length);
297 data_blob_free(&p->auth_info->credentials);
304 fill in the fixed values in a dcerpc header
306 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
309 pkt->rpc_vers_minor = 0;
310 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
313 pkt->drep[0] = DCERPC_DREP_LE;
322 perform a bind using the given syntax
324 the auth_info structure is updated with the reply authentication info
327 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
329 const struct dcerpc_syntax_id *syntax,
330 const struct dcerpc_syntax_id *transfer_syntax)
332 struct dcerpc_packet pkt;
335 struct dcerpc_syntax_id tsyntax;
337 init_dcerpc_hdr(p, &pkt);
339 pkt.ptype = DCERPC_PKT_BIND;
340 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
341 pkt.call_id = p->call_id;
344 pkt.u.bind.max_xmit_frag = 0x2000;
345 pkt.u.bind.max_recv_frag = 0x2000;
346 pkt.u.bind.assoc_group_id = 0;
347 pkt.u.bind.num_contexts = 1;
348 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
349 if (!pkt.u.bind.ctx_list) {
350 return NT_STATUS_NO_MEMORY;
352 pkt.u.bind.ctx_list[0].context_id = 0;
353 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
354 pkt.u.bind.ctx_list[0].abstract_syntax = *syntax;
355 tsyntax = *transfer_syntax;
356 pkt.u.bind.ctx_list[0].transfer_syntaxes = &tsyntax;
357 pkt.u.bind.auth_info = data_blob(NULL, 0);
359 /* construct the NDR form of the packet */
360 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info);
361 if (!NT_STATUS_IS_OK(status)) {
365 /* send it on its way */
366 status = p->transport.full_request(p, mem_ctx, &blob, &blob);
367 if (!NT_STATUS_IS_OK(status)) {
371 /* unmarshall the NDR */
372 status = dcerpc_pull(&blob, mem_ctx, &pkt);
373 if (!NT_STATUS_IS_OK(status)) {
377 if ((pkt.ptype != DCERPC_PKT_BIND_ACK && pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
378 pkt.u.bind_ack.num_results == 0 ||
379 pkt.u.bind_ack.ctx_list[0].result != 0) {
380 status = NT_STATUS_UNSUCCESSFUL;
383 if (pkt.ptype != DCERPC_PKT_ALTER_ACK) {
384 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
385 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
388 /* the bind_ack might contain a reply set of credentials */
389 if (p->auth_info && pkt.u.bind_ack.auth_info.length) {
390 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
393 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
400 perform a continued bind (and auth3)
402 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
405 struct dcerpc_packet pkt;
409 init_dcerpc_hdr(p, &pkt);
411 pkt.ptype = DCERPC_PKT_AUTH3;
412 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
413 pkt.call_id = p->call_id++;
416 pkt.u.auth.auth_info = data_blob(NULL, 0);
418 /* construct the NDR form of the packet */
419 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info);
420 if (!NT_STATUS_IS_OK(status)) {
424 /* send it on its way */
425 status = p->transport.initial_request(p, mem_ctx, &blob);
426 if (!NT_STATUS_IS_OK(status)) {
434 /* perform a dcerpc bind, using the uuid as the key */
435 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
437 const char *uuid, unsigned version)
439 struct dcerpc_syntax_id syntax;
440 struct dcerpc_syntax_id transfer_syntax;
443 status = GUID_from_string(uuid, &syntax.uuid);
444 if (!NT_STATUS_IS_OK(status)) {
445 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
448 syntax.if_version = version;
450 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
451 if (!NT_STATUS_IS_OK(status)) {
454 transfer_syntax.if_version = NDR_GUID_VERSION;
456 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
460 perform a full request/response pair on a dcerpc pipe
462 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
465 DATA_BLOB *stub_data_in,
466 DATA_BLOB *stub_data_out)
469 struct dcerpc_packet pkt;
471 DATA_BLOB blob, payload;
472 uint32_t remaining, chunk_size;
474 /* allow the application to tell when a fault has happened */
475 p->last_fault_code = 0;
477 init_dcerpc_hdr(p, &pkt);
479 remaining = stub_data_in->length;
481 /* we can write a full max_recv_frag size, minus the dcerpc
482 request header size */
483 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
485 pkt.ptype = DCERPC_PKT_REQUEST;
486 pkt.call_id = p->call_id++;
488 pkt.u.request.alloc_hint = remaining;
489 pkt.u.request.context_id = 0;
490 pkt.u.request.opnum = opnum;
492 /* we send a series of pdus without waiting for a reply until
494 while (remaining > chunk_size) {
495 if (remaining == stub_data_in->length) {
496 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST;
501 pkt.u.request.stub_and_verifier.data = stub_data_in->data +
502 (stub_data_in->length - remaining);
503 pkt.u.request.stub_and_verifier.length = chunk_size;
505 status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
506 if (!NT_STATUS_IS_OK(status)) {
510 status = p->transport.initial_request(p, mem_ctx, &blob);
511 if (!NT_STATUS_IS_OK(status)) {
515 remaining -= chunk_size;
518 /* now we send a pdu with LAST_FRAG sent and get the first
520 if (remaining == stub_data_in->length) {
521 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
523 pkt.pfc_flags = DCERPC_PFC_FLAG_LAST;
525 pkt.u.request.stub_and_verifier.data = stub_data_in->data +
526 (stub_data_in->length - remaining);
527 pkt.u.request.stub_and_verifier.length = remaining;
529 status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
530 if (!NT_STATUS_IS_OK(status)) {
534 /* send the pdu and get the initial response pdu */
535 status = p->transport.full_request(p, mem_ctx, &blob, &blob);
536 if (!NT_STATUS_IS_OK(status)) {
540 status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
541 if (!NT_STATUS_IS_OK(status)) {
545 if (pkt.ptype == DCERPC_PKT_FAULT) {
546 p->last_fault_code = pkt.u.fault.status;
547 return NT_STATUS_NET_WRITE_FAULT;
550 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
551 return NT_STATUS_UNSUCCESSFUL;
554 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
555 /* something is badly wrong! */
556 return NT_STATUS_UNSUCCESSFUL;
559 payload = pkt.u.response.stub_and_verifier;
561 /* continue receiving fragments */
562 while (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
565 status = p->transport.secondary_request(p, mem_ctx, &blob);
566 if (!NT_STATUS_IS_OK(status)) {
570 status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
571 if (!NT_STATUS_IS_OK(status)) {
575 if (pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
576 /* start of another packet!? */
577 return NT_STATUS_UNSUCCESSFUL;
580 if (pkt.ptype == DCERPC_PKT_FAULT) {
581 p->last_fault_code = pkt.u.fault.status;
582 return NT_STATUS_NET_WRITE_FAULT;
585 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
586 return NT_STATUS_UNSUCCESSFUL;
589 length = pkt.u.response.stub_and_verifier.length;
591 payload.data = talloc_realloc(mem_ctx,
593 payload.length + length);
595 return NT_STATUS_NO_MEMORY;
598 memcpy(payload.data + payload.length,
599 pkt.u.response.stub_and_verifier.data,
602 payload.length += length;
606 *stub_data_out = payload;
609 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
610 p->flags |= DCERPC_PULL_BIGENDIAN;
612 p->flags &= ~DCERPC_PULL_BIGENDIAN;
620 this is a paranoid NDR validator. For every packet we push onto the wire
621 we pull it back again, then push it again. Then we compare the raw NDR data
622 for that to the NDR we initially generated. If they don't match then we know
623 we must have a bug in either the pull or push side of our code
625 static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
628 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
629 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
632 struct ndr_pull *pull;
633 struct ndr_push *push;
637 st = talloc(mem_ctx, struct_size);
639 return NT_STATUS_NO_MEMORY;
642 pull = ndr_pull_init_blob(&blob, mem_ctx);
644 return NT_STATUS_NO_MEMORY;
647 status = ndr_pull(pull, NDR_IN, st);
648 if (!NT_STATUS_IS_OK(status)) {
649 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
650 "failed input validation pull - %s",
654 push = ndr_push_init_ctx(mem_ctx);
656 return NT_STATUS_NO_MEMORY;
659 status = ndr_push(push, NDR_IN, st);
660 if (!NT_STATUS_IS_OK(status)) {
661 return ndr_push_error(push, NDR_ERR_VALIDATE,
662 "failed input validation push - %s",
666 blob2 = ndr_push_blob(push);
668 if (!data_blob_equal(&blob, &blob2)) {
669 DEBUG(3,("original:\n"));
670 dump_data(3, blob.data, blob.length);
671 DEBUG(3,("secondary:\n"));
672 dump_data(3, blob2.data, blob2.length);
673 return ndr_push_error(push, NDR_ERR_VALIDATE,
674 "failed input validation data - %s",
682 this is a paranoid NDR input validator. For every packet we pull
683 from the wire we push it back again then pull and push it
684 again. Then we compare the raw NDR data for that to the NDR we
685 initially generated. If they don't match then we know we must have a
686 bug in either the pull or push side of our code
688 static NTSTATUS dcerpc_ndr_validate_out(TALLOC_CTX *mem_ctx,
691 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
692 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
695 struct ndr_pull *pull;
696 struct ndr_push *push;
698 DATA_BLOB blob, blob2;
700 st = talloc(mem_ctx, struct_size);
702 return NT_STATUS_NO_MEMORY;
704 memcpy(st, struct_ptr, struct_size);
706 push = ndr_push_init_ctx(mem_ctx);
708 return NT_STATUS_NO_MEMORY;
711 status = ndr_push(push, NDR_OUT, struct_ptr);
712 if (!NT_STATUS_IS_OK(status)) {
713 return ndr_push_error(push, NDR_ERR_VALIDATE,
714 "failed output validation push - %s",
718 blob = ndr_push_blob(push);
720 pull = ndr_pull_init_blob(&blob, mem_ctx);
722 return NT_STATUS_NO_MEMORY;
725 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
726 status = ndr_pull(pull, NDR_OUT, st);
727 if (!NT_STATUS_IS_OK(status)) {
728 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
729 "failed output validation pull - %s",
733 push = ndr_push_init_ctx(mem_ctx);
735 return NT_STATUS_NO_MEMORY;
738 status = ndr_push(push, NDR_OUT, st);
739 if (!NT_STATUS_IS_OK(status)) {
740 return ndr_push_error(push, NDR_ERR_VALIDATE,
741 "failed output validation push2 - %s",
745 blob2 = ndr_push_blob(push);
747 if (!data_blob_equal(&blob, &blob2)) {
748 DEBUG(3,("original:\n"));
749 dump_data(3, blob.data, blob.length);
750 DEBUG(3,("secondary:\n"));
751 dump_data(3, blob2.data, blob2.length);
752 return ndr_push_error(push, NDR_ERR_VALIDATE,
753 "failed output validation data - %s",
761 a useful helper function for synchronous rpc requests
763 this can be used when you have ndr push/pull functions in the
766 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
769 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
770 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
774 struct ndr_push *push;
775 struct ndr_pull *pull;
777 DATA_BLOB request, response;
779 /* setup for a ndr_push_* call */
780 push = ndr_push_init();
782 talloc_destroy(mem_ctx);
783 return NT_STATUS_NO_MEMORY;
786 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
787 push->flags |= LIBNDR_FLAG_BIGENDIAN;
790 /* push the structure into a blob */
791 status = ndr_push(push, NDR_IN, struct_ptr);
792 if (!NT_STATUS_IS_OK(status)) {
796 /* retrieve the blob */
797 request = ndr_push_blob(push);
799 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
800 status = dcerpc_ndr_validate_in(mem_ctx, request, struct_size,
802 if (!NT_STATUS_IS_OK(status)) {
807 DEBUG(10,("rpc request data:\n"));
808 dump_data(10, request.data, request.length);
810 /* make the actual dcerpc request */
811 status = dcerpc_request(p, opnum, mem_ctx, &request, &response);
812 if (!NT_STATUS_IS_OK(status)) {
816 /* prepare for ndr_pull_* */
817 pull = ndr_pull_init_blob(&response, mem_ctx);
822 if (p->flags & DCERPC_PULL_BIGENDIAN) {
823 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
826 DEBUG(10,("rpc reply data:\n"));
827 dump_data(10, pull->data, pull->data_size);
829 /* pull the structure from the blob */
830 status = ndr_pull(pull, NDR_OUT, struct_ptr);
831 if (!NT_STATUS_IS_OK(status)) {
835 /* possibly check the packet signature */
838 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
839 status = dcerpc_ndr_validate_out(mem_ctx, struct_ptr, struct_size,
841 if (!NT_STATUS_IS_OK(status)) {
846 if (pull->offset != pull->data_size) {
847 DEBUG(0,("Warning! %d unread bytes\n", pull->data_size - pull->offset));
848 status = NT_STATUS_INFO_LENGTH_MISMATCH;
859 a useful function for retrieving the server name we connected to
861 const char *dcerpc_server_name(struct dcerpc_pipe *p)
863 if (!p->transport.peer_name) {
866 return p->transport.peer_name(p);