2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004
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 dcerpc_packet structure. This handles both
186 input and output packets
188 static NTSTATUS dcerpc_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
189 struct dcerpc_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_dcerpc_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 dcerpc_pull_request_sign(struct dcerpc_connection *c,
235 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
236 struct dcerpc_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 dcerpc_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_dcerpc_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 dcerpc_push_request_sign(struct dcerpc_connection *c,
352 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
353 struct dcerpc_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 dcerpc_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_dcerpc_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_dcerpc_hdr(struct dcerpc_connection *c, struct dcerpc_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 dcerpc_packet pkt;
589 p->transfer_syntax = *transfer_syntax;
591 init_dcerpc_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 = dcerpc_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 = dcerpc_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);
657 perform a continued bind (and auth3)
659 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
662 struct dcerpc_packet pkt;
666 init_dcerpc_hdr(c, &pkt);
668 pkt.ptype = DCERPC_PKT_AUTH3;
669 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
670 pkt.call_id = next_call_id(c);
672 pkt.u.auth3._pad = 0;
673 pkt.u.auth3.auth_info = data_blob(NULL, 0);
675 /* construct the NDR form of the packet */
676 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
677 if (!NT_STATUS_IS_OK(status)) {
681 /* send it on its way */
682 status = c->transport.send_request(c, &blob, False);
683 if (!NT_STATUS_IS_OK(status)) {
691 /* perform a dcerpc bind, using the uuid as the key */
692 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
694 const char *uuid, uint_t version)
696 struct dcerpc_syntax_id syntax;
697 struct dcerpc_syntax_id transfer_syntax;
700 status = GUID_from_string(uuid, &syntax.uuid);
701 if (!NT_STATUS_IS_OK(status)) {
702 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
705 syntax.if_version = version;
707 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
708 if (!NT_STATUS_IS_OK(status)) {
711 transfer_syntax.if_version = NDR_GUID_VERSION;
713 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
717 process a fragment received from the transport layer during a
720 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
724 struct dcerpc_packet pkt;
725 struct rpc_request *req;
728 if (!NT_STATUS_IS_OK(status)) {
729 /* all pending requests get the error */
732 req->state = RPC_REQUEST_DONE;
733 req->status = status;
734 DLIST_REMOVE(c->pending, req);
735 if (req->async.callback) {
736 req->async.callback(req);
744 status = dcerpc_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
746 /* find the matching request. Notice we match before we check
747 the status. this is ok as a pending call_id can never be
749 for (req=c->pending;req;req=req->next) {
750 if (pkt.call_id == req->call_id) break;
754 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
758 if (!NT_STATUS_IS_OK(status)) {
759 req->status = status;
760 req->state = RPC_REQUEST_DONE;
761 DLIST_REMOVE(c->pending, req);
762 if (req->async.callback) {
763 req->async.callback(req);
768 if (pkt.ptype == DCERPC_PKT_FAULT) {
769 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
770 req->fault_code = pkt.u.fault.status;
771 req->status = NT_STATUS_NET_WRITE_FAULT;
772 req->state = RPC_REQUEST_DONE;
773 DLIST_REMOVE(c->pending, req);
774 if (req->async.callback) {
775 req->async.callback(req);
780 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
781 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
783 req->fault_code = DCERPC_FAULT_OTHER;
784 req->status = NT_STATUS_NET_WRITE_FAULT;
785 req->state = RPC_REQUEST_DONE;
786 DLIST_REMOVE(c->pending, req);
787 if (req->async.callback) {
788 req->async.callback(req);
793 length = pkt.u.response.stub_and_verifier.length;
796 req->payload.data = talloc_realloc(req,
799 req->payload.length + length);
800 if (!req->payload.data) {
801 req->status = NT_STATUS_NO_MEMORY;
802 req->state = RPC_REQUEST_DONE;
803 DLIST_REMOVE(c->pending, req);
804 if (req->async.callback) {
805 req->async.callback(req);
809 memcpy(req->payload.data+req->payload.length,
810 pkt.u.response.stub_and_verifier.data, length);
811 req->payload.length += length;
814 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
815 c->transport.send_read(c);
819 /* we've got the full payload */
820 req->state = RPC_REQUEST_DONE;
821 DLIST_REMOVE(c->pending, req);
823 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
824 req->flags |= DCERPC_PULL_BIGENDIAN;
826 req->flags &= ~DCERPC_PULL_BIGENDIAN;
829 if (req->async.callback) {
830 req->async.callback(req);
836 make sure requests are cleaned up
838 static int dcerpc_req_destructor(void *ptr)
840 struct rpc_request *req = ptr;
841 DLIST_REMOVE(req->p->conn->pending, req);
846 perform the send side of a async dcerpc request
848 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
849 const struct GUID *object,
851 DATA_BLOB *stub_data)
853 struct rpc_request *req;
854 struct dcerpc_packet pkt;
856 uint32_t remaining, chunk_size;
857 BOOL first_packet = True;
859 p->conn->transport.recv_data = dcerpc_request_recv_data;
861 req = talloc(p, struct rpc_request);
867 req->call_id = next_call_id(p->conn);
868 req->status = NT_STATUS_OK;
869 req->state = RPC_REQUEST_PENDING;
870 req->payload = data_blob(NULL, 0);
873 req->async.callback = NULL;
875 init_dcerpc_hdr(p->conn, &pkt);
877 remaining = stub_data->length;
879 /* we can write a full max_recv_frag size, minus the dcerpc
880 request header size */
881 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
883 pkt.ptype = DCERPC_PKT_REQUEST;
884 pkt.call_id = req->call_id;
887 pkt.u.request.alloc_hint = remaining;
888 pkt.u.request.context_id = p->context_id;
889 pkt.u.request.opnum = opnum;
892 pkt.u.request.object.object = *object;
893 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
894 chunk_size -= ndr_size_GUID(object,0);
897 DLIST_ADD(p->conn->pending, req);
899 /* we send a series of pdus without waiting for a reply */
900 while (remaining > 0 || first_packet) {
901 uint32_t chunk = MIN(chunk_size, remaining);
902 BOOL last_frag = False;
904 first_packet = False;
905 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
907 if (remaining == stub_data->length) {
908 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
910 if (chunk == remaining) {
911 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
915 pkt.u.request.stub_and_verifier.data = stub_data->data +
916 (stub_data->length - remaining);
917 pkt.u.request.stub_and_verifier.length = chunk;
919 req->status = dcerpc_push_request_sign(p->conn, &blob, req, &pkt);
920 if (!NT_STATUS_IS_OK(req->status)) {
921 req->state = RPC_REQUEST_DONE;
922 DLIST_REMOVE(p->conn->pending, req);
926 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
927 if (!NT_STATUS_IS_OK(req->status)) {
928 req->state = RPC_REQUEST_DONE;
929 DLIST_REMOVE(p->conn->pending, req);
936 talloc_set_destructor(req, dcerpc_req_destructor);
942 return the event context for a dcerpc pipe
943 used by callers who wish to operate asynchronously
945 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
947 return p->conn->transport.event_context(p->conn);
953 perform the receive side of a async dcerpc request
955 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
957 DATA_BLOB *stub_data)
961 while (req->state == RPC_REQUEST_PENDING) {
962 struct event_context *ctx = dcerpc_event_context(req->p);
963 if (event_loop_once(ctx) != 0) {
964 return NT_STATUS_CONNECTION_DISCONNECTED;
967 *stub_data = req->payload;
968 status = req->status;
969 if (stub_data->data) {
970 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
972 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
973 req->p->last_fault_code = req->fault_code;
980 perform a full request/response pair on a dcerpc pipe
982 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
986 DATA_BLOB *stub_data_in,
987 DATA_BLOB *stub_data_out)
989 struct rpc_request *req;
991 req = dcerpc_request_send(p, object, opnum, stub_data_in);
993 return NT_STATUS_NO_MEMORY;
996 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1001 this is a paranoid NDR validator. For every packet we push onto the wire
1002 we pull it back again, then push it again. Then we compare the raw NDR data
1003 for that to the NDR we initially generated. If they don't match then we know
1004 we must have a bug in either the pull or push side of our code
1006 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1007 TALLOC_CTX *mem_ctx,
1010 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1011 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1014 struct ndr_pull *pull;
1015 struct ndr_push *push;
1019 st = talloc_size(mem_ctx, struct_size);
1021 return NT_STATUS_NO_MEMORY;
1024 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1026 return NT_STATUS_NO_MEMORY;
1028 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1030 status = ndr_pull(pull, NDR_IN, st);
1031 if (!NT_STATUS_IS_OK(status)) {
1032 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1033 "failed input validation pull - %s",
1037 push = ndr_push_init_ctx(mem_ctx);
1039 return NT_STATUS_NO_MEMORY;
1042 status = ndr_push(push, NDR_IN, st);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 return ndr_push_error(push, NDR_ERR_VALIDATE,
1045 "failed input validation push - %s",
1049 blob2 = ndr_push_blob(push);
1051 if (!data_blob_equal(&blob, &blob2)) {
1052 DEBUG(3,("original:\n"));
1053 dump_data(3, blob.data, blob.length);
1054 DEBUG(3,("secondary:\n"));
1055 dump_data(3, blob2.data, blob2.length);
1056 return ndr_push_error(push, NDR_ERR_VALIDATE,
1057 "failed input validation data - %s",
1061 return NT_STATUS_OK;
1065 this is a paranoid NDR input validator. For every packet we pull
1066 from the wire we push it back again then pull and push it
1067 again. Then we compare the raw NDR data for that to the NDR we
1068 initially generated. If they don't match then we know we must have a
1069 bug in either the pull or push side of our code
1071 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1072 TALLOC_CTX *mem_ctx,
1075 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1076 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1079 struct ndr_pull *pull;
1080 struct ndr_push *push;
1082 DATA_BLOB blob, blob2;
1084 st = talloc_size(mem_ctx, struct_size);
1086 return NT_STATUS_NO_MEMORY;
1088 memcpy(st, struct_ptr, struct_size);
1090 push = ndr_push_init_ctx(mem_ctx);
1092 return NT_STATUS_NO_MEMORY;
1095 status = ndr_push(push, NDR_OUT, struct_ptr);
1096 if (!NT_STATUS_IS_OK(status)) {
1097 return ndr_push_error(push, NDR_ERR_VALIDATE,
1098 "failed output validation push - %s",
1102 blob = ndr_push_blob(push);
1104 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1106 return NT_STATUS_NO_MEMORY;
1109 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1110 status = ndr_pull(pull, NDR_OUT, st);
1111 if (!NT_STATUS_IS_OK(status)) {
1112 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1113 "failed output validation pull - %s",
1117 push = ndr_push_init_ctx(mem_ctx);
1119 return NT_STATUS_NO_MEMORY;
1122 status = ndr_push(push, NDR_OUT, st);
1123 if (!NT_STATUS_IS_OK(status)) {
1124 return ndr_push_error(push, NDR_ERR_VALIDATE,
1125 "failed output validation push2 - %s",
1129 blob2 = ndr_push_blob(push);
1131 if (!data_blob_equal(&blob, &blob2)) {
1132 DEBUG(3,("original:\n"));
1133 dump_data(3, blob.data, blob.length);
1134 DEBUG(3,("secondary:\n"));
1135 dump_data(3, blob2.data, blob2.length);
1136 return ndr_push_error(push, NDR_ERR_VALIDATE,
1137 "failed output validation data - %s",
1141 return NT_STATUS_OK;
1146 send a rpc request given a dcerpc_call structure
1148 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1149 const struct GUID *object,
1150 const struct dcerpc_interface_table *table,
1152 TALLOC_CTX *mem_ctx,
1155 const struct dcerpc_interface_call *call;
1156 struct ndr_push *push;
1159 struct rpc_request *req;
1161 call = &table->calls[opnum];
1163 /* setup for a ndr_push_* call */
1164 push = ndr_push_init_ctx(mem_ctx);
1169 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1170 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1173 /* push the structure into a blob */
1174 status = call->ndr_push(push, NDR_IN, r);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1177 nt_errstr(status)));
1182 /* retrieve the blob */
1183 request = ndr_push_blob(push);
1185 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1186 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1187 call->ndr_push, call->ndr_pull);
1188 if (!NT_STATUS_IS_OK(status)) {
1189 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1190 nt_errstr(status)));
1196 DEBUG(10,("rpc request data:\n"));
1197 dump_data(10, request.data, request.length);
1199 /* make the actual dcerpc request */
1200 req = dcerpc_request_send(p, object, opnum, &request);
1203 req->ndr.table = table;
1204 req->ndr.opnum = opnum;
1205 req->ndr.struct_ptr = r;
1206 req->ndr.mem_ctx = mem_ctx;
1215 receive the answer from a dcerpc_ndr_request_send()
1217 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1219 struct dcerpc_pipe *p = req->p;
1222 struct ndr_pull *pull;
1224 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1225 void *r = req->ndr.struct_ptr;
1226 uint32_t opnum = req->ndr.opnum;
1227 const struct dcerpc_interface_table *table = req->ndr.table;
1228 const struct dcerpc_interface_call *call = &table->calls[opnum];
1230 /* make sure the recv code doesn't free the request, as we
1231 need to grab the flags element before it is freed */
1232 talloc_increase_ref_count(req);
1234 status = dcerpc_request_recv(req, mem_ctx, &response);
1235 if (!NT_STATUS_IS_OK(status)) {
1241 /* prepare for ndr_pull_* */
1242 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1245 return NT_STATUS_NO_MEMORY;
1249 pull->data = talloc_steal(pull, pull->data);
1253 if (flags & DCERPC_PULL_BIGENDIAN) {
1254 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1257 DEBUG(10,("rpc reply data:\n"));
1258 dump_data(10, pull->data, pull->data_size);
1260 /* pull the structure from the blob */
1261 status = call->ndr_pull(pull, NDR_OUT, r);
1262 if (!NT_STATUS_IS_OK(status)) {
1263 dcerpc_log_packet(table, opnum, NDR_OUT,
1268 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1269 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1270 call->ndr_push, call->ndr_pull);
1271 if (!NT_STATUS_IS_OK(status)) {
1272 dcerpc_log_packet(table, opnum, NDR_OUT,
1278 if (pull->offset != pull->data_size) {
1279 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1280 pull->data_size - pull->offset));
1281 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1282 but it turns out that early versions of NT
1283 (specifically NT3.1) add junk onto the end of rpc
1284 packets, so if we want to interoperate at all with
1285 those versions then we need to ignore this error */
1288 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1290 return NT_STATUS_OK;
1295 a useful helper function for synchronous rpc requests
1297 this can be used when you have ndr push/pull functions in the
1300 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1301 const struct GUID *object,
1302 const struct dcerpc_interface_table *table,
1304 TALLOC_CTX *mem_ctx,
1307 struct rpc_request *req;
1309 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1311 return NT_STATUS_NO_MEMORY;
1314 return dcerpc_ndr_request_recv(req);
1319 a useful function for retrieving the server name we connected to
1321 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1323 if (!p->conn->transport.peer_name) {
1326 return p->conn->transport.peer_name(p->conn);
1331 get the dcerpc auth_level for a open connection
1333 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1337 if (c->flags & DCERPC_SEAL) {
1338 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1339 } else if (c->flags & DCERPC_SIGN) {
1340 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1341 } else if (c->flags & DCERPC_CONNECT) {
1342 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1344 auth_level = DCERPC_AUTH_LEVEL_NONE;
1351 send a dcerpc alter_context request
1353 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1354 TALLOC_CTX *mem_ctx,
1355 const struct dcerpc_syntax_id *syntax,
1356 const struct dcerpc_syntax_id *transfer_syntax)
1358 struct dcerpc_packet pkt;
1362 p->syntax = *syntax;
1363 p->transfer_syntax = *transfer_syntax;
1365 init_dcerpc_hdr(p->conn, &pkt);
1367 pkt.ptype = DCERPC_PKT_ALTER;
1368 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1369 pkt.call_id = p->conn->call_id;
1370 pkt.auth_length = 0;
1372 pkt.u.alter.max_xmit_frag = 5840;
1373 pkt.u.alter.max_recv_frag = 5840;
1374 pkt.u.alter.assoc_group_id = 0;
1375 pkt.u.alter.num_contexts = 1;
1376 pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1377 if (!pkt.u.alter.ctx_list) {
1378 return NT_STATUS_NO_MEMORY;
1380 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1381 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1382 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1383 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1384 pkt.u.alter.auth_info = data_blob(NULL, 0);
1386 /* construct the NDR form of the packet */
1387 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1388 if (!NT_STATUS_IS_OK(status)) {
1392 /* send it on its way */
1393 status = full_request(p->conn, mem_ctx, &blob, &blob);
1394 if (!NT_STATUS_IS_OK(status)) {
1398 /* unmarshall the NDR */
1399 status = dcerpc_pull(p->conn, &blob, mem_ctx, &pkt);
1400 if (!NT_STATUS_IS_OK(status)) {
1404 if (pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1405 pkt.u.alter_resp.num_results == 1 &&
1406 pkt.u.alter_resp.ctx_list[0].result != 0) {
1407 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1408 pkt.u.alter_resp.ctx_list[0].reason));
1409 return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason);
1412 if (pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1413 pkt.u.alter_resp.num_results == 0 ||
1414 pkt.u.alter_resp.ctx_list[0].result != 0) {
1415 return NT_STATUS_UNSUCCESSFUL;
1418 /* the alter_resp might contain a reply set of credentials */
1419 if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) {
1420 status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info,
1422 p->conn->security_state.auth_info,
1423 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);