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,
186 pkt->u.response.stub_and_verifier.data,
187 pkt->u.response.stub_and_verifier.length,
191 case DCERPC_AUTH_LEVEL_INTEGRITY:
192 status = p->security_state->check_packet(p->security_state,
193 pkt->u.response.stub_and_verifier.data,
194 pkt->u.response.stub_and_verifier.length,
198 case DCERPC_AUTH_LEVEL_NONE:
202 status = NT_STATUS_INVALID_LEVEL;
206 /* remove the indicated amount of paddiing */
207 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
208 return NT_STATUS_INFO_LENGTH_MISMATCH;
210 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
217 push a dcerpc request packet into a blob, possibly signing it.
219 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
220 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
221 struct dcerpc_packet *pkt)
224 struct ndr_push *ndr;
226 /* non-signed packets are simpler */
227 if (!p->auth_info || !p->security_state) {
228 return dcerpc_push_auth(blob, mem_ctx, pkt, p->auth_info);
231 ndr = ndr_push_init_ctx(mem_ctx);
233 return NT_STATUS_NO_MEMORY;
236 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
237 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
240 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
241 if (!NT_STATUS_IS_OK(status)) {
245 /* pad to 8 byte multiple */
246 p->auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
247 ndr_push_zero(ndr, p->auth_info->auth_pad_length);
249 /* sign or seal the packet */
250 switch (p->auth_info->auth_level) {
251 case DCERPC_AUTH_LEVEL_PRIVACY:
252 status = p->security_state->seal_packet(p->security_state,
253 ndr->data + DCERPC_REQUEST_LENGTH,
254 ndr->offset - DCERPC_REQUEST_LENGTH,
255 &p->auth_info->credentials);
258 case DCERPC_AUTH_LEVEL_INTEGRITY:
259 status = p->security_state->sign_packet(p->security_state,
260 ndr->data + DCERPC_REQUEST_LENGTH,
261 ndr->offset - DCERPC_REQUEST_LENGTH,
262 &p->auth_info->credentials);
265 case DCERPC_AUTH_LEVEL_NONE:
266 p->auth_info->credentials = data_blob(NULL, 0);
270 status = NT_STATUS_INVALID_LEVEL;
274 if (!NT_STATUS_IS_OK(status)) {
278 /* add the auth verifier */
279 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->auth_info);
280 if (!NT_STATUS_IS_OK(status)) {
284 /* extract the whole packet as a blob */
285 *blob = ndr_push_blob(ndr);
287 /* fill in the fragment length and auth_length, we can't fill
288 in these earlier as we don't know the signature length (it
289 could be variable length) */
290 dcerpc_set_frag_length(blob, blob->length);
291 dcerpc_set_auth_length(blob, p->auth_info->credentials.length);
293 data_blob_free(&p->auth_info->credentials);
300 fill in the fixed values in a dcerpc header
302 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
305 pkt->rpc_vers_minor = 0;
306 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
309 pkt->drep[0] = DCERPC_DREP_LE;
318 perform a bind using the given syntax
320 the auth_info structure is updated with the reply authentication info
323 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
325 const struct dcerpc_syntax_id *syntax,
326 const struct dcerpc_syntax_id *transfer_syntax)
328 struct dcerpc_packet pkt;
331 struct dcerpc_syntax_id tsyntax;
333 init_dcerpc_hdr(p, &pkt);
335 pkt.ptype = DCERPC_PKT_BIND;
336 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
337 pkt.call_id = p->call_id;
340 pkt.u.bind.max_xmit_frag = 0x2000;
341 pkt.u.bind.max_recv_frag = 0x2000;
342 pkt.u.bind.assoc_group_id = 0;
343 pkt.u.bind.num_contexts = 1;
344 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
345 if (!pkt.u.bind.ctx_list) {
346 return NT_STATUS_NO_MEMORY;
348 pkt.u.bind.ctx_list[0].context_id = 0;
349 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
350 pkt.u.bind.ctx_list[0].abstract_syntax = *syntax;
351 tsyntax = *transfer_syntax;
352 pkt.u.bind.ctx_list[0].transfer_syntaxes = &tsyntax;
353 pkt.u.bind.auth_info = data_blob(NULL, 0);
355 /* construct the NDR form of the packet */
356 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info);
357 if (!NT_STATUS_IS_OK(status)) {
361 /* send it on its way */
362 status = p->transport.full_request(p, mem_ctx, &blob, &blob);
363 if (!NT_STATUS_IS_OK(status)) {
367 /* unmarshall the NDR */
368 status = dcerpc_pull(&blob, mem_ctx, &pkt);
369 if (!NT_STATUS_IS_OK(status)) {
373 if ((pkt.ptype != DCERPC_PKT_BIND_ACK && pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
374 pkt.u.bind_ack.num_results == 0 ||
375 pkt.u.bind_ack.ctx_list[0].result != 0) {
376 status = NT_STATUS_UNSUCCESSFUL;
379 if (pkt.ptype != DCERPC_PKT_ALTER_ACK) {
380 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
381 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
384 /* the bind_ack might contain a reply set of credentials */
385 if (p->auth_info && pkt.u.bind_ack.auth_info.length) {
386 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
389 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
396 perform a continued bind (and auth3)
398 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
401 struct dcerpc_packet pkt;
405 init_dcerpc_hdr(p, &pkt);
407 pkt.ptype = DCERPC_PKT_AUTH3;
408 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
409 pkt.call_id = p->call_id++;
412 pkt.u.auth.auth_info = data_blob(NULL, 0);
414 /* construct the NDR form of the packet */
415 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info);
416 if (!NT_STATUS_IS_OK(status)) {
420 /* send it on its way */
421 status = p->transport.initial_request(p, mem_ctx, &blob);
422 if (!NT_STATUS_IS_OK(status)) {
430 /* perform a dcerpc bind, using the uuid as the key */
431 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
433 const char *uuid, unsigned version)
435 struct dcerpc_syntax_id syntax;
436 struct dcerpc_syntax_id transfer_syntax;
439 status = GUID_from_string(uuid, &syntax.uuid);
440 if (!NT_STATUS_IS_OK(status)) {
441 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
444 syntax.if_version = version;
446 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
447 if (!NT_STATUS_IS_OK(status)) {
450 transfer_syntax.if_version = NDR_GUID_VERSION;
452 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
456 perform a full request/response pair on a dcerpc pipe
458 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
461 DATA_BLOB *stub_data_in,
462 DATA_BLOB *stub_data_out)
465 struct dcerpc_packet pkt;
467 DATA_BLOB blob, payload;
468 uint32 remaining, chunk_size;
470 init_dcerpc_hdr(p, &pkt);
472 remaining = stub_data_in->length;
474 /* we can write a full max_recv_frag size, minus the dcerpc
475 request header size */
476 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
478 pkt.ptype = DCERPC_PKT_REQUEST;
479 pkt.call_id = p->call_id++;
481 pkt.u.request.alloc_hint = remaining;
482 pkt.u.request.context_id = 0;
483 pkt.u.request.opnum = opnum;
485 /* we send a series of pdus without waiting for a reply until
487 while (remaining > chunk_size) {
488 if (remaining == stub_data_in->length) {
489 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST;
494 pkt.u.request.stub_and_verifier.data = stub_data_in->data +
495 (stub_data_in->length - remaining);
496 pkt.u.request.stub_and_verifier.length = chunk_size;
498 status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
499 if (!NT_STATUS_IS_OK(status)) {
503 status = p->transport.initial_request(p, mem_ctx, &blob);
504 if (!NT_STATUS_IS_OK(status)) {
508 remaining -= chunk_size;
511 /* now we send a pdu with LAST_FRAG sent and get the first
513 if (remaining == stub_data_in->length) {
514 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
516 pkt.pfc_flags = DCERPC_PFC_FLAG_LAST;
518 pkt.u.request.stub_and_verifier.data = stub_data_in->data +
519 (stub_data_in->length - remaining);
520 pkt.u.request.stub_and_verifier.length = remaining;
522 status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
523 if (!NT_STATUS_IS_OK(status)) {
527 /* send the pdu and get the initial response pdu */
528 status = p->transport.full_request(p, mem_ctx, &blob, &blob);
529 if (!NT_STATUS_IS_OK(status)) {
533 status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
534 if (!NT_STATUS_IS_OK(status)) {
538 if (pkt.ptype == DCERPC_PKT_FAULT) {
539 p->last_fault_code = pkt.u.fault.status;
540 return NT_STATUS_NET_WRITE_FAULT;
543 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
544 return NT_STATUS_UNSUCCESSFUL;
547 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
548 /* something is badly wrong! */
549 return NT_STATUS_UNSUCCESSFUL;
552 payload = pkt.u.response.stub_and_verifier;
554 /* continue receiving fragments */
555 while (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
558 status = p->transport.secondary_request(p, mem_ctx, &blob);
559 if (!NT_STATUS_IS_OK(status)) {
563 status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
564 if (!NT_STATUS_IS_OK(status)) {
568 if (pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
569 /* start of another packet!? */
570 return NT_STATUS_UNSUCCESSFUL;
573 if (pkt.ptype == DCERPC_PKT_FAULT) {
574 p->last_fault_code = pkt.u.fault.status;
575 return NT_STATUS_NET_WRITE_FAULT;
578 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
579 return NT_STATUS_UNSUCCESSFUL;
582 length = pkt.u.response.stub_and_verifier.length;
584 payload.data = talloc_realloc(mem_ctx,
586 payload.length + length);
588 return NT_STATUS_NO_MEMORY;
591 memcpy(payload.data + payload.length,
592 pkt.u.response.stub_and_verifier.data,
595 payload.length += length;
599 *stub_data_out = payload;
602 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
603 p->flags |= DCERPC_PULL_BIGENDIAN;
605 p->flags &= ~DCERPC_PULL_BIGENDIAN;
613 this is a paranoid NDR validator. For every packet we push onto the wire
614 we pull it back again, then push it again. Then we compare the raw NDR data
615 for that to the NDR we initially generated. If they don't match then we know
616 we must have a bug in either the pull or push side of our code
618 static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
621 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
622 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
625 struct ndr_pull *pull;
626 struct ndr_push *push;
630 st = talloc(mem_ctx, struct_size);
632 return NT_STATUS_NO_MEMORY;
635 pull = ndr_pull_init_blob(&blob, mem_ctx);
637 return NT_STATUS_NO_MEMORY;
640 status = ndr_pull(pull, NDR_IN, st);
641 if (!NT_STATUS_IS_OK(status)) {
642 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
643 "failed input validation pull - %s",
647 push = ndr_push_init_ctx(mem_ctx);
649 return NT_STATUS_NO_MEMORY;
652 status = ndr_push(push, NDR_IN, st);
653 if (!NT_STATUS_IS_OK(status)) {
654 return ndr_push_error(push, NDR_ERR_VALIDATE,
655 "failed input validation push - %s",
659 blob2 = ndr_push_blob(push);
661 if (!data_blob_equal(&blob, &blob2)) {
662 DEBUG(3,("original:\n"));
663 dump_data(3, blob.data, blob.length);
664 DEBUG(3,("secondary:\n"));
665 dump_data(3, blob2.data, blob2.length);
666 return ndr_push_error(push, NDR_ERR_VALIDATE,
667 "failed input validation data - %s",
675 this is a paranoid NDR input validator. For every packet we pull
676 from the wire we push it back again then pull and push it
677 again. Then we compare the raw NDR data for that to the NDR we
678 initially generated. If they don't match then we know we must have a
679 bug in either the pull or push side of our code
681 static NTSTATUS dcerpc_ndr_validate_out(TALLOC_CTX *mem_ctx,
684 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
685 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
688 struct ndr_pull *pull;
689 struct ndr_push *push;
691 DATA_BLOB blob, blob2;
693 st = talloc(mem_ctx, struct_size);
695 return NT_STATUS_NO_MEMORY;
697 memcpy(st, struct_ptr, struct_size);
699 push = ndr_push_init_ctx(mem_ctx);
701 return NT_STATUS_NO_MEMORY;
704 status = ndr_push(push, NDR_OUT, struct_ptr);
705 if (!NT_STATUS_IS_OK(status)) {
706 return ndr_push_error(push, NDR_ERR_VALIDATE,
707 "failed output validation push - %s",
711 blob = ndr_push_blob(push);
713 pull = ndr_pull_init_blob(&blob, mem_ctx);
715 return NT_STATUS_NO_MEMORY;
718 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
719 status = ndr_pull(pull, NDR_OUT, st);
720 if (!NT_STATUS_IS_OK(status)) {
721 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
722 "failed output validation pull - %s",
726 push = ndr_push_init_ctx(mem_ctx);
728 return NT_STATUS_NO_MEMORY;
731 status = ndr_push(push, NDR_OUT, st);
732 if (!NT_STATUS_IS_OK(status)) {
733 return ndr_push_error(push, NDR_ERR_VALIDATE,
734 "failed output validation push2 - %s",
738 blob2 = ndr_push_blob(push);
740 if (!data_blob_equal(&blob, &blob2)) {
741 DEBUG(3,("original:\n"));
742 dump_data(3, blob.data, blob.length);
743 DEBUG(3,("secondary:\n"));
744 dump_data(3, blob2.data, blob2.length);
745 return ndr_push_error(push, NDR_ERR_VALIDATE,
746 "failed output validation data - %s",
754 a useful helper function for synchronous rpc requests
756 this can be used when you have ndr push/pull functions in the
759 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
762 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
763 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
767 struct ndr_push *push;
768 struct ndr_pull *pull;
770 DATA_BLOB request, response;
772 /* setup for a ndr_push_* call */
773 push = ndr_push_init();
775 talloc_destroy(mem_ctx);
776 return NT_STATUS_NO_MEMORY;
779 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
780 push->flags |= LIBNDR_FLAG_BIGENDIAN;
783 /* push the structure into a blob */
784 status = ndr_push(push, NDR_IN, struct_ptr);
785 if (!NT_STATUS_IS_OK(status)) {
789 /* retrieve the blob */
790 request = ndr_push_blob(push);
792 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
793 status = dcerpc_ndr_validate_in(mem_ctx, request, struct_size,
795 if (!NT_STATUS_IS_OK(status)) {
800 DEBUG(10,("rpc request data:\n"));
801 dump_data(10, request.data, request.length);
803 /* make the actual dcerpc request */
804 status = dcerpc_request(p, opnum, mem_ctx, &request, &response);
805 if (!NT_STATUS_IS_OK(status)) {
809 /* prepare for ndr_pull_* */
810 pull = ndr_pull_init_blob(&response, mem_ctx);
815 if (p->flags & DCERPC_PULL_BIGENDIAN) {
816 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
819 DEBUG(10,("rpc reply data:\n"));
820 dump_data(10, pull->data, pull->data_size);
822 /* pull the structure from the blob */
823 status = ndr_pull(pull, NDR_OUT, struct_ptr);
824 if (!NT_STATUS_IS_OK(status)) {
828 /* possibly check the packet signature */
831 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
832 status = dcerpc_ndr_validate_out(mem_ctx, struct_ptr, struct_size,
834 if (!NT_STATUS_IS_OK(status)) {
839 if (pull->offset != pull->data_size) {
840 DEBUG(0,("Warning! %d unread bytes\n", pull->data_size - pull->offset));
841 status = NT_STATUS_INFO_LENGTH_MISMATCH;
852 a useful function for retrieving the server name we connected to
854 const char *dcerpc_server_name(struct dcerpc_pipe *p)
856 if (!p->transport.peer_name) {
859 return p->transport.peer_name(p);