2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/gen_ndr/ndr_epmapper.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 static struct dcerpc_interface_list *dcerpc_pipes = NULL;
33 register a dcerpc client interface
35 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
37 struct dcerpc_interface_list *l = talloc(talloc_autofree_context(),
38 struct dcerpc_interface_list);
40 if (idl_iface_by_name (interface->name) != NULL) {
41 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
42 return NT_STATUS_OBJECT_NAME_COLLISION;
46 DLIST_ADD(dcerpc_pipes, l);
52 return the list of registered dcerpc_pipes
54 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
59 /* destroy a dcerpc connection */
60 static int dcerpc_connection_destructor(void *ptr)
62 struct dcerpc_connection *c = ptr;
63 if (c->transport.shutdown_pipe) {
64 c->transport.shutdown_pipe(c);
70 /* initialise a dcerpc connection. */
71 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx)
73 struct dcerpc_connection *c;
75 c = talloc_zero(mem_ctx, struct dcerpc_connection);
81 c->security_state.auth_info = NULL;
82 c->security_state.session_key = dcerpc_generic_session_key;
83 c->security_state.generic_state = NULL;
84 c->binding_string = NULL;
86 c->srv_max_xmit_frag = 0;
87 c->srv_max_recv_frag = 0;
90 talloc_set_destructor(c, dcerpc_connection_destructor);
95 /* initialise a dcerpc pipe. */
96 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx)
98 struct dcerpc_pipe *p;
100 p = talloc(mem_ctx, struct dcerpc_pipe);
105 p->conn = dcerpc_connection_init(p);
106 if (p->conn == NULL) {
111 p->last_fault_code = 0;
114 ZERO_STRUCT(p->syntax);
115 ZERO_STRUCT(p->transfer_syntax);
122 choose the next call id to use
124 static uint32_t next_call_id(struct dcerpc_connection *c)
127 if (c->call_id == 0) {
133 /* we need to be able to get/set the fragment length without doing a full
135 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
137 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
138 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
140 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
144 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
146 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
147 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
149 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
153 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
155 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
156 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
158 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
164 setup for a ndr pull, also setting up any flags from the binding string
166 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
167 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
169 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
171 if (ndr == NULL) return ndr;
173 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
174 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
177 if (c->flags & DCERPC_NDR_REF_ALLOC) {
178 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
185 parse a data blob into a ncacn_packet structure. This handles both
186 input and output packets
188 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
189 struct ncacn_packet *pkt)
191 struct ndr_pull *ndr;
193 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
195 return NT_STATUS_NO_MEMORY;
198 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
199 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
202 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
206 generate a CONNECT level verifier
208 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
210 *blob = data_blob_talloc(mem_ctx, NULL, 16);
211 if (blob->data == NULL) {
212 return NT_STATUS_NO_MEMORY;
214 SIVAL(blob->data, 0, 1);
215 memset(blob->data+4, 0, 12);
220 check a CONNECT level verifier
222 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
224 if (blob->length != 16 ||
225 IVAL(blob->data, 0) != 1) {
226 return NT_STATUS_ACCESS_DENIED;
232 parse a possibly signed blob into a dcerpc request packet structure
234 static NTSTATUS ncacn_pull_request_sign(struct dcerpc_connection *c,
235 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
236 struct ncacn_packet *pkt)
238 struct ndr_pull *ndr;
240 struct dcerpc_auth auth;
243 /* non-signed packets are simpler */
244 if (!c->security_state.auth_info ||
245 !c->security_state.generic_state) {
246 return ncacn_pull(c, blob, mem_ctx, pkt);
249 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
251 return NT_STATUS_NO_MEMORY;
254 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
255 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
258 /* pull the basic packet */
259 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
260 if (!NT_STATUS_IS_OK(status)) {
264 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
268 if (pkt->auth_length == 0 &&
269 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
273 auth_blob.length = 8 + pkt->auth_length;
275 /* check for a valid length */
276 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
277 return NT_STATUS_INFO_LENGTH_MISMATCH;
281 pkt->u.response.stub_and_verifier.data +
282 pkt->u.response.stub_and_verifier.length - auth_blob.length;
283 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
285 /* pull the auth structure */
286 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
288 return NT_STATUS_NO_MEMORY;
291 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
292 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
295 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
296 if (!NT_STATUS_IS_OK(status)) {
301 /* check signature or unseal the packet */
302 switch (c->security_state.auth_info->auth_level) {
303 case DCERPC_AUTH_LEVEL_PRIVACY:
304 status = gensec_unseal_packet(c->security_state.generic_state,
306 blob->data + DCERPC_REQUEST_LENGTH,
307 pkt->u.response.stub_and_verifier.length,
309 blob->length - auth.credentials.length,
311 memcpy(pkt->u.response.stub_and_verifier.data,
312 blob->data + DCERPC_REQUEST_LENGTH,
313 pkt->u.response.stub_and_verifier.length);
316 case DCERPC_AUTH_LEVEL_INTEGRITY:
317 status = gensec_check_packet(c->security_state.generic_state,
319 pkt->u.response.stub_and_verifier.data,
320 pkt->u.response.stub_and_verifier.length,
322 blob->length - auth.credentials.length,
326 case DCERPC_AUTH_LEVEL_CONNECT:
327 status = dcerpc_check_connect_verifier(&auth.credentials);
330 case DCERPC_AUTH_LEVEL_NONE:
334 status = NT_STATUS_INVALID_LEVEL;
338 /* remove the indicated amount of paddiing */
339 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
340 return NT_STATUS_INFO_LENGTH_MISMATCH;
342 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
349 push a dcerpc request packet into a blob, possibly signing it.
351 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
352 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
353 struct ncacn_packet *pkt)
356 struct ndr_push *ndr;
359 /* non-signed packets are simpler */
360 if (!c->security_state.auth_info ||
361 !c->security_state.generic_state) {
362 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
365 ndr = ndr_push_init_ctx(mem_ctx);
367 return NT_STATUS_NO_MEMORY;
370 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
371 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
374 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
375 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
378 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
379 if (!NT_STATUS_IS_OK(status)) {
383 /* pad to 16 byte multiple in the payload portion of the
384 packet. This matches what w2k3 does */
385 c->security_state.auth_info->auth_pad_length =
386 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
387 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
389 /* sign or seal the packet */
390 switch (c->security_state.auth_info->auth_level) {
391 case DCERPC_AUTH_LEVEL_PRIVACY:
392 case DCERPC_AUTH_LEVEL_INTEGRITY:
393 c->security_state.auth_info->credentials
394 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state));
395 data_blob_clear(&c->security_state.auth_info->credentials);
398 case DCERPC_AUTH_LEVEL_CONNECT:
399 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
402 case DCERPC_AUTH_LEVEL_NONE:
403 c->security_state.auth_info->credentials = data_blob(NULL, 0);
407 status = NT_STATUS_INVALID_LEVEL;
411 if (!NT_STATUS_IS_OK(status)) {
415 /* add the auth verifier */
416 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
417 if (!NT_STATUS_IS_OK(status)) {
421 /* extract the whole packet as a blob */
422 *blob = ndr_push_blob(ndr);
424 /* fill in the fragment length and auth_length, we can't fill
425 in these earlier as we don't know the signature length (it
426 could be variable length) */
427 dcerpc_set_frag_length(blob, blob->length);
428 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
430 /* sign or seal the packet */
431 switch (c->security_state.auth_info->auth_level) {
432 case DCERPC_AUTH_LEVEL_PRIVACY:
433 status = gensec_seal_packet(c->security_state.generic_state,
435 blob->data + DCERPC_REQUEST_LENGTH,
436 pkt->u.request.stub_and_verifier.length +
437 c->security_state.auth_info->auth_pad_length,
440 c->security_state.auth_info->credentials.length,
442 if (!NT_STATUS_IS_OK(status)) {
445 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
448 case DCERPC_AUTH_LEVEL_INTEGRITY:
449 status = gensec_sign_packet(c->security_state.generic_state,
451 blob->data + DCERPC_REQUEST_LENGTH,
452 pkt->u.request.stub_and_verifier.length +
453 c->security_state.auth_info->auth_pad_length,
456 c->security_state.auth_info->credentials.length,
458 if (!NT_STATUS_IS_OK(status)) {
461 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
464 case DCERPC_AUTH_LEVEL_CONNECT:
467 case DCERPC_AUTH_LEVEL_NONE:
468 c->security_state.auth_info->credentials = data_blob(NULL, 0);
472 status = NT_STATUS_INVALID_LEVEL;
476 data_blob_free(&c->security_state.auth_info->credentials);
483 fill in the fixed values in a dcerpc header
485 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
488 pkt->rpc_vers_minor = 0;
489 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
492 pkt->drep[0] = DCERPC_DREP_LE;
500 hold the state of pending full requests
502 struct full_request_state {
503 DATA_BLOB *reply_blob;
508 receive a reply to a full request
510 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob,
513 struct full_request_state *state = c->full_request_private;
515 if (!NT_STATUS_IS_OK(status)) {
516 state->status = status;
519 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
520 state->reply_blob = NULL;
524 perform a single pdu synchronous request - used for the bind code
525 this cannot be mixed with normal async requests
527 static NTSTATUS full_request(struct dcerpc_connection *c,
529 DATA_BLOB *request_blob,
530 DATA_BLOB *reply_blob)
532 struct full_request_state *state = talloc(mem_ctx, struct full_request_state);
536 return NT_STATUS_NO_MEMORY;
539 state->reply_blob = reply_blob;
540 state->status = NT_STATUS_OK;
542 c->transport.recv_data = full_request_recv;
543 c->full_request_private = state;
545 status = c->transport.send_request(c, request_blob, True);
546 if (!NT_STATUS_IS_OK(status)) {
550 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
551 struct event_context *ctx = c->transport.event_context(c);
552 if (event_loop_once(ctx) != 0) {
553 return NT_STATUS_CONNECTION_DISCONNECTED;
557 return state->status;
561 map a bind nak reason to a NTSTATUS
563 static NTSTATUS dcerpc_map_reason(uint16_t reason)
566 case DCERPC_BIND_REASON_ASYNTAX:
567 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
569 return NT_STATUS_UNSUCCESSFUL;
574 perform a bind using the given syntax
576 the auth_info structure is updated with the reply authentication info
579 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
581 const struct dcerpc_syntax_id *syntax,
582 const struct dcerpc_syntax_id *transfer_syntax)
584 struct ncacn_packet pkt;
589 p->transfer_syntax = *transfer_syntax;
591 init_ncacn_hdr(p->conn, &pkt);
593 pkt.ptype = DCERPC_PKT_BIND;
594 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
595 pkt.call_id = p->conn->call_id;
598 pkt.u.bind.max_xmit_frag = 5840;
599 pkt.u.bind.max_recv_frag = 5840;
600 pkt.u.bind.assoc_group_id = 0;
601 pkt.u.bind.num_contexts = 1;
602 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
603 if (!pkt.u.bind.ctx_list) {
604 return NT_STATUS_NO_MEMORY;
606 pkt.u.bind.ctx_list[0].context_id = p->context_id;
607 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
608 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
609 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
610 pkt.u.bind.auth_info = data_blob(NULL, 0);
612 /* construct the NDR form of the packet */
613 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
614 if (!NT_STATUS_IS_OK(status)) {
618 /* send it on its way */
619 status = full_request(p->conn, mem_ctx, &blob, &blob);
620 if (!NT_STATUS_IS_OK(status)) {
624 /* unmarshall the NDR */
625 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
626 if (!NT_STATUS_IS_OK(status)) {
630 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
631 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
632 return dcerpc_map_reason(pkt.u.bind_nak.reject_reason);
635 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
636 pkt.u.bind_ack.num_results == 0 ||
637 pkt.u.bind_ack.ctx_list[0].result != 0) {
638 return NT_STATUS_UNSUCCESSFUL;
641 p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
642 p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
644 /* the bind_ack might contain a reply set of credentials */
645 if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
646 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
648 p->conn->security_state.auth_info,
649 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
656 perform a continued bind (and auth3)
658 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
661 struct ncacn_packet pkt;
665 init_ncacn_hdr(c, &pkt);
667 pkt.ptype = DCERPC_PKT_AUTH3;
668 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
669 pkt.call_id = next_call_id(c);
671 pkt.u.auth3._pad = 0;
672 pkt.u.auth3.auth_info = data_blob(NULL, 0);
674 /* construct the NDR form of the packet */
675 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
676 if (!NT_STATUS_IS_OK(status)) {
680 /* send it on its way */
681 status = c->transport.send_request(c, &blob, False);
682 if (!NT_STATUS_IS_OK(status)) {
690 /* perform a dcerpc bind, using the uuid as the key */
691 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
693 const char *uuid, uint_t version)
695 struct dcerpc_syntax_id syntax;
696 struct dcerpc_syntax_id transfer_syntax;
699 status = GUID_from_string(uuid, &syntax.uuid);
700 if (!NT_STATUS_IS_OK(status)) {
701 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
704 syntax.if_version = version;
706 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
707 if (!NT_STATUS_IS_OK(status)) {
710 transfer_syntax.if_version = NDR_GUID_VERSION;
712 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
716 process a fragment received from the transport layer during a
719 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
723 struct ncacn_packet pkt;
724 struct rpc_request *req;
727 if (!NT_STATUS_IS_OK(status)) {
728 /* all pending requests get the error */
731 req->state = RPC_REQUEST_DONE;
732 req->status = status;
733 DLIST_REMOVE(c->pending, req);
734 if (req->async.callback) {
735 req->async.callback(req);
743 status = ncacn_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
745 /* find the matching request. Notice we match before we check
746 the status. this is ok as a pending call_id can never be
748 for (req=c->pending;req;req=req->next) {
749 if (pkt.call_id == req->call_id) break;
753 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
757 if (!NT_STATUS_IS_OK(status)) {
758 req->status = status;
759 req->state = RPC_REQUEST_DONE;
760 DLIST_REMOVE(c->pending, req);
761 if (req->async.callback) {
762 req->async.callback(req);
767 if (pkt.ptype == DCERPC_PKT_FAULT) {
768 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
769 req->fault_code = pkt.u.fault.status;
770 req->status = NT_STATUS_NET_WRITE_FAULT;
771 req->state = RPC_REQUEST_DONE;
772 DLIST_REMOVE(c->pending, req);
773 if (req->async.callback) {
774 req->async.callback(req);
779 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
780 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
782 req->fault_code = DCERPC_FAULT_OTHER;
783 req->status = NT_STATUS_NET_WRITE_FAULT;
784 req->state = RPC_REQUEST_DONE;
785 DLIST_REMOVE(c->pending, req);
786 if (req->async.callback) {
787 req->async.callback(req);
792 length = pkt.u.response.stub_and_verifier.length;
795 req->payload.data = talloc_realloc(req,
798 req->payload.length + length);
799 if (!req->payload.data) {
800 req->status = NT_STATUS_NO_MEMORY;
801 req->state = RPC_REQUEST_DONE;
802 DLIST_REMOVE(c->pending, req);
803 if (req->async.callback) {
804 req->async.callback(req);
808 memcpy(req->payload.data+req->payload.length,
809 pkt.u.response.stub_and_verifier.data, length);
810 req->payload.length += length;
813 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
814 c->transport.send_read(c);
818 /* we've got the full payload */
819 req->state = RPC_REQUEST_DONE;
820 DLIST_REMOVE(c->pending, req);
822 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
823 req->flags |= DCERPC_PULL_BIGENDIAN;
825 req->flags &= ~DCERPC_PULL_BIGENDIAN;
828 if (req->async.callback) {
829 req->async.callback(req);
835 make sure requests are cleaned up
837 static int dcerpc_req_destructor(void *ptr)
839 struct rpc_request *req = ptr;
840 DLIST_REMOVE(req->p->conn->pending, req);
845 perform the send side of a async dcerpc request
847 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
848 const struct GUID *object,
850 DATA_BLOB *stub_data)
852 struct rpc_request *req;
853 struct ncacn_packet pkt;
855 uint32_t remaining, chunk_size;
856 BOOL first_packet = True;
858 p->conn->transport.recv_data = dcerpc_request_recv_data;
860 req = talloc(p, struct rpc_request);
866 req->call_id = next_call_id(p->conn);
867 req->status = NT_STATUS_OK;
868 req->state = RPC_REQUEST_PENDING;
869 req->payload = data_blob(NULL, 0);
872 req->async.callback = NULL;
874 init_ncacn_hdr(p->conn, &pkt);
876 remaining = stub_data->length;
878 /* we can write a full max_recv_frag size, minus the dcerpc
879 request header size */
880 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
882 pkt.ptype = DCERPC_PKT_REQUEST;
883 pkt.call_id = req->call_id;
886 pkt.u.request.alloc_hint = remaining;
887 pkt.u.request.context_id = p->context_id;
888 pkt.u.request.opnum = opnum;
891 pkt.u.request.object.object = *object;
892 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
893 chunk_size -= ndr_size_GUID(object,0);
896 DLIST_ADD(p->conn->pending, req);
898 /* we send a series of pdus without waiting for a reply */
899 while (remaining > 0 || first_packet) {
900 uint32_t chunk = MIN(chunk_size, remaining);
901 BOOL last_frag = False;
903 first_packet = False;
904 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
906 if (remaining == stub_data->length) {
907 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
909 if (chunk == remaining) {
910 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
914 pkt.u.request.stub_and_verifier.data = stub_data->data +
915 (stub_data->length - remaining);
916 pkt.u.request.stub_and_verifier.length = chunk;
918 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
919 if (!NT_STATUS_IS_OK(req->status)) {
920 req->state = RPC_REQUEST_DONE;
921 DLIST_REMOVE(p->conn->pending, req);
925 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
926 if (!NT_STATUS_IS_OK(req->status)) {
927 req->state = RPC_REQUEST_DONE;
928 DLIST_REMOVE(p->conn->pending, req);
935 talloc_set_destructor(req, dcerpc_req_destructor);
941 return the event context for a dcerpc pipe
942 used by callers who wish to operate asynchronously
944 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
946 return p->conn->transport.event_context(p->conn);
952 perform the receive side of a async dcerpc request
954 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
956 DATA_BLOB *stub_data)
960 while (req->state == RPC_REQUEST_PENDING) {
961 struct event_context *ctx = dcerpc_event_context(req->p);
962 if (event_loop_once(ctx) != 0) {
963 return NT_STATUS_CONNECTION_DISCONNECTED;
966 *stub_data = req->payload;
967 status = req->status;
968 if (stub_data->data) {
969 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
971 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
972 req->p->last_fault_code = req->fault_code;
979 perform a full request/response pair on a dcerpc pipe
981 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
985 DATA_BLOB *stub_data_in,
986 DATA_BLOB *stub_data_out)
988 struct rpc_request *req;
990 req = dcerpc_request_send(p, object, opnum, stub_data_in);
992 return NT_STATUS_NO_MEMORY;
995 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1000 this is a paranoid NDR validator. For every packet we push onto the wire
1001 we pull it back again, then push it again. Then we compare the raw NDR data
1002 for that to the NDR we initially generated. If they don't match then we know
1003 we must have a bug in either the pull or push side of our code
1005 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1006 TALLOC_CTX *mem_ctx,
1009 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1010 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1013 struct ndr_pull *pull;
1014 struct ndr_push *push;
1018 st = talloc_size(mem_ctx, struct_size);
1020 return NT_STATUS_NO_MEMORY;
1023 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1025 return NT_STATUS_NO_MEMORY;
1027 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1029 status = ndr_pull(pull, NDR_IN, st);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1032 "failed input validation pull - %s",
1036 push = ndr_push_init_ctx(mem_ctx);
1038 return NT_STATUS_NO_MEMORY;
1041 status = ndr_push(push, NDR_IN, st);
1042 if (!NT_STATUS_IS_OK(status)) {
1043 return ndr_push_error(push, NDR_ERR_VALIDATE,
1044 "failed input validation push - %s",
1048 blob2 = ndr_push_blob(push);
1050 if (!data_blob_equal(&blob, &blob2)) {
1051 DEBUG(3,("original:\n"));
1052 dump_data(3, blob.data, blob.length);
1053 DEBUG(3,("secondary:\n"));
1054 dump_data(3, blob2.data, blob2.length);
1055 return ndr_push_error(push, NDR_ERR_VALIDATE,
1056 "failed input validation data - %s",
1060 return NT_STATUS_OK;
1064 this is a paranoid NDR input validator. For every packet we pull
1065 from the wire we push it back again then pull and push it
1066 again. Then we compare the raw NDR data for that to the NDR we
1067 initially generated. If they don't match then we know we must have a
1068 bug in either the pull or push side of our code
1070 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1071 TALLOC_CTX *mem_ctx,
1074 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1075 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1078 struct ndr_pull *pull;
1079 struct ndr_push *push;
1081 DATA_BLOB blob, blob2;
1083 st = talloc_size(mem_ctx, struct_size);
1085 return NT_STATUS_NO_MEMORY;
1087 memcpy(st, struct_ptr, struct_size);
1089 push = ndr_push_init_ctx(mem_ctx);
1091 return NT_STATUS_NO_MEMORY;
1094 status = ndr_push(push, NDR_OUT, struct_ptr);
1095 if (!NT_STATUS_IS_OK(status)) {
1096 return ndr_push_error(push, NDR_ERR_VALIDATE,
1097 "failed output validation push - %s",
1101 blob = ndr_push_blob(push);
1103 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1105 return NT_STATUS_NO_MEMORY;
1108 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1109 status = ndr_pull(pull, NDR_OUT, st);
1110 if (!NT_STATUS_IS_OK(status)) {
1111 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1112 "failed output validation pull - %s",
1116 push = ndr_push_init_ctx(mem_ctx);
1118 return NT_STATUS_NO_MEMORY;
1121 status = ndr_push(push, NDR_OUT, st);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 return ndr_push_error(push, NDR_ERR_VALIDATE,
1124 "failed output validation push2 - %s",
1128 blob2 = ndr_push_blob(push);
1130 if (!data_blob_equal(&blob, &blob2)) {
1131 DEBUG(3,("original:\n"));
1132 dump_data(3, blob.data, blob.length);
1133 DEBUG(3,("secondary:\n"));
1134 dump_data(3, blob2.data, blob2.length);
1135 return ndr_push_error(push, NDR_ERR_VALIDATE,
1136 "failed output validation data - %s",
1140 return NT_STATUS_OK;
1145 send a rpc request given a dcerpc_call structure
1147 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1148 const struct GUID *object,
1149 const struct dcerpc_interface_table *table,
1151 TALLOC_CTX *mem_ctx,
1154 const struct dcerpc_interface_call *call;
1155 struct ndr_push *push;
1158 struct rpc_request *req;
1160 call = &table->calls[opnum];
1162 /* setup for a ndr_push_* call */
1163 push = ndr_push_init_ctx(mem_ctx);
1168 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1169 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1172 /* push the structure into a blob */
1173 status = call->ndr_push(push, NDR_IN, r);
1174 if (!NT_STATUS_IS_OK(status)) {
1175 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1176 nt_errstr(status)));
1181 /* retrieve the blob */
1182 request = ndr_push_blob(push);
1184 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1185 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1186 call->ndr_push, call->ndr_pull);
1187 if (!NT_STATUS_IS_OK(status)) {
1188 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1189 nt_errstr(status)));
1195 DEBUG(10,("rpc request data:\n"));
1196 dump_data(10, request.data, request.length);
1198 /* make the actual dcerpc request */
1199 req = dcerpc_request_send(p, object, opnum, &request);
1202 req->ndr.table = table;
1203 req->ndr.opnum = opnum;
1204 req->ndr.struct_ptr = r;
1205 req->ndr.mem_ctx = mem_ctx;
1214 receive the answer from a dcerpc_ndr_request_send()
1216 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1218 struct dcerpc_pipe *p = req->p;
1221 struct ndr_pull *pull;
1223 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1224 void *r = req->ndr.struct_ptr;
1225 uint32_t opnum = req->ndr.opnum;
1226 const struct dcerpc_interface_table *table = req->ndr.table;
1227 const struct dcerpc_interface_call *call = &table->calls[opnum];
1229 /* make sure the recv code doesn't free the request, as we
1230 need to grab the flags element before it is freed */
1231 talloc_increase_ref_count(req);
1233 status = dcerpc_request_recv(req, mem_ctx, &response);
1234 if (!NT_STATUS_IS_OK(status)) {
1240 /* prepare for ndr_pull_* */
1241 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1244 return NT_STATUS_NO_MEMORY;
1248 pull->data = talloc_steal(pull, pull->data);
1252 if (flags & DCERPC_PULL_BIGENDIAN) {
1253 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1256 DEBUG(10,("rpc reply data:\n"));
1257 dump_data(10, pull->data, pull->data_size);
1259 /* pull the structure from the blob */
1260 status = call->ndr_pull(pull, NDR_OUT, r);
1261 if (!NT_STATUS_IS_OK(status)) {
1262 dcerpc_log_packet(table, opnum, NDR_OUT,
1267 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1268 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1269 call->ndr_push, call->ndr_pull);
1270 if (!NT_STATUS_IS_OK(status)) {
1271 dcerpc_log_packet(table, opnum, NDR_OUT,
1277 if (pull->offset != pull->data_size) {
1278 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1279 pull->data_size - pull->offset));
1280 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1281 but it turns out that early versions of NT
1282 (specifically NT3.1) add junk onto the end of rpc
1283 packets, so if we want to interoperate at all with
1284 those versions then we need to ignore this error */
1287 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1289 return NT_STATUS_OK;
1294 a useful helper function for synchronous rpc requests
1296 this can be used when you have ndr push/pull functions in the
1299 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1300 const struct GUID *object,
1301 const struct dcerpc_interface_table *table,
1303 TALLOC_CTX *mem_ctx,
1306 struct rpc_request *req;
1308 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1310 return NT_STATUS_NO_MEMORY;
1313 return dcerpc_ndr_request_recv(req);
1318 a useful function for retrieving the server name we connected to
1320 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1322 if (!p->conn->transport.peer_name) {
1325 return p->conn->transport.peer_name(p->conn);
1330 get the dcerpc auth_level for a open connection
1332 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1336 if (c->flags & DCERPC_SEAL) {
1337 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1338 } else if (c->flags & DCERPC_SIGN) {
1339 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1340 } else if (c->flags & DCERPC_CONNECT) {
1341 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1343 auth_level = DCERPC_AUTH_LEVEL_NONE;
1350 send a dcerpc alter_context request
1352 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1353 TALLOC_CTX *mem_ctx,
1354 const struct dcerpc_syntax_id *syntax,
1355 const struct dcerpc_syntax_id *transfer_syntax)
1357 struct ncacn_packet pkt;
1361 p->syntax = *syntax;
1362 p->transfer_syntax = *transfer_syntax;
1364 init_ncacn_hdr(p->conn, &pkt);
1366 pkt.ptype = DCERPC_PKT_ALTER;
1367 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1368 pkt.call_id = p->conn->call_id;
1369 pkt.auth_length = 0;
1371 pkt.u.alter.max_xmit_frag = 5840;
1372 pkt.u.alter.max_recv_frag = 5840;
1373 pkt.u.alter.assoc_group_id = 0;
1374 pkt.u.alter.num_contexts = 1;
1375 pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1376 if (!pkt.u.alter.ctx_list) {
1377 return NT_STATUS_NO_MEMORY;
1379 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1380 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1381 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1382 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1383 pkt.u.alter.auth_info = data_blob(NULL, 0);
1385 /* construct the NDR form of the packet */
1386 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1387 if (!NT_STATUS_IS_OK(status)) {
1391 /* send it on its way */
1392 status = full_request(p->conn, mem_ctx, &blob, &blob);
1393 if (!NT_STATUS_IS_OK(status)) {
1397 /* unmarshall the NDR */
1398 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
1399 if (!NT_STATUS_IS_OK(status)) {
1403 if (pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1404 pkt.u.alter_resp.num_results == 1 &&
1405 pkt.u.alter_resp.ctx_list[0].result != 0) {
1406 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1407 pkt.u.alter_resp.ctx_list[0].reason));
1408 return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason);
1411 if (pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1412 pkt.u.alter_resp.num_results == 0 ||
1413 pkt.u.alter_resp.ctx_list[0].result != 0) {
1414 return NT_STATUS_UNSUCCESSFUL;
1417 /* the alter_resp might contain a reply set of credentials */
1418 if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) {
1419 status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info,
1421 p->conn->security_state.auth_info,
1422 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);