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 p = talloc_p(NULL, struct dcerpc_pipe);
36 p->reference_count = 0;
38 p->security_state.auth_info = NULL;
39 p->security_state.generic_state = NULL;
40 p->binding_string = NULL;
42 p->srv_max_xmit_frag = 0;
43 p->srv_max_recv_frag = 0;
44 p->last_fault_code = 0;
51 choose the next call id to use
53 static uint32_t next_call_id(struct dcerpc_pipe *p)
56 if (p->call_id == 0) {
62 /* close down a dcerpc over SMB pipe */
63 void dcerpc_pipe_close(struct dcerpc_pipe *p)
67 if (p->reference_count <= 0) {
68 if (p->security_state.generic_state) {
69 gensec_end(&p->security_state.generic_state);
71 p->transport.shutdown_pipe(p);
76 /* we need to be able to get/set the fragment length without doing a full
78 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
80 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
81 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
83 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
87 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
89 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
90 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
92 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
96 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
98 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
99 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
101 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
107 setup for a ndr pull, also setting up any flags from the binding string
109 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
111 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
113 if (ndr == NULL) return ndr;
115 if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
116 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
123 parse a data blob into a dcerpc_packet structure. This handles both
124 input and output packets
126 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
127 struct dcerpc_packet *pkt)
129 struct ndr_pull *ndr;
131 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
133 return NT_STATUS_NO_MEMORY;
136 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
137 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
140 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
144 parse a possibly signed blob into a dcerpc request packet structure
146 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
147 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
148 struct dcerpc_packet *pkt)
150 struct ndr_pull *ndr;
152 struct dcerpc_auth auth;
155 /* non-signed packets are simpler */
156 if (!p->security_state.auth_info || !p->security_state.generic_state) {
157 return dcerpc_pull(p, blob, mem_ctx, pkt);
160 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
162 return NT_STATUS_NO_MEMORY;
165 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
166 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
169 /* pull the basic packet */
170 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
171 if (!NT_STATUS_IS_OK(status)) {
175 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
179 auth_blob.length = 8 + pkt->auth_length;
181 /* check for a valid length */
182 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
183 return NT_STATUS_INFO_LENGTH_MISMATCH;
187 pkt->u.response.stub_and_verifier.data +
188 pkt->u.response.stub_and_verifier.length - auth_blob.length;
189 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
191 /* pull the auth structure */
192 ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
194 return NT_STATUS_NO_MEMORY;
197 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
198 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
201 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
202 if (!NT_STATUS_IS_OK(status)) {
207 /* check signature or unseal the packet */
208 switch (p->security_state.auth_info->auth_level) {
209 case DCERPC_AUTH_LEVEL_PRIVACY:
210 status = gensec_unseal_packet(p->security_state.generic_state,
212 pkt->u.response.stub_and_verifier.data,
213 pkt->u.response.stub_and_verifier.length,
217 case DCERPC_AUTH_LEVEL_INTEGRITY:
218 status = gensec_check_packet(p->security_state.generic_state,
220 pkt->u.response.stub_and_verifier.data,
221 pkt->u.response.stub_and_verifier.length,
225 case DCERPC_AUTH_LEVEL_NONE:
229 status = NT_STATUS_INVALID_LEVEL;
233 /* remove the indicated amount of paddiing */
234 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
235 return NT_STATUS_INFO_LENGTH_MISMATCH;
237 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
244 push a dcerpc request packet into a blob, possibly signing it.
246 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
247 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
248 struct dcerpc_packet *pkt)
251 struct ndr_push *ndr;
253 /* non-signed packets are simpler */
254 if (!p->security_state.auth_info || !p->security_state.generic_state) {
255 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
258 ndr = ndr_push_init_ctx(mem_ctx);
260 return NT_STATUS_NO_MEMORY;
263 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
264 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
267 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
268 if (!NT_STATUS_IS_OK(status)) {
272 /* pad to 16 byte multiple in the payload portion of the
273 packet. This matches what w2k3 does */
274 p->security_state.auth_info->auth_pad_length =
275 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
276 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
278 /* sign or seal the packet */
279 switch (p->security_state.auth_info->auth_level) {
280 case DCERPC_AUTH_LEVEL_PRIVACY:
281 status = gensec_seal_packet(p->security_state.generic_state,
283 ndr->data + DCERPC_REQUEST_LENGTH,
284 ndr->offset - DCERPC_REQUEST_LENGTH,
285 &p->security_state.auth_info->credentials);
288 case DCERPC_AUTH_LEVEL_INTEGRITY:
289 status = gensec_sign_packet(p->security_state.generic_state,
291 ndr->data + DCERPC_REQUEST_LENGTH,
292 ndr->offset - DCERPC_REQUEST_LENGTH,
293 &p->security_state.auth_info->credentials);
296 case DCERPC_AUTH_LEVEL_NONE:
297 p->security_state.auth_info->credentials = data_blob(NULL, 0);
301 status = NT_STATUS_INVALID_LEVEL;
305 if (!NT_STATUS_IS_OK(status)) {
309 /* add the auth verifier */
310 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
311 if (!NT_STATUS_IS_OK(status)) {
315 /* extract the whole packet as a blob */
316 *blob = ndr_push_blob(ndr);
318 /* fill in the fragment length and auth_length, we can't fill
319 in these earlier as we don't know the signature length (it
320 could be variable length) */
321 dcerpc_set_frag_length(blob, blob->length);
322 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
324 data_blob_free(&p->security_state.auth_info->credentials);
331 fill in the fixed values in a dcerpc header
333 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
336 pkt->rpc_vers_minor = 0;
337 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
340 pkt->drep[0] = DCERPC_DREP_LE;
348 hold the state of pending full requests
350 struct full_request_state {
351 DATA_BLOB *reply_blob;
356 receive a reply to a full request
358 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
361 struct full_request_state *state = p->full_request_private;
363 if (!NT_STATUS_IS_OK(status)) {
364 state->status = status;
367 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
368 state->reply_blob = NULL;
372 perform a single pdu synchronous request - used for the bind code
373 this cannot be mixed with normal async requests
375 static NTSTATUS full_request(struct dcerpc_pipe *p,
377 DATA_BLOB *request_blob,
378 DATA_BLOB *reply_blob)
380 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
384 return NT_STATUS_NO_MEMORY;
387 state->reply_blob = reply_blob;
388 state->status = NT_STATUS_OK;
390 p->transport.recv_data = full_request_recv;
391 p->full_request_private = state;
393 status = p->transport.send_request(p, request_blob, True);
394 if (!NT_STATUS_IS_OK(status)) {
398 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
399 struct event_context *ctx = p->transport.event_context(p);
400 event_loop_once(ctx);
403 return state->status;
408 perform a bind using the given syntax
410 the auth_info structure is updated with the reply authentication info
413 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
415 const struct dcerpc_syntax_id *syntax,
416 const struct dcerpc_syntax_id *transfer_syntax)
418 struct dcerpc_packet pkt;
423 p->transfer_syntax = *transfer_syntax;
425 init_dcerpc_hdr(p, &pkt);
427 pkt.ptype = DCERPC_PKT_BIND;
428 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
429 pkt.call_id = p->call_id;
432 pkt.u.bind.max_xmit_frag = 0x2000;
433 pkt.u.bind.max_recv_frag = 0x2000;
434 pkt.u.bind.assoc_group_id = 0;
435 pkt.u.bind.num_contexts = 1;
436 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
437 if (!pkt.u.bind.ctx_list) {
438 return NT_STATUS_NO_MEMORY;
440 pkt.u.bind.ctx_list[0].context_id = 0;
441 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
442 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
443 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
444 pkt.u.bind.auth_info = data_blob(NULL, 0);
446 /* construct the NDR form of the packet */
447 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
448 if (!NT_STATUS_IS_OK(status)) {
452 /* send it on its way */
453 status = full_request(p, mem_ctx, &blob, &blob);
454 if (!NT_STATUS_IS_OK(status)) {
458 /* unmarshall the NDR */
459 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
460 if (!NT_STATUS_IS_OK(status)) {
464 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
465 pkt.u.bind_ack.num_results == 0 ||
466 pkt.u.bind_ack.ctx_list[0].result != 0) {
467 status = NT_STATUS_UNSUCCESSFUL;
470 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
471 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
472 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
475 /* the bind_ack might contain a reply set of credentials */
476 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
477 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
479 p->security_state.auth_info,
480 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
487 perform a alter context using the given syntax
489 the auth_info structure is updated with the reply authentication info
492 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
495 struct dcerpc_packet pkt;
499 init_dcerpc_hdr(p, &pkt);
501 pkt.ptype = DCERPC_PKT_ALTER;
502 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
503 pkt.call_id = p->call_id;
506 pkt.u.alter.max_xmit_frag = 0x2000;
507 pkt.u.alter.max_recv_frag = 0x2000;
508 pkt.u.alter.assoc_group_id = 0;
509 pkt.u.alter.num_contexts = 1;
510 pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
511 if (!pkt.u.alter.ctx_list) {
512 return NT_STATUS_NO_MEMORY;
514 pkt.u.alter.ctx_list[0].context_id = 0;
515 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
516 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
517 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
518 pkt.u.alter.auth_info = data_blob(NULL, 0);
520 /* construct the NDR form of the packet */
521 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
522 if (!NT_STATUS_IS_OK(status)) {
526 /* send it on its way */
527 status = full_request(p, mem_ctx, &blob, &blob);
528 if (!NT_STATUS_IS_OK(status)) {
532 /* unmarshall the NDR */
533 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
534 if (!NT_STATUS_IS_OK(status)) {
538 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
539 pkt.u.alter_ack.num_results == 0 ||
540 pkt.u.alter_ack.ctx_list[0].result != 0) {
541 status = NT_STATUS_UNSUCCESSFUL;
544 /* the bind_ack might contain a reply set of credentials */
545 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
546 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
548 p->security_state.auth_info,
549 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
556 perform a continued bind (and auth3)
558 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
561 struct dcerpc_packet pkt;
565 init_dcerpc_hdr(p, &pkt);
567 pkt.ptype = DCERPC_PKT_AUTH3;
568 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
569 pkt.call_id = next_call_id(p);
572 pkt.u.auth.auth_info = data_blob(NULL, 0);
574 /* construct the NDR form of the packet */
575 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
576 if (!NT_STATUS_IS_OK(status)) {
580 /* send it on its way */
581 status = p->transport.send_request(p, &blob, False);
582 if (!NT_STATUS_IS_OK(status)) {
590 /* perform a dcerpc bind, using the uuid as the key */
591 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
593 const char *uuid, uint_t version)
595 struct dcerpc_syntax_id syntax;
596 struct dcerpc_syntax_id transfer_syntax;
599 status = GUID_from_string(uuid, &syntax.uuid);
600 if (!NT_STATUS_IS_OK(status)) {
601 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
604 syntax.if_version = version;
606 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
607 if (!NT_STATUS_IS_OK(status)) {
610 transfer_syntax.if_version = NDR_GUID_VERSION;
612 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
616 process a fragment received from the transport layer during a
619 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
623 struct dcerpc_packet pkt;
624 struct rpc_request *req;
627 if (!NT_STATUS_IS_OK(status)) {
628 /* all pending requests get the error */
631 req->state = RPC_REQUEST_DONE;
632 req->status = status;
633 DLIST_REMOVE(p->pending, req);
634 if (req->async.callback) {
635 req->async.callback(req);
643 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
645 /* find the matching request. Notice we match before we check
646 the status. this is ok as a pending call_id can never be
648 for (req=p->pending;req;req=req->next) {
649 if (pkt.call_id == req->call_id) break;
653 DEBUG(2,("dcerpc_request: unmatched call_id in response packet\n"));
657 if (!NT_STATUS_IS_OK(status)) {
658 req->status = status;
659 req->state = RPC_REQUEST_DONE;
660 DLIST_REMOVE(p->pending, req);
661 if (req->async.callback) {
662 req->async.callback(req);
667 if (pkt.ptype == DCERPC_PKT_FAULT) {
668 DEBUG(5,("rpc fault 0x%x\n", pkt.u.fault.status));
669 req->fault_code = pkt.u.fault.status;
670 req->status = NT_STATUS_NET_WRITE_FAULT;
671 req->state = RPC_REQUEST_DONE;
672 DLIST_REMOVE(p->pending, req);
673 if (req->async.callback) {
674 req->async.callback(req);
679 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
680 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
682 req->fault_code = DCERPC_FAULT_OTHER;
683 req->status = NT_STATUS_NET_WRITE_FAULT;
684 req->state = RPC_REQUEST_DONE;
685 DLIST_REMOVE(p->pending, req);
686 if (req->async.callback) {
687 req->async.callback(req);
692 length = pkt.u.response.stub_and_verifier.length;
695 req->payload.data = talloc_realloc(req->payload.data,
696 req->payload.length + length);
697 if (!req->payload.data) {
698 req->status = NT_STATUS_NO_MEMORY;
699 req->state = RPC_REQUEST_DONE;
700 DLIST_REMOVE(p->pending, req);
701 if (req->async.callback) {
702 req->async.callback(req);
706 memcpy(req->payload.data+req->payload.length,
707 pkt.u.response.stub_and_verifier.data, length);
708 req->payload.length += length;
711 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
712 p->transport.send_read(p);
716 /* we've got the full payload */
717 req->state = RPC_REQUEST_DONE;
718 DLIST_REMOVE(p->pending, req);
720 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
721 req->flags |= DCERPC_PULL_BIGENDIAN;
723 req->flags &= ~DCERPC_PULL_BIGENDIAN;
726 if (req->async.callback) {
727 req->async.callback(req);
733 perform the send size of a async dcerpc request
735 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
738 DATA_BLOB *stub_data)
740 struct rpc_request *req;
741 struct dcerpc_packet pkt;
743 uint32_t remaining, chunk_size;
745 p->transport.recv_data = dcerpc_request_recv_data;
747 req = talloc_p(mem_ctx, struct rpc_request);
753 req->call_id = next_call_id(p);
754 req->status = NT_STATUS_OK;
755 req->state = RPC_REQUEST_PENDING;
756 req->payload = data_blob(NULL, 0);
759 req->async.callback = NULL;
761 init_dcerpc_hdr(p, &pkt);
763 remaining = stub_data->length;
765 /* we can write a full max_recv_frag size, minus the dcerpc
766 request header size */
767 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
769 pkt.ptype = DCERPC_PKT_REQUEST;
770 pkt.call_id = req->call_id;
772 pkt.u.request.alloc_hint = remaining;
773 pkt.u.request.context_id = 0;
774 pkt.u.request.opnum = opnum;
776 /* we send a series of pdus without waiting for a reply until
778 while (remaining > chunk_size) {
779 if (remaining == stub_data->length) {
780 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST;
785 pkt.u.request.stub_and_verifier.data = stub_data->data +
786 (stub_data->length - remaining);
787 pkt.u.request.stub_and_verifier.length = chunk_size;
789 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
790 if (!NT_STATUS_IS_OK(req->status)) {
791 req->state = RPC_REQUEST_DONE;
795 req->status = p->transport.send_request(p, &blob, False);
796 if (!NT_STATUS_IS_OK(req->status)) {
797 req->state = RPC_REQUEST_DONE;
801 remaining -= chunk_size;
804 /* now we send a pdu with LAST_FRAG sent and get the first
806 if (remaining == stub_data->length) {
807 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
809 pkt.pfc_flags = DCERPC_PFC_FLAG_LAST;
811 pkt.u.request.stub_and_verifier.data = stub_data->data +
812 (stub_data->length - remaining);
813 pkt.u.request.stub_and_verifier.length = remaining;
815 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
816 if (!NT_STATUS_IS_OK(req->status)) {
817 req->state = RPC_REQUEST_DONE;
821 /* send the final pdu */
822 req->status = p->transport.send_request(p, &blob, True);
824 if (!NT_STATUS_IS_OK(req->status)) {
825 req->state = RPC_REQUEST_DONE;
828 DLIST_ADD(p->pending, req);
834 return the event context for a dcerpc pipe
835 used by callers who wish to operate asynchronously
837 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
839 return p->transport.event_context(p);
845 perform the receive side of a async dcerpc request
847 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
849 DATA_BLOB *stub_data)
853 while (req->state == RPC_REQUEST_PENDING) {
854 struct event_context *ctx = dcerpc_event_context(req->p);
855 event_loop_once(ctx);
857 *stub_data = req->payload;
858 status = req->status;
859 if (stub_data->data) {
860 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
862 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
863 req->p->last_fault_code = req->fault_code;
870 perform a full request/response pair on a dcerpc pipe
872 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
875 DATA_BLOB *stub_data_in,
876 DATA_BLOB *stub_data_out)
878 struct rpc_request *req;
880 req = dcerpc_request_send(p, opnum, mem_ctx, stub_data_in);
882 return NT_STATUS_NO_MEMORY;
885 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
890 this is a paranoid NDR validator. For every packet we push onto the wire
891 we pull it back again, then push it again. Then we compare the raw NDR data
892 for that to the NDR we initially generated. If they don't match then we know
893 we must have a bug in either the pull or push side of our code
895 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
899 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
900 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
903 struct ndr_pull *pull;
904 struct ndr_push *push;
908 st = talloc(mem_ctx, struct_size);
910 return NT_STATUS_NO_MEMORY;
913 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
915 return NT_STATUS_NO_MEMORY;
918 status = ndr_pull(pull, NDR_IN, st);
919 if (!NT_STATUS_IS_OK(status)) {
920 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
921 "failed input validation pull - %s",
925 push = ndr_push_init_ctx(mem_ctx);
927 return NT_STATUS_NO_MEMORY;
930 status = ndr_push(push, NDR_IN, st);
931 if (!NT_STATUS_IS_OK(status)) {
932 return ndr_push_error(push, NDR_ERR_VALIDATE,
933 "failed input validation push - %s",
937 blob2 = ndr_push_blob(push);
939 if (!data_blob_equal(&blob, &blob2)) {
940 DEBUG(3,("original:\n"));
941 dump_data(3, blob.data, blob.length);
942 DEBUG(3,("secondary:\n"));
943 dump_data(3, blob2.data, blob2.length);
944 return ndr_push_error(push, NDR_ERR_VALIDATE,
945 "failed input validation data - %s",
953 this is a paranoid NDR input validator. For every packet we pull
954 from the wire we push it back again then pull and push it
955 again. Then we compare the raw NDR data for that to the NDR we
956 initially generated. If they don't match then we know we must have a
957 bug in either the pull or push side of our code
959 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
963 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
964 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
967 struct ndr_pull *pull;
968 struct ndr_push *push;
970 DATA_BLOB blob, blob2;
972 st = talloc(mem_ctx, struct_size);
974 return NT_STATUS_NO_MEMORY;
976 memcpy(st, struct_ptr, struct_size);
978 push = ndr_push_init_ctx(mem_ctx);
980 return NT_STATUS_NO_MEMORY;
983 status = ndr_push(push, NDR_OUT, struct_ptr);
984 if (!NT_STATUS_IS_OK(status)) {
985 return ndr_push_error(push, NDR_ERR_VALIDATE,
986 "failed output validation push - %s",
990 blob = ndr_push_blob(push);
992 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
994 return NT_STATUS_NO_MEMORY;
997 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
998 status = ndr_pull(pull, NDR_OUT, st);
999 if (!NT_STATUS_IS_OK(status)) {
1000 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1001 "failed output validation pull - %s",
1005 push = ndr_push_init_ctx(mem_ctx);
1007 return NT_STATUS_NO_MEMORY;
1010 status = ndr_push(push, NDR_OUT, st);
1011 if (!NT_STATUS_IS_OK(status)) {
1012 return ndr_push_error(push, NDR_ERR_VALIDATE,
1013 "failed output validation push2 - %s",
1017 blob2 = ndr_push_blob(push);
1019 if (!data_blob_equal(&blob, &blob2)) {
1020 DEBUG(3,("original:\n"));
1021 dump_data(3, blob.data, blob.length);
1022 DEBUG(3,("secondary:\n"));
1023 dump_data(3, blob2.data, blob2.length);
1024 return ndr_push_error(push, NDR_ERR_VALIDATE,
1025 "failed output validation data - %s",
1029 return NT_STATUS_OK;
1034 send a rpc request with a given set of ndr helper functions
1036 call dcerpc_ndr_request_recv() to receive the answer
1038 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1040 TALLOC_CTX *mem_ctx,
1041 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1042 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1046 struct ndr_push *push;
1049 struct rpc_request *req;
1051 /* setup for a ndr_push_* call */
1052 push = ndr_push_init();
1057 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1058 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1061 /* push the structure into a blob */
1062 status = ndr_push(push, NDR_IN, struct_ptr);
1063 if (!NT_STATUS_IS_OK(status)) {
1064 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1065 nt_errstr(status)));
1066 ndr_push_free(push);
1070 /* retrieve the blob */
1071 request = ndr_push_blob(push);
1073 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1074 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size,
1075 ndr_push, ndr_pull);
1076 if (!NT_STATUS_IS_OK(status)) {
1077 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1078 nt_errstr(status)));
1079 ndr_push_free(push);
1084 DEBUG(10,("rpc request data:\n"));
1085 dump_data(10, request.data, request.length);
1087 /* make the actual dcerpc request */
1088 req = dcerpc_request_send(p, opnum, mem_ctx, &request);
1091 req->ndr.ndr_push = ndr_push;
1092 req->ndr.ndr_pull = ndr_pull;
1093 req->ndr.struct_ptr = struct_ptr;
1094 req->ndr.struct_size = struct_size;
1095 req->ndr.mem_ctx = mem_ctx;
1098 ndr_push_free(push);
1104 receive the answer from a dcerpc_ndr_request_send()
1106 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1108 struct dcerpc_pipe *p = req->p;
1111 struct ndr_pull *pull;
1112 struct rpc_request_ndr ndr = req->ndr;
1115 /* make sure the recv code doesn't free the request, as we
1116 need to grab the flags element before it is freed */
1117 talloc_increase_ref_count(req);
1119 status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1120 if (!NT_STATUS_IS_OK(status)) {
1127 /* prepare for ndr_pull_* */
1128 pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1130 return NT_STATUS_NO_MEMORY;
1133 if (flags & DCERPC_PULL_BIGENDIAN) {
1134 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1137 DEBUG(10,("rpc reply data:\n"));
1138 dump_data(10, pull->data, pull->data_size);
1140 /* pull the structure from the blob */
1141 status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1142 if (!NT_STATUS_IS_OK(status)) {
1146 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1147 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
1148 ndr.ndr_push, ndr.ndr_pull);
1149 if (!NT_STATUS_IS_OK(status)) {
1154 if (pull->offset != pull->data_size) {
1155 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1156 pull->data_size - pull->offset));
1157 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1158 but it turns out that early versions of NT
1159 (specifically NT3.1) add junk onto the end of rpc
1160 packets, so if we want to interoperate at all with
1161 those versions then we need to ignore this error */
1164 return NT_STATUS_OK;
1169 a useful helper function for synchronous rpc requests
1171 this can be used when you have ndr push/pull functions in the
1174 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1176 TALLOC_CTX *mem_ctx,
1177 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1178 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1182 struct rpc_request *req;
1184 req = dcerpc_ndr_request_send(p, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1186 return NT_STATUS_NO_MEMORY;
1189 return dcerpc_ndr_request_recv(req);
1194 a useful function for retrieving the server name we connected to
1196 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1198 if (!p->transport.peer_name) {
1201 return p->transport.peer_name(p);
1205 a useful function to get the auth_level
1208 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1212 if (p->flags & DCERPC_SEAL) {
1213 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1214 } else if (p->flags & DCERPC_SIGN) {
1215 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1217 auth_level = DCERPC_AUTH_LEVEL_NONE;