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;
113 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
115 ZERO_STRUCT(p->syntax);
116 ZERO_STRUCT(p->transfer_syntax);
123 choose the next call id to use
125 static uint32_t next_call_id(struct dcerpc_connection *c)
128 if (c->call_id == 0) {
134 /* we need to be able to get/set the fragment length without doing a full
136 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
138 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
139 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
141 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
145 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
147 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
148 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
150 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
154 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
156 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
157 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
159 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
165 setup for a ndr pull, also setting up any flags from the binding string
167 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
168 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
170 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
172 if (ndr == NULL) return ndr;
174 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
175 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
178 if (c->flags & DCERPC_NDR_REF_ALLOC) {
179 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
186 parse a data blob into a ncacn_packet structure. This handles both
187 input and output packets
189 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
190 struct ncacn_packet *pkt)
192 struct ndr_pull *ndr;
194 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
196 return NT_STATUS_NO_MEMORY;
199 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
200 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
203 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
207 generate a CONNECT level verifier
209 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
211 *blob = data_blob_talloc(mem_ctx, NULL, 16);
212 if (blob->data == NULL) {
213 return NT_STATUS_NO_MEMORY;
215 SIVAL(blob->data, 0, 1);
216 memset(blob->data+4, 0, 12);
221 check a CONNECT level verifier
223 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
225 if (blob->length != 16 ||
226 IVAL(blob->data, 0) != 1) {
227 return NT_STATUS_ACCESS_DENIED;
233 parse a possibly signed blob into a dcerpc request packet structure
235 static NTSTATUS ncacn_pull_request_sign(struct dcerpc_connection *c,
236 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
237 struct ncacn_packet *pkt)
239 struct ndr_pull *ndr;
241 struct dcerpc_auth auth;
244 /* non-signed packets are simpler */
245 if (!c->security_state.auth_info ||
246 !c->security_state.generic_state) {
247 return ncacn_pull(c, blob, mem_ctx, pkt);
250 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
252 return NT_STATUS_NO_MEMORY;
255 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
256 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
259 /* pull the basic packet */
260 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
261 if (!NT_STATUS_IS_OK(status)) {
265 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
269 if (pkt->auth_length == 0 &&
270 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
274 auth_blob.length = 8 + pkt->auth_length;
276 /* check for a valid length */
277 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
278 return NT_STATUS_INFO_LENGTH_MISMATCH;
282 pkt->u.response.stub_and_verifier.data +
283 pkt->u.response.stub_and_verifier.length - auth_blob.length;
284 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
286 /* pull the auth structure */
287 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
289 return NT_STATUS_NO_MEMORY;
292 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
293 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
296 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
297 if (!NT_STATUS_IS_OK(status)) {
302 /* check signature or unseal the packet */
303 switch (c->security_state.auth_info->auth_level) {
304 case DCERPC_AUTH_LEVEL_PRIVACY:
305 status = gensec_unseal_packet(c->security_state.generic_state,
307 blob->data + DCERPC_REQUEST_LENGTH,
308 pkt->u.response.stub_and_verifier.length,
310 blob->length - auth.credentials.length,
312 memcpy(pkt->u.response.stub_and_verifier.data,
313 blob->data + DCERPC_REQUEST_LENGTH,
314 pkt->u.response.stub_and_verifier.length);
317 case DCERPC_AUTH_LEVEL_INTEGRITY:
318 status = gensec_check_packet(c->security_state.generic_state,
320 pkt->u.response.stub_and_verifier.data,
321 pkt->u.response.stub_and_verifier.length,
323 blob->length - auth.credentials.length,
327 case DCERPC_AUTH_LEVEL_CONNECT:
328 status = dcerpc_check_connect_verifier(&auth.credentials);
331 case DCERPC_AUTH_LEVEL_NONE:
335 status = NT_STATUS_INVALID_LEVEL;
339 /* remove the indicated amount of paddiing */
340 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
341 return NT_STATUS_INFO_LENGTH_MISMATCH;
343 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
350 push a dcerpc request packet into a blob, possibly signing it.
352 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
353 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
354 struct ncacn_packet *pkt)
357 struct ndr_push *ndr;
360 /* non-signed packets are simpler */
361 if (!c->security_state.auth_info ||
362 !c->security_state.generic_state) {
363 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
366 ndr = ndr_push_init_ctx(mem_ctx);
368 return NT_STATUS_NO_MEMORY;
371 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
372 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
375 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
376 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
379 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
380 if (!NT_STATUS_IS_OK(status)) {
384 /* pad to 16 byte multiple in the payload portion of the
385 packet. This matches what w2k3 does */
386 c->security_state.auth_info->auth_pad_length =
387 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
388 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
390 /* sign or seal the packet */
391 switch (c->security_state.auth_info->auth_level) {
392 case DCERPC_AUTH_LEVEL_PRIVACY:
393 case DCERPC_AUTH_LEVEL_INTEGRITY:
394 c->security_state.auth_info->credentials
395 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state));
396 data_blob_clear(&c->security_state.auth_info->credentials);
399 case DCERPC_AUTH_LEVEL_CONNECT:
400 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
403 case DCERPC_AUTH_LEVEL_NONE:
404 c->security_state.auth_info->credentials = data_blob(NULL, 0);
408 status = NT_STATUS_INVALID_LEVEL;
412 if (!NT_STATUS_IS_OK(status)) {
416 /* add the auth verifier */
417 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
418 if (!NT_STATUS_IS_OK(status)) {
422 /* extract the whole packet as a blob */
423 *blob = ndr_push_blob(ndr);
425 /* fill in the fragment length and auth_length, we can't fill
426 in these earlier as we don't know the signature length (it
427 could be variable length) */
428 dcerpc_set_frag_length(blob, blob->length);
429 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
431 /* sign or seal the packet */
432 switch (c->security_state.auth_info->auth_level) {
433 case DCERPC_AUTH_LEVEL_PRIVACY:
434 status = gensec_seal_packet(c->security_state.generic_state,
436 blob->data + DCERPC_REQUEST_LENGTH,
437 pkt->u.request.stub_and_verifier.length +
438 c->security_state.auth_info->auth_pad_length,
441 c->security_state.auth_info->credentials.length,
443 if (!NT_STATUS_IS_OK(status)) {
446 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
449 case DCERPC_AUTH_LEVEL_INTEGRITY:
450 status = gensec_sign_packet(c->security_state.generic_state,
452 blob->data + DCERPC_REQUEST_LENGTH,
453 pkt->u.request.stub_and_verifier.length +
454 c->security_state.auth_info->auth_pad_length,
457 c->security_state.auth_info->credentials.length,
459 if (!NT_STATUS_IS_OK(status)) {
462 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
465 case DCERPC_AUTH_LEVEL_CONNECT:
468 case DCERPC_AUTH_LEVEL_NONE:
469 c->security_state.auth_info->credentials = data_blob(NULL, 0);
473 status = NT_STATUS_INVALID_LEVEL;
477 data_blob_free(&c->security_state.auth_info->credentials);
484 fill in the fixed values in a dcerpc header
486 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
489 pkt->rpc_vers_minor = 0;
490 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
493 pkt->drep[0] = DCERPC_DREP_LE;
501 hold the state of pending full requests
503 struct full_request_state {
504 DATA_BLOB *reply_blob;
509 receive a reply to a full request
511 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob,
514 struct full_request_state *state = c->full_request_private;
516 if (!NT_STATUS_IS_OK(status)) {
517 state->status = status;
520 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
521 state->reply_blob = NULL;
525 handle timeouts of full dcerpc requests
527 static void dcerpc_full_timeout_handler(struct event_context *ev, struct timed_event *te,
528 struct timeval t, void *private)
530 struct full_request_state *state = talloc_get_type(private,
531 struct full_request_state);
532 state->status = NT_STATUS_IO_TIMEOUT;
536 perform a single pdu synchronous request - used for the bind code
537 this cannot be mixed with normal async requests
539 static NTSTATUS full_request(struct dcerpc_connection *c,
541 DATA_BLOB *request_blob,
542 DATA_BLOB *reply_blob)
544 struct full_request_state *state = talloc(mem_ctx, struct full_request_state);
548 return NT_STATUS_NO_MEMORY;
551 state->reply_blob = reply_blob;
552 state->status = NT_STATUS_OK;
554 c->transport.recv_data = full_request_recv;
555 c->full_request_private = state;
557 status = c->transport.send_request(c, request_blob, True);
558 if (!NT_STATUS_IS_OK(status)) {
562 event_add_timed(c->transport.event_context(c), state,
563 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
564 dcerpc_full_timeout_handler, state);
566 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
567 struct event_context *ctx = c->transport.event_context(c);
568 if (event_loop_once(ctx) != 0) {
569 return NT_STATUS_CONNECTION_DISCONNECTED;
573 return state->status;
577 map a bind nak reason to a NTSTATUS
579 static NTSTATUS dcerpc_map_reason(uint16_t reason)
582 case DCERPC_BIND_REASON_ASYNTAX:
583 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
585 return NT_STATUS_UNSUCCESSFUL;
590 perform a bind using the given syntax
592 the auth_info structure is updated with the reply authentication info
595 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
597 const struct dcerpc_syntax_id *syntax,
598 const struct dcerpc_syntax_id *transfer_syntax)
600 struct ncacn_packet pkt;
605 p->transfer_syntax = *transfer_syntax;
607 init_ncacn_hdr(p->conn, &pkt);
609 pkt.ptype = DCERPC_PKT_BIND;
610 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
611 pkt.call_id = p->conn->call_id;
614 pkt.u.bind.max_xmit_frag = 5840;
615 pkt.u.bind.max_recv_frag = 5840;
616 pkt.u.bind.assoc_group_id = 0;
617 pkt.u.bind.num_contexts = 1;
618 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
619 if (!pkt.u.bind.ctx_list) {
620 return NT_STATUS_NO_MEMORY;
622 pkt.u.bind.ctx_list[0].context_id = p->context_id;
623 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
624 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
625 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
626 pkt.u.bind.auth_info = data_blob(NULL, 0);
628 /* construct the NDR form of the packet */
629 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
630 if (!NT_STATUS_IS_OK(status)) {
634 /* send it on its way */
635 status = full_request(p->conn, mem_ctx, &blob, &blob);
636 if (!NT_STATUS_IS_OK(status)) {
640 /* unmarshall the NDR */
641 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
642 if (!NT_STATUS_IS_OK(status)) {
646 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
647 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
648 return dcerpc_map_reason(pkt.u.bind_nak.reject_reason);
651 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
652 pkt.u.bind_ack.num_results == 0 ||
653 pkt.u.bind_ack.ctx_list[0].result != 0) {
654 return NT_STATUS_UNSUCCESSFUL;
657 p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
658 p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
660 /* the bind_ack might contain a reply set of credentials */
661 if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
662 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
664 p->conn->security_state.auth_info,
665 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
672 perform a continued bind (and auth3)
674 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
677 struct ncacn_packet pkt;
681 init_ncacn_hdr(c, &pkt);
683 pkt.ptype = DCERPC_PKT_AUTH3;
684 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
685 pkt.call_id = next_call_id(c);
687 pkt.u.auth3._pad = 0;
688 pkt.u.auth3.auth_info = data_blob(NULL, 0);
690 /* construct the NDR form of the packet */
691 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
692 if (!NT_STATUS_IS_OK(status)) {
696 /* send it on its way */
697 status = c->transport.send_request(c, &blob, False);
698 if (!NT_STATUS_IS_OK(status)) {
706 /* perform a dcerpc bind, using the uuid as the key */
707 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
709 const char *uuid, uint_t version)
711 struct dcerpc_syntax_id syntax;
712 struct dcerpc_syntax_id transfer_syntax;
715 status = GUID_from_string(uuid, &syntax.uuid);
716 if (!NT_STATUS_IS_OK(status)) {
717 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
720 syntax.if_version = version;
722 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
723 if (!NT_STATUS_IS_OK(status)) {
726 transfer_syntax.if_version = NDR_GUID_VERSION;
728 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
732 process a fragment received from the transport layer during a
735 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
739 struct ncacn_packet pkt;
740 struct rpc_request *req;
743 if (!NT_STATUS_IS_OK(status)) {
744 /* all pending requests get the error */
747 req->state = RPC_REQUEST_DONE;
748 req->status = status;
749 DLIST_REMOVE(c->pending, req);
750 if (req->async.callback) {
751 req->async.callback(req);
759 status = ncacn_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
761 /* find the matching request. Notice we match before we check
762 the status. this is ok as a pending call_id can never be
764 for (req=c->pending;req;req=req->next) {
765 if (pkt.call_id == req->call_id) break;
769 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
773 if (!NT_STATUS_IS_OK(status)) {
774 req->status = status;
775 req->state = RPC_REQUEST_DONE;
776 DLIST_REMOVE(c->pending, req);
777 if (req->async.callback) {
778 req->async.callback(req);
783 if (pkt.ptype == DCERPC_PKT_FAULT) {
784 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
785 req->fault_code = pkt.u.fault.status;
786 req->status = NT_STATUS_NET_WRITE_FAULT;
787 req->state = RPC_REQUEST_DONE;
788 DLIST_REMOVE(c->pending, req);
789 if (req->async.callback) {
790 req->async.callback(req);
795 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
796 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
798 req->fault_code = DCERPC_FAULT_OTHER;
799 req->status = NT_STATUS_NET_WRITE_FAULT;
800 req->state = RPC_REQUEST_DONE;
801 DLIST_REMOVE(c->pending, req);
802 if (req->async.callback) {
803 req->async.callback(req);
808 length = pkt.u.response.stub_and_verifier.length;
811 req->payload.data = talloc_realloc(req,
814 req->payload.length + length);
815 if (!req->payload.data) {
816 req->status = NT_STATUS_NO_MEMORY;
817 req->state = RPC_REQUEST_DONE;
818 DLIST_REMOVE(c->pending, req);
819 if (req->async.callback) {
820 req->async.callback(req);
824 memcpy(req->payload.data+req->payload.length,
825 pkt.u.response.stub_and_verifier.data, length);
826 req->payload.length += length;
829 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
830 c->transport.send_read(c);
834 /* we've got the full payload */
835 req->state = RPC_REQUEST_DONE;
836 DLIST_REMOVE(c->pending, req);
838 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
839 req->flags |= DCERPC_PULL_BIGENDIAN;
841 req->flags &= ~DCERPC_PULL_BIGENDIAN;
844 if (req->async.callback) {
845 req->async.callback(req);
850 handle timeouts of individual dcerpc requests
852 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
853 struct timeval t, void *private)
855 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
857 if (req->state != RPC_REQUEST_PENDING) {
861 req->status = NT_STATUS_IO_TIMEOUT;
862 req->state = RPC_REQUEST_DONE;
863 DLIST_REMOVE(req->p->conn->pending, req);
864 if (req->async.callback) {
865 req->async.callback(req);
871 make sure requests are cleaned up
873 static int dcerpc_req_destructor(void *ptr)
875 struct rpc_request *req = ptr;
876 DLIST_REMOVE(req->p->conn->pending, req);
881 perform the send side of a async dcerpc request
883 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
884 const struct GUID *object,
886 DATA_BLOB *stub_data)
888 struct rpc_request *req;
889 struct ncacn_packet pkt;
891 uint32_t remaining, chunk_size;
892 BOOL first_packet = True;
894 p->conn->transport.recv_data = dcerpc_request_recv_data;
896 req = talloc(p, struct rpc_request);
902 req->call_id = next_call_id(p->conn);
903 req->status = NT_STATUS_OK;
904 req->state = RPC_REQUEST_PENDING;
905 req->payload = data_blob(NULL, 0);
908 req->async.callback = NULL;
910 init_ncacn_hdr(p->conn, &pkt);
912 remaining = stub_data->length;
914 /* we can write a full max_recv_frag size, minus the dcerpc
915 request header size */
916 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
918 pkt.ptype = DCERPC_PKT_REQUEST;
919 pkt.call_id = req->call_id;
922 pkt.u.request.alloc_hint = remaining;
923 pkt.u.request.context_id = p->context_id;
924 pkt.u.request.opnum = opnum;
927 pkt.u.request.object.object = *object;
928 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
929 chunk_size -= ndr_size_GUID(object,0);
932 DLIST_ADD(p->conn->pending, req);
934 /* we send a series of pdus without waiting for a reply */
935 while (remaining > 0 || first_packet) {
936 uint32_t chunk = MIN(chunk_size, remaining);
937 BOOL last_frag = False;
939 first_packet = False;
940 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
942 if (remaining == stub_data->length) {
943 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
945 if (chunk == remaining) {
946 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
950 pkt.u.request.stub_and_verifier.data = stub_data->data +
951 (stub_data->length - remaining);
952 pkt.u.request.stub_and_verifier.length = chunk;
954 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
955 if (!NT_STATUS_IS_OK(req->status)) {
956 req->state = RPC_REQUEST_DONE;
957 DLIST_REMOVE(p->conn->pending, req);
961 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
962 if (!NT_STATUS_IS_OK(req->status)) {
963 req->state = RPC_REQUEST_DONE;
964 DLIST_REMOVE(p->conn->pending, req);
971 if (p->request_timeout) {
972 event_add_timed(dcerpc_event_context(p), req,
973 timeval_current_ofs(p->request_timeout, 0),
974 dcerpc_timeout_handler, req);
977 talloc_set_destructor(req, dcerpc_req_destructor);
983 return the event context for a dcerpc pipe
984 used by callers who wish to operate asynchronously
986 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
988 return p->conn->transport.event_context(p->conn);
994 perform the receive side of a async dcerpc request
996 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
998 DATA_BLOB *stub_data)
1002 while (req->state == RPC_REQUEST_PENDING) {
1003 struct event_context *ctx = dcerpc_event_context(req->p);
1004 if (event_loop_once(ctx) != 0) {
1005 return NT_STATUS_CONNECTION_DISCONNECTED;
1008 *stub_data = req->payload;
1009 status = req->status;
1010 if (stub_data->data) {
1011 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1013 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1014 req->p->last_fault_code = req->fault_code;
1021 perform a full request/response pair on a dcerpc pipe
1023 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1024 struct GUID *object,
1026 TALLOC_CTX *mem_ctx,
1027 DATA_BLOB *stub_data_in,
1028 DATA_BLOB *stub_data_out)
1030 struct rpc_request *req;
1032 req = dcerpc_request_send(p, object, opnum, stub_data_in);
1034 return NT_STATUS_NO_MEMORY;
1037 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1042 this is a paranoid NDR validator. For every packet we push onto the wire
1043 we pull it back again, then push it again. Then we compare the raw NDR data
1044 for that to the NDR we initially generated. If they don't match then we know
1045 we must have a bug in either the pull or push side of our code
1047 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1048 TALLOC_CTX *mem_ctx,
1051 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1052 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1055 struct ndr_pull *pull;
1056 struct ndr_push *push;
1060 st = talloc_size(mem_ctx, struct_size);
1062 return NT_STATUS_NO_MEMORY;
1065 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1067 return NT_STATUS_NO_MEMORY;
1069 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1071 status = ndr_pull(pull, NDR_IN, st);
1072 if (!NT_STATUS_IS_OK(status)) {
1073 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1074 "failed input validation pull - %s",
1078 push = ndr_push_init_ctx(mem_ctx);
1080 return NT_STATUS_NO_MEMORY;
1083 status = ndr_push(push, NDR_IN, st);
1084 if (!NT_STATUS_IS_OK(status)) {
1085 return ndr_push_error(push, NDR_ERR_VALIDATE,
1086 "failed input validation push - %s",
1090 blob2 = ndr_push_blob(push);
1092 if (!data_blob_equal(&blob, &blob2)) {
1093 DEBUG(3,("original:\n"));
1094 dump_data(3, blob.data, blob.length);
1095 DEBUG(3,("secondary:\n"));
1096 dump_data(3, blob2.data, blob2.length);
1097 return ndr_push_error(push, NDR_ERR_VALIDATE,
1098 "failed input validation data - %s",
1102 return NT_STATUS_OK;
1106 this is a paranoid NDR input validator. For every packet we pull
1107 from the wire we push it back again then pull and push it
1108 again. Then we compare the raw NDR data for that to the NDR we
1109 initially generated. If they don't match then we know we must have a
1110 bug in either the pull or push side of our code
1112 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1113 TALLOC_CTX *mem_ctx,
1116 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1117 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1120 struct ndr_pull *pull;
1121 struct ndr_push *push;
1123 DATA_BLOB blob, blob2;
1125 st = talloc_size(mem_ctx, struct_size);
1127 return NT_STATUS_NO_MEMORY;
1129 memcpy(st, struct_ptr, struct_size);
1131 push = ndr_push_init_ctx(mem_ctx);
1133 return NT_STATUS_NO_MEMORY;
1136 status = ndr_push(push, NDR_OUT, struct_ptr);
1137 if (!NT_STATUS_IS_OK(status)) {
1138 return ndr_push_error(push, NDR_ERR_VALIDATE,
1139 "failed output validation push - %s",
1143 blob = ndr_push_blob(push);
1145 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1147 return NT_STATUS_NO_MEMORY;
1150 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1151 status = ndr_pull(pull, NDR_OUT, st);
1152 if (!NT_STATUS_IS_OK(status)) {
1153 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1154 "failed output validation pull - %s",
1158 push = ndr_push_init_ctx(mem_ctx);
1160 return NT_STATUS_NO_MEMORY;
1163 status = ndr_push(push, NDR_OUT, st);
1164 if (!NT_STATUS_IS_OK(status)) {
1165 return ndr_push_error(push, NDR_ERR_VALIDATE,
1166 "failed output validation push2 - %s",
1170 blob2 = ndr_push_blob(push);
1172 if (!data_blob_equal(&blob, &blob2)) {
1173 DEBUG(3,("original:\n"));
1174 dump_data(3, blob.data, blob.length);
1175 DEBUG(3,("secondary:\n"));
1176 dump_data(3, blob2.data, blob2.length);
1177 return ndr_push_error(push, NDR_ERR_VALIDATE,
1178 "failed output validation data - %s",
1182 return NT_STATUS_OK;
1187 send a rpc request given a dcerpc_call structure
1189 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1190 const struct GUID *object,
1191 const struct dcerpc_interface_table *table,
1193 TALLOC_CTX *mem_ctx,
1196 const struct dcerpc_interface_call *call;
1197 struct ndr_push *push;
1200 struct rpc_request *req;
1202 call = &table->calls[opnum];
1204 /* setup for a ndr_push_* call */
1205 push = ndr_push_init_ctx(mem_ctx);
1210 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1211 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1214 /* push the structure into a blob */
1215 status = call->ndr_push(push, NDR_IN, r);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1218 nt_errstr(status)));
1223 /* retrieve the blob */
1224 request = ndr_push_blob(push);
1226 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1227 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1228 call->ndr_push, call->ndr_pull);
1229 if (!NT_STATUS_IS_OK(status)) {
1230 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1231 nt_errstr(status)));
1237 DEBUG(10,("rpc request data:\n"));
1238 dump_data(10, request.data, request.length);
1240 /* make the actual dcerpc request */
1241 req = dcerpc_request_send(p, object, opnum, &request);
1244 req->ndr.table = table;
1245 req->ndr.opnum = opnum;
1246 req->ndr.struct_ptr = r;
1247 req->ndr.mem_ctx = mem_ctx;
1256 receive the answer from a dcerpc_ndr_request_send()
1258 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1260 struct dcerpc_pipe *p = req->p;
1263 struct ndr_pull *pull;
1265 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1266 void *r = req->ndr.struct_ptr;
1267 uint32_t opnum = req->ndr.opnum;
1268 const struct dcerpc_interface_table *table = req->ndr.table;
1269 const struct dcerpc_interface_call *call = &table->calls[opnum];
1271 /* make sure the recv code doesn't free the request, as we
1272 need to grab the flags element before it is freed */
1273 talloc_increase_ref_count(req);
1275 status = dcerpc_request_recv(req, mem_ctx, &response);
1276 if (!NT_STATUS_IS_OK(status)) {
1282 /* prepare for ndr_pull_* */
1283 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1286 return NT_STATUS_NO_MEMORY;
1290 pull->data = talloc_steal(pull, pull->data);
1294 if (flags & DCERPC_PULL_BIGENDIAN) {
1295 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1298 DEBUG(10,("rpc reply data:\n"));
1299 dump_data(10, pull->data, pull->data_size);
1301 /* pull the structure from the blob */
1302 status = call->ndr_pull(pull, NDR_OUT, r);
1303 if (!NT_STATUS_IS_OK(status)) {
1304 dcerpc_log_packet(table, opnum, NDR_OUT,
1309 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1310 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1311 call->ndr_push, call->ndr_pull);
1312 if (!NT_STATUS_IS_OK(status)) {
1313 dcerpc_log_packet(table, opnum, NDR_OUT,
1319 if (pull->offset != pull->data_size) {
1320 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1321 pull->data_size - pull->offset));
1322 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1323 but it turns out that early versions of NT
1324 (specifically NT3.1) add junk onto the end of rpc
1325 packets, so if we want to interoperate at all with
1326 those versions then we need to ignore this error */
1329 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1331 return NT_STATUS_OK;
1336 a useful helper function for synchronous rpc requests
1338 this can be used when you have ndr push/pull functions in the
1341 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1342 const struct GUID *object,
1343 const struct dcerpc_interface_table *table,
1345 TALLOC_CTX *mem_ctx,
1348 struct rpc_request *req;
1350 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1352 return NT_STATUS_NO_MEMORY;
1355 return dcerpc_ndr_request_recv(req);
1360 a useful function for retrieving the server name we connected to
1362 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1364 if (!p->conn->transport.peer_name) {
1367 return p->conn->transport.peer_name(p->conn);
1372 get the dcerpc auth_level for a open connection
1374 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1378 if (c->flags & DCERPC_SEAL) {
1379 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1380 } else if (c->flags & DCERPC_SIGN) {
1381 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1382 } else if (c->flags & DCERPC_CONNECT) {
1383 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1385 auth_level = DCERPC_AUTH_LEVEL_NONE;
1392 send a dcerpc alter_context request
1394 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1395 TALLOC_CTX *mem_ctx,
1396 const struct dcerpc_syntax_id *syntax,
1397 const struct dcerpc_syntax_id *transfer_syntax)
1399 struct ncacn_packet pkt;
1403 p->syntax = *syntax;
1404 p->transfer_syntax = *transfer_syntax;
1406 init_ncacn_hdr(p->conn, &pkt);
1408 pkt.ptype = DCERPC_PKT_ALTER;
1409 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1410 pkt.call_id = p->conn->call_id;
1411 pkt.auth_length = 0;
1413 pkt.u.alter.max_xmit_frag = 5840;
1414 pkt.u.alter.max_recv_frag = 5840;
1415 pkt.u.alter.assoc_group_id = 0;
1416 pkt.u.alter.num_contexts = 1;
1417 pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1418 if (!pkt.u.alter.ctx_list) {
1419 return NT_STATUS_NO_MEMORY;
1421 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1422 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1423 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1424 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1425 pkt.u.alter.auth_info = data_blob(NULL, 0);
1427 /* construct the NDR form of the packet */
1428 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1429 if (!NT_STATUS_IS_OK(status)) {
1433 /* send it on its way */
1434 status = full_request(p->conn, mem_ctx, &blob, &blob);
1435 if (!NT_STATUS_IS_OK(status)) {
1439 /* unmarshall the NDR */
1440 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
1441 if (!NT_STATUS_IS_OK(status)) {
1445 if (pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1446 pkt.u.alter_resp.num_results == 1 &&
1447 pkt.u.alter_resp.ctx_list[0].result != 0) {
1448 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1449 pkt.u.alter_resp.ctx_list[0].reason));
1450 return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason);
1453 if (pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1454 pkt.u.alter_resp.num_results == 0 ||
1455 pkt.u.alter_resp.ctx_list[0].result != 0) {
1456 return NT_STATUS_UNSUCCESSFUL;
1459 /* the alter_resp might contain a reply set of credentials */
1460 if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) {
1461 status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info,
1463 p->conn->security_state.auth_info,
1464 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);