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"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "libcli/composite/composite.h"
32 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
34 static struct dcerpc_interface_list *dcerpc_pipes = NULL;
37 register a dcerpc client interface
39 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
41 struct dcerpc_interface_list *l = talloc(talloc_autofree_context(),
42 struct dcerpc_interface_list);
44 if (idl_iface_by_name (interface->name) != NULL) {
45 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
46 return NT_STATUS_OBJECT_NAME_COLLISION;
50 DLIST_ADD(dcerpc_pipes, l);
56 return the list of registered dcerpc_pipes
58 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
63 /* destroy a dcerpc connection */
64 static int dcerpc_connection_destructor(void *ptr)
66 struct dcerpc_connection *c = ptr;
67 if (c->transport.shutdown_pipe) {
68 c->transport.shutdown_pipe(c);
74 /* initialise a dcerpc connection.
75 the event context is optional
77 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
78 struct event_context *ev)
80 struct dcerpc_connection *c;
82 c = talloc_zero(mem_ctx, struct dcerpc_connection);
88 ev = event_context_init(c);
97 c->security_state.auth_info = NULL;
98 c->security_state.session_key = dcerpc_generic_session_key;
99 c->security_state.generic_state = NULL;
100 c->binding_string = NULL;
102 c->srv_max_xmit_frag = 0;
103 c->srv_max_recv_frag = 0;
106 talloc_set_destructor(c, dcerpc_connection_destructor);
111 /* initialise a dcerpc pipe. */
112 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
114 struct dcerpc_pipe *p;
116 p = talloc(mem_ctx, struct dcerpc_pipe);
121 p->conn = dcerpc_connection_init(p, ev);
122 if (p->conn == NULL) {
127 p->last_fault_code = 0;
129 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
131 ZERO_STRUCT(p->syntax);
132 ZERO_STRUCT(p->transfer_syntax);
139 choose the next call id to use
141 static uint32_t next_call_id(struct dcerpc_connection *c)
144 if (c->call_id == 0) {
150 /* we need to be able to get/set the fragment length without doing a full
152 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
154 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
155 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
157 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
161 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
163 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
164 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
166 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
170 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
172 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
173 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
175 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
181 setup for a ndr pull, also setting up any flags from the binding string
183 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
184 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
186 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
188 if (ndr == NULL) return ndr;
190 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
191 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
194 if (c->flags & DCERPC_NDR_REF_ALLOC) {
195 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
202 parse a data blob into a ncacn_packet structure. This handles both
203 input and output packets
205 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
206 struct ncacn_packet *pkt)
208 struct ndr_pull *ndr;
210 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
212 return NT_STATUS_NO_MEMORY;
215 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
216 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
219 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
223 generate a CONNECT level verifier
225 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
227 *blob = data_blob_talloc(mem_ctx, NULL, 16);
228 if (blob->data == NULL) {
229 return NT_STATUS_NO_MEMORY;
231 SIVAL(blob->data, 0, 1);
232 memset(blob->data+4, 0, 12);
237 check a CONNECT level verifier
239 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
241 if (blob->length != 16 ||
242 IVAL(blob->data, 0) != 1) {
243 return NT_STATUS_ACCESS_DENIED;
249 parse the authentication information on a dcerpc response packet
251 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
252 DATA_BLOB *raw_packet,
253 struct ncacn_packet *pkt)
255 struct ndr_pull *ndr;
257 struct dcerpc_auth auth;
260 if (pkt->auth_length == 0 &&
261 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
265 auth_blob.length = 8 + pkt->auth_length;
267 /* check for a valid length */
268 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
269 return NT_STATUS_INFO_LENGTH_MISMATCH;
273 pkt->u.response.stub_and_verifier.data +
274 pkt->u.response.stub_and_verifier.length - auth_blob.length;
275 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
277 /* pull the auth structure */
278 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
280 return NT_STATUS_NO_MEMORY;
283 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
284 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
287 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
288 if (!NT_STATUS_IS_OK(status)) {
293 /* check signature or unseal the packet */
294 switch (c->security_state.auth_info->auth_level) {
295 case DCERPC_AUTH_LEVEL_PRIVACY:
296 status = gensec_unseal_packet(c->security_state.generic_state,
298 raw_packet->data + DCERPC_REQUEST_LENGTH,
299 pkt->u.response.stub_and_verifier.length,
301 raw_packet->length - auth.credentials.length,
303 memcpy(pkt->u.response.stub_and_verifier.data,
304 raw_packet->data + DCERPC_REQUEST_LENGTH,
305 pkt->u.response.stub_and_verifier.length);
308 case DCERPC_AUTH_LEVEL_INTEGRITY:
309 status = gensec_check_packet(c->security_state.generic_state,
311 pkt->u.response.stub_and_verifier.data,
312 pkt->u.response.stub_and_verifier.length,
314 raw_packet->length - auth.credentials.length,
318 case DCERPC_AUTH_LEVEL_CONNECT:
319 status = dcerpc_check_connect_verifier(&auth.credentials);
322 case DCERPC_AUTH_LEVEL_NONE:
326 status = NT_STATUS_INVALID_LEVEL;
330 /* remove the indicated amount of paddiing */
331 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
332 return NT_STATUS_INFO_LENGTH_MISMATCH;
334 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
341 push a dcerpc request packet into a blob, possibly signing it.
343 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
344 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
345 struct ncacn_packet *pkt)
348 struct ndr_push *ndr;
350 size_t payload_length;
352 /* non-signed packets are simpler */
353 if (!c->security_state.auth_info ||
354 !c->security_state.generic_state) {
355 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
358 ndr = ndr_push_init_ctx(mem_ctx);
360 return NT_STATUS_NO_MEMORY;
363 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
364 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
367 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
368 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
371 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
372 if (!NT_STATUS_IS_OK(status)) {
376 /* pad to 16 byte multiple in the payload portion of the
377 packet. This matches what w2k3 does */
378 c->security_state.auth_info->auth_pad_length =
379 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
380 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
382 payload_length = pkt->u.request.stub_and_verifier.length +
383 c->security_state.auth_info->auth_pad_length;
385 /* sign or seal the packet */
386 switch (c->security_state.auth_info->auth_level) {
387 case DCERPC_AUTH_LEVEL_PRIVACY:
388 case DCERPC_AUTH_LEVEL_INTEGRITY:
389 c->security_state.auth_info->credentials
390 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
392 data_blob_clear(&c->security_state.auth_info->credentials);
395 case DCERPC_AUTH_LEVEL_CONNECT:
396 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
399 case DCERPC_AUTH_LEVEL_NONE:
400 c->security_state.auth_info->credentials = data_blob(NULL, 0);
404 status = NT_STATUS_INVALID_LEVEL;
408 if (!NT_STATUS_IS_OK(status)) {
412 /* add the auth verifier */
413 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
414 if (!NT_STATUS_IS_OK(status)) {
418 /* extract the whole packet as a blob */
419 *blob = ndr_push_blob(ndr);
421 /* fill in the fragment length and auth_length, we can't fill
422 in these earlier as we don't know the signature length (it
423 could be variable length) */
424 dcerpc_set_frag_length(blob, blob->length);
425 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
427 /* sign or seal the packet */
428 switch (c->security_state.auth_info->auth_level) {
429 case DCERPC_AUTH_LEVEL_PRIVACY:
430 status = gensec_seal_packet(c->security_state.generic_state,
432 blob->data + DCERPC_REQUEST_LENGTH,
436 c->security_state.auth_info->credentials.length,
438 if (!NT_STATUS_IS_OK(status)) {
441 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
444 case DCERPC_AUTH_LEVEL_INTEGRITY:
445 status = gensec_sign_packet(c->security_state.generic_state,
447 blob->data + DCERPC_REQUEST_LENGTH,
451 c->security_state.auth_info->credentials.length,
453 if (!NT_STATUS_IS_OK(status)) {
456 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
459 case DCERPC_AUTH_LEVEL_CONNECT:
462 case DCERPC_AUTH_LEVEL_NONE:
463 c->security_state.auth_info->credentials = data_blob(NULL, 0);
467 status = NT_STATUS_INVALID_LEVEL;
471 data_blob_free(&c->security_state.auth_info->credentials);
478 fill in the fixed values in a dcerpc header
480 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
483 pkt->rpc_vers_minor = 0;
484 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
487 pkt->drep[0] = DCERPC_DREP_LE;
495 map a bind nak reason to a NTSTATUS
497 static NTSTATUS dcerpc_map_reason(uint16_t reason)
500 case DCERPC_BIND_REASON_ASYNTAX:
501 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
503 return NT_STATUS_UNSUCCESSFUL;
507 mark the dcerpc connection dead. All outstanding requests get an error
509 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
511 /* all pending requests get the error */
512 while (conn->pending) {
513 struct rpc_request *req = conn->pending;
514 req->state = RPC_REQUEST_DONE;
515 req->status = status;
516 DLIST_REMOVE(conn->pending, req);
517 if (req->async.callback) {
518 req->async.callback(req);
522 if (conn->bind_private) {
523 /* a bind was in flight - fail it */
524 struct composite_context *c = talloc_get_type(conn->bind_private, struct composite_context);
525 composite_error(c, status);
528 if (conn->alter_private) {
529 /* a alter context was in flight - fail it */
530 struct composite_context *c = talloc_get_type(conn->alter_private, struct composite_context);
531 composite_error(c, status);
536 forward declarations of the recv_data handlers for the 3 types of packets we need
539 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
540 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt);
541 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
542 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
545 receive a dcerpc reply from the transport. Here we work out what
546 type of reply it is (normal request, bind or alter context) and
547 dispatch to the appropriate handler
549 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
551 struct ncacn_packet pkt;
553 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
554 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
557 /* the transport may be telling us of a severe error, such as
559 if (!NT_STATUS_IS_OK(status)) {
560 data_blob_free(blob);
561 dcerpc_connection_dead(conn, status);
565 /* parse the basic packet to work out what type of response this is */
566 status = ncacn_pull(conn, blob, blob->data, &pkt);
567 if (!NT_STATUS_IS_OK(status)) {
568 data_blob_free(blob);
569 dcerpc_connection_dead(conn, status);
573 case DCERPC_PKT_BIND_NAK:
574 case DCERPC_PKT_BIND_ACK:
575 if (conn->bind_private) {
576 talloc_steal(conn->bind_private, blob->data);
577 dcerpc_bind_recv_data(conn, &pkt);
581 case DCERPC_PKT_ALTER_RESP:
582 if (conn->alter_private) {
583 talloc_steal(conn->alter_private, blob->data);
584 dcerpc_alter_recv_data(conn, &pkt);
589 /* assume its an ordinary request */
590 dcerpc_request_recv_data(conn, blob, &pkt);
597 Receive a bind reply from the transport
599 static void dcerpc_bind_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
601 struct composite_context *c;
602 struct dcerpc_pipe *pipe;
604 c = talloc_get_type(conn->bind_private, struct composite_context);
605 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
607 /* mark the connection as not waiting for a bind reply */
608 conn->bind_private = NULL;
610 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
611 DEBUG(2,("dcerpc: bind_nak reason %d\n",
612 pkt->u.bind_nak.reject_reason));
613 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
618 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
619 (pkt->u.bind_ack.num_results == 0) ||
620 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
621 composite_error(c, NT_STATUS_UNSUCCESSFUL);
625 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
626 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
628 /* the bind_ack might contain a reply set of credentials */
629 if (conn->security_state.auth_info &&
630 pkt->u.bind_ack.auth_info.length) {
631 c->status = ndr_pull_struct_blob(
632 &pkt->u.bind_ack.auth_info, conn,
633 conn->security_state.auth_info,
634 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
635 if (!composite_is_ok(c)) return;
642 handle timeouts of dcerpc bind and alter context requests
644 static void bind_timeout_handler(struct event_context *ev,
645 struct timed_event *te,
646 struct timeval t, void *private)
648 struct composite_context *ctx =
649 talloc_get_type(private, struct composite_context);
650 struct dcerpc_pipe *pipe = talloc_get_type(ctx->private_data, struct dcerpc_pipe);
652 SMB_ASSERT(pipe->conn->bind_private != NULL);
653 pipe->conn->bind_private = NULL;
654 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
658 send a async dcerpc bind request
660 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
662 const struct dcerpc_syntax_id *syntax,
663 const struct dcerpc_syntax_id *transfer_syntax)
665 struct composite_context *c;
666 struct ncacn_packet pkt;
669 c = talloc_zero(mem_ctx, struct composite_context);
670 if (c == NULL) return NULL;
672 c->state = COMPOSITE_STATE_IN_PROGRESS;
674 c->event_ctx = p->conn->event_ctx;
677 p->transfer_syntax = *transfer_syntax;
679 init_ncacn_hdr(p->conn, &pkt);
681 pkt.ptype = DCERPC_PKT_BIND;
682 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
683 pkt.call_id = p->conn->call_id;
686 pkt.u.bind.max_xmit_frag = 5840;
687 pkt.u.bind.max_recv_frag = 5840;
688 pkt.u.bind.assoc_group_id = 0;
689 pkt.u.bind.num_contexts = 1;
690 pkt.u.bind.ctx_list =
691 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
692 if (pkt.u.bind.ctx_list == NULL) {
693 c->status = NT_STATUS_NO_MEMORY;
696 pkt.u.bind.ctx_list[0].context_id = p->context_id;
697 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
698 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
699 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
700 pkt.u.bind.auth_info = data_blob(NULL, 0);
702 /* construct the NDR form of the packet */
703 c->status = ncacn_push_auth(&blob, c, &pkt,
704 p->conn->security_state.auth_info);
705 if (!NT_STATUS_IS_OK(c->status)) {
709 p->conn->transport.recv_data = dcerpc_recv_data;
710 p->conn->bind_private = c;
712 c->status = p->conn->transport.send_request(p->conn, &blob,
714 if (!NT_STATUS_IS_OK(c->status)) {
718 event_add_timed(c->event_ctx, c,
719 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
720 bind_timeout_handler, c);
725 composite_error(c, c->status);
730 recv side of async dcerpc bind request
732 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
734 NTSTATUS result = composite_wait(ctx);
740 perform a bind using the given syntax
742 the auth_info structure is updated with the reply authentication info
745 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
747 const struct dcerpc_syntax_id *syntax,
748 const struct dcerpc_syntax_id *transfer_syntax)
750 struct composite_context *creq;
751 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
752 return dcerpc_bind_recv(creq);
756 perform a continued bind (and auth3)
758 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
761 struct ncacn_packet pkt;
765 init_ncacn_hdr(c, &pkt);
767 pkt.ptype = DCERPC_PKT_AUTH3;
768 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
769 pkt.call_id = next_call_id(c);
771 pkt.u.auth3._pad = 0;
772 pkt.u.auth3.auth_info = data_blob(NULL, 0);
774 /* construct the NDR form of the packet */
775 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
776 if (!NT_STATUS_IS_OK(status)) {
780 /* send it on its way */
781 status = c->transport.send_request(c, &blob, False);
782 if (!NT_STATUS_IS_OK(status)) {
791 return the rpc syntax and transfer syntax given the pipe uuid and version
793 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
794 struct dcerpc_syntax_id *syntax,
795 struct dcerpc_syntax_id *transfer_syntax)
799 syntax->uuid = table->uuid;
800 syntax->if_version = table->if_version;
802 status = GUID_from_string(NDR_GUID, &transfer_syntax->uuid);
803 if (!NT_STATUS_IS_OK(status)) return status;
805 transfer_syntax->if_version = NDR_GUID_VERSION;
810 /* perform a dcerpc bind, using the uuid as the key */
811 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
813 const struct dcerpc_interface_table *table)
815 struct dcerpc_syntax_id syntax;
816 struct dcerpc_syntax_id transfer_syntax;
819 status = dcerpc_init_syntaxes(table,
820 &syntax, &transfer_syntax);
821 if (!NT_STATUS_IS_OK(status)) {
822 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
826 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
831 process a fragment received from the transport layer during a
834 This function frees the data
836 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
837 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
839 struct rpc_request *req;
841 NTSTATUS status = NT_STATUS_OK;
844 if this is an authenticated connection then parse and check
845 the auth info. We have to do this before finding the
846 matching packet, as the request structure might have been
847 removed due to a timeout, but if it has been we still need
848 to run the auth routines so that we don't get the sign/seal
849 info out of step with the server
851 if (c->security_state.auth_info && c->security_state.generic_state &&
852 pkt->ptype == DCERPC_PKT_RESPONSE) {
853 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
856 /* find the matching request */
857 for (req=c->pending;req;req=req->next) {
858 if (pkt->call_id == req->call_id) break;
862 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
863 data_blob_free(raw_packet);
867 talloc_steal(req, raw_packet->data);
869 if (pkt->ptype == DCERPC_PKT_FAULT) {
870 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
871 req->fault_code = pkt->u.fault.status;
872 req->status = NT_STATUS_NET_WRITE_FAULT;
876 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
877 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
879 req->fault_code = DCERPC_FAULT_OTHER;
880 req->status = NT_STATUS_NET_WRITE_FAULT;
884 /* now check the status from the auth routines, and if it failed then fail
885 this request accordingly */
886 if (!NT_STATUS_IS_OK(status)) {
887 req->status = status;
891 length = pkt->u.response.stub_and_verifier.length;
894 req->payload.data = talloc_realloc(req,
897 req->payload.length + length);
898 if (!req->payload.data) {
899 req->status = NT_STATUS_NO_MEMORY;
902 memcpy(req->payload.data+req->payload.length,
903 pkt->u.response.stub_and_verifier.data, length);
904 req->payload.length += length;
907 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
908 c->transport.send_read(c);
912 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
913 req->flags |= DCERPC_PULL_BIGENDIAN;
915 req->flags &= ~DCERPC_PULL_BIGENDIAN;
920 /* we've got the full payload */
921 req->state = RPC_REQUEST_DONE;
922 DLIST_REMOVE(c->pending, req);
924 if (c->request_queue != NULL) {
925 /* We have to look at shipping further requests before calling
926 * the async function, that one might close the pipe */
927 dcerpc_ship_next_request(c);
930 if (req->async.callback) {
931 req->async.callback(req);
936 handle timeouts of individual dcerpc requests
938 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
939 struct timeval t, void *private)
941 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
943 if (req->state != RPC_REQUEST_PENDING) {
947 req->status = NT_STATUS_IO_TIMEOUT;
948 req->state = RPC_REQUEST_DONE;
949 DLIST_REMOVE(req->p->conn->pending, req);
950 if (req->async.callback) {
951 req->async.callback(req);
957 make sure requests are cleaned up
959 static int dcerpc_req_destructor(void *ptr)
961 struct rpc_request *req = ptr;
962 DLIST_REMOVE(req->p->conn->pending, req);
967 perform the send side of a async dcerpc request
969 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
970 const struct GUID *object,
973 DATA_BLOB *stub_data)
975 struct rpc_request *req;
977 p->conn->transport.recv_data = dcerpc_recv_data;
979 req = talloc(p, struct rpc_request);
985 req->call_id = next_call_id(p->conn);
986 req->status = NT_STATUS_OK;
987 req->state = RPC_REQUEST_PENDING;
988 req->payload = data_blob(NULL, 0);
991 req->async_call = async;
992 req->async.callback = NULL;
994 if (object != NULL) {
995 req->object = talloc_memdup(req, object, sizeof(*object));
996 if (req->object == NULL) {
1005 req->request_data.length = stub_data->length;
1006 req->request_data.data = talloc_reference(req, stub_data->data);
1007 if (req->request_data.data == NULL) {
1011 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1013 dcerpc_ship_next_request(p->conn);
1015 if (p->request_timeout) {
1016 event_add_timed(dcerpc_event_context(p), req,
1017 timeval_current_ofs(p->request_timeout, 0),
1018 dcerpc_timeout_handler, req);
1021 talloc_set_destructor(req, dcerpc_req_destructor);
1026 Send a request using the transport
1029 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1031 struct rpc_request *req;
1032 struct dcerpc_pipe *p;
1033 DATA_BLOB *stub_data;
1034 struct ncacn_packet pkt;
1036 uint32_t remaining, chunk_size;
1037 BOOL first_packet = True;
1039 req = c->request_queue;
1045 stub_data = &req->request_data;
1047 if (!req->async_call && (c->pending != NULL)) {
1051 DLIST_REMOVE(c->request_queue, req);
1052 DLIST_ADD(c->pending, req);
1054 init_ncacn_hdr(p->conn, &pkt);
1056 remaining = stub_data->length;
1058 /* we can write a full max_recv_frag size, minus the dcerpc
1059 request header size */
1060 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1062 pkt.ptype = DCERPC_PKT_REQUEST;
1063 pkt.call_id = req->call_id;
1064 pkt.auth_length = 0;
1066 pkt.u.request.alloc_hint = remaining;
1067 pkt.u.request.context_id = p->context_id;
1068 pkt.u.request.opnum = req->opnum;
1071 pkt.u.request.object.object = *req->object;
1072 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1073 chunk_size -= ndr_size_GUID(req->object,0);
1076 /* we send a series of pdus without waiting for a reply */
1077 while (remaining > 0 || first_packet) {
1078 uint32_t chunk = MIN(chunk_size, remaining);
1079 BOOL last_frag = False;
1081 first_packet = False;
1082 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1084 if (remaining == stub_data->length) {
1085 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1087 if (chunk == remaining) {
1088 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1092 pkt.u.request.stub_and_verifier.data = stub_data->data +
1093 (stub_data->length - remaining);
1094 pkt.u.request.stub_and_verifier.length = chunk;
1096 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1097 if (!NT_STATUS_IS_OK(req->status)) {
1098 req->state = RPC_REQUEST_DONE;
1099 DLIST_REMOVE(p->conn->pending, req);
1103 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1104 if (!NT_STATUS_IS_OK(req->status)) {
1105 req->state = RPC_REQUEST_DONE;
1106 DLIST_REMOVE(p->conn->pending, req);
1115 return the event context for a dcerpc pipe
1116 used by callers who wish to operate asynchronously
1118 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1120 return p->conn->event_ctx;
1126 perform the receive side of a async dcerpc request
1128 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1129 TALLOC_CTX *mem_ctx,
1130 DATA_BLOB *stub_data)
1134 while (req->state == RPC_REQUEST_PENDING) {
1135 struct event_context *ctx = dcerpc_event_context(req->p);
1136 if (event_loop_once(ctx) != 0) {
1137 return NT_STATUS_CONNECTION_DISCONNECTED;
1140 *stub_data = req->payload;
1141 status = req->status;
1142 if (stub_data->data) {
1143 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1145 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1146 req->p->last_fault_code = req->fault_code;
1153 perform a full request/response pair on a dcerpc pipe
1155 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1156 struct GUID *object,
1159 TALLOC_CTX *mem_ctx,
1160 DATA_BLOB *stub_data_in,
1161 DATA_BLOB *stub_data_out)
1163 struct rpc_request *req;
1165 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1167 return NT_STATUS_NO_MEMORY;
1170 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1175 this is a paranoid NDR validator. For every packet we push onto the wire
1176 we pull it back again, then push it again. Then we compare the raw NDR data
1177 for that to the NDR we initially generated. If they don't match then we know
1178 we must have a bug in either the pull or push side of our code
1180 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1181 TALLOC_CTX *mem_ctx,
1184 ndr_push_flags_fn_t ndr_push,
1185 ndr_pull_flags_fn_t ndr_pull)
1188 struct ndr_pull *pull;
1189 struct ndr_push *push;
1193 st = talloc_size(mem_ctx, struct_size);
1195 return NT_STATUS_NO_MEMORY;
1198 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1200 return NT_STATUS_NO_MEMORY;
1202 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1204 status = ndr_pull(pull, NDR_IN, st);
1205 if (!NT_STATUS_IS_OK(status)) {
1206 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1207 "failed input validation pull - %s",
1211 push = ndr_push_init_ctx(mem_ctx);
1213 return NT_STATUS_NO_MEMORY;
1216 status = ndr_push(push, NDR_IN, st);
1217 if (!NT_STATUS_IS_OK(status)) {
1218 return ndr_push_error(push, NDR_ERR_VALIDATE,
1219 "failed input validation push - %s",
1223 blob2 = ndr_push_blob(push);
1225 if (!data_blob_equal(&blob, &blob2)) {
1226 DEBUG(3,("original:\n"));
1227 dump_data(3, blob.data, blob.length);
1228 DEBUG(3,("secondary:\n"));
1229 dump_data(3, blob2.data, blob2.length);
1230 return ndr_push_error(push, NDR_ERR_VALIDATE,
1231 "failed input validation data - %s",
1235 return NT_STATUS_OK;
1239 this is a paranoid NDR input validator. For every packet we pull
1240 from the wire we push it back again then pull and push it
1241 again. Then we compare the raw NDR data for that to the NDR we
1242 initially generated. If they don't match then we know we must have a
1243 bug in either the pull or push side of our code
1245 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1246 TALLOC_CTX *mem_ctx,
1249 ndr_push_flags_fn_t ndr_push,
1250 ndr_pull_flags_fn_t ndr_pull)
1253 struct ndr_pull *pull;
1254 struct ndr_push *push;
1256 DATA_BLOB blob, blob2;
1258 st = talloc_size(mem_ctx, struct_size);
1260 return NT_STATUS_NO_MEMORY;
1262 memcpy(st, struct_ptr, struct_size);
1264 push = ndr_push_init_ctx(mem_ctx);
1266 return NT_STATUS_NO_MEMORY;
1269 status = ndr_push(push, NDR_OUT, struct_ptr);
1270 if (!NT_STATUS_IS_OK(status)) {
1271 return ndr_push_error(push, NDR_ERR_VALIDATE,
1272 "failed output validation push - %s",
1276 blob = ndr_push_blob(push);
1278 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1280 return NT_STATUS_NO_MEMORY;
1283 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1284 status = ndr_pull(pull, NDR_OUT, st);
1285 if (!NT_STATUS_IS_OK(status)) {
1286 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1287 "failed output validation pull - %s",
1291 push = ndr_push_init_ctx(mem_ctx);
1293 return NT_STATUS_NO_MEMORY;
1296 status = ndr_push(push, NDR_OUT, st);
1297 if (!NT_STATUS_IS_OK(status)) {
1298 return ndr_push_error(push, NDR_ERR_VALIDATE,
1299 "failed output validation push2 - %s",
1303 blob2 = ndr_push_blob(push);
1305 if (!data_blob_equal(&blob, &blob2)) {
1306 DEBUG(3,("original:\n"));
1307 dump_data(3, blob.data, blob.length);
1308 DEBUG(3,("secondary:\n"));
1309 dump_data(3, blob2.data, blob2.length);
1310 return ndr_push_error(push, NDR_ERR_VALIDATE,
1311 "failed output validation data - %s",
1315 return NT_STATUS_OK;
1320 send a rpc request given a dcerpc_call structure
1322 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1323 const struct GUID *object,
1324 const struct dcerpc_interface_table *table,
1326 TALLOC_CTX *mem_ctx,
1329 const struct dcerpc_interface_call *call;
1330 struct ndr_push *push;
1333 struct rpc_request *req;
1335 call = &table->calls[opnum];
1337 /* setup for a ndr_push_* call */
1338 push = ndr_push_init_ctx(mem_ctx);
1343 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1344 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1347 /* push the structure into a blob */
1348 status = call->ndr_push(push, NDR_IN, r);
1349 if (!NT_STATUS_IS_OK(status)) {
1350 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1351 nt_errstr(status)));
1356 /* retrieve the blob */
1357 request = ndr_push_blob(push);
1359 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1360 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1361 call->ndr_push, call->ndr_pull);
1362 if (!NT_STATUS_IS_OK(status)) {
1363 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1364 nt_errstr(status)));
1370 DEBUG(10,("rpc request data:\n"));
1371 dump_data(10, request.data, request.length);
1373 /* make the actual dcerpc request */
1374 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1378 req->ndr.table = table;
1379 req->ndr.opnum = opnum;
1380 req->ndr.struct_ptr = r;
1381 req->ndr.mem_ctx = mem_ctx;
1390 receive the answer from a dcerpc_ndr_request_send()
1392 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1394 struct dcerpc_pipe *p = req->p;
1397 struct ndr_pull *pull;
1399 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1400 void *r = req->ndr.struct_ptr;
1401 uint32_t opnum = req->ndr.opnum;
1402 const struct dcerpc_interface_table *table = req->ndr.table;
1403 const struct dcerpc_interface_call *call = &table->calls[opnum];
1405 /* make sure the recv code doesn't free the request, as we
1406 need to grab the flags element before it is freed */
1407 talloc_increase_ref_count(req);
1409 status = dcerpc_request_recv(req, mem_ctx, &response);
1410 if (!NT_STATUS_IS_OK(status)) {
1416 /* prepare for ndr_pull_* */
1417 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1420 return NT_STATUS_NO_MEMORY;
1424 pull->data = talloc_steal(pull, pull->data);
1428 if (flags & DCERPC_PULL_BIGENDIAN) {
1429 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1432 DEBUG(10,("rpc reply data:\n"));
1433 dump_data(10, pull->data, pull->data_size);
1435 /* pull the structure from the blob */
1436 status = call->ndr_pull(pull, NDR_OUT, r);
1437 if (!NT_STATUS_IS_OK(status)) {
1438 dcerpc_log_packet(table, opnum, NDR_OUT,
1443 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1444 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1445 call->ndr_push, call->ndr_pull);
1446 if (!NT_STATUS_IS_OK(status)) {
1447 dcerpc_log_packet(table, opnum, NDR_OUT,
1453 if (pull->offset != pull->data_size) {
1454 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1455 pull->data_size - pull->offset));
1456 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1457 but it turns out that early versions of NT
1458 (specifically NT3.1) add junk onto the end of rpc
1459 packets, so if we want to interoperate at all with
1460 those versions then we need to ignore this error */
1463 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1465 return NT_STATUS_OK;
1470 a useful helper function for synchronous rpc requests
1472 this can be used when you have ndr push/pull functions in the
1475 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1476 const struct GUID *object,
1477 const struct dcerpc_interface_table *table,
1479 TALLOC_CTX *mem_ctx,
1482 struct rpc_request *req;
1484 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1486 return NT_STATUS_NO_MEMORY;
1489 return dcerpc_ndr_request_recv(req);
1494 a useful function for retrieving the server name we connected to
1496 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1498 if (!p->conn->transport.peer_name) {
1501 return p->conn->transport.peer_name(p->conn);
1506 get the dcerpc auth_level for a open connection
1508 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1512 if (c->flags & DCERPC_SEAL) {
1513 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1514 } else if (c->flags & DCERPC_SIGN) {
1515 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1516 } else if (c->flags & DCERPC_CONNECT) {
1517 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1519 auth_level = DCERPC_AUTH_LEVEL_NONE;
1525 Receive an alter reply from the transport
1527 static void dcerpc_alter_recv_data(struct dcerpc_connection *conn, struct ncacn_packet *pkt)
1529 struct composite_context *c;
1530 struct dcerpc_pipe *pipe;
1532 c = talloc_get_type(conn->alter_private, struct composite_context);
1533 pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1535 /* mark the connection as not waiting for a alter context reply */
1536 conn->alter_private = NULL;
1538 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1539 pkt->u.alter_resp.num_results == 1 &&
1540 pkt->u.alter_resp.ctx_list[0].result != 0) {
1541 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1542 pkt->u.alter_resp.ctx_list[0].reason));
1543 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1547 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1548 pkt->u.alter_resp.num_results == 0 ||
1549 pkt->u.alter_resp.ctx_list[0].result != 0) {
1550 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1554 /* the alter_resp might contain a reply set of credentials */
1555 if (pipe->conn->security_state.auth_info &&
1556 pkt->u.alter_resp.auth_info.length) {
1557 c->status = ndr_pull_struct_blob(
1558 &pkt->u.alter_resp.auth_info, pipe,
1559 pipe->conn->security_state.auth_info,
1560 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1561 if (!composite_is_ok(c)) return;
1568 send a dcerpc alter_context request
1570 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1571 TALLOC_CTX *mem_ctx,
1572 const struct dcerpc_syntax_id *syntax,
1573 const struct dcerpc_syntax_id *transfer_syntax)
1575 struct composite_context *c;
1576 struct ncacn_packet pkt;
1579 c = talloc_zero(mem_ctx, struct composite_context);
1580 if (c == NULL) return NULL;
1582 c->state = COMPOSITE_STATE_IN_PROGRESS;
1583 c->private_data = p;
1584 c->event_ctx = p->conn->event_ctx;
1586 p->syntax = *syntax;
1587 p->transfer_syntax = *transfer_syntax;
1589 init_ncacn_hdr(p->conn, &pkt);
1591 pkt.ptype = DCERPC_PKT_ALTER;
1592 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1593 pkt.call_id = p->conn->call_id;
1594 pkt.auth_length = 0;
1596 pkt.u.alter.max_xmit_frag = 5840;
1597 pkt.u.alter.max_recv_frag = 5840;
1598 pkt.u.alter.assoc_group_id = 0;
1599 pkt.u.alter.num_contexts = 1;
1600 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1601 struct dcerpc_ctx_list, 1);
1602 if (pkt.u.alter.ctx_list == NULL) {
1603 c->status = NT_STATUS_NO_MEMORY;
1606 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1607 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1608 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1609 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1610 pkt.u.alter.auth_info = data_blob(NULL, 0);
1612 /* construct the NDR form of the packet */
1613 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1614 p->conn->security_state.auth_info);
1615 if (!NT_STATUS_IS_OK(c->status)) {
1619 p->conn->transport.recv_data = dcerpc_recv_data;
1620 p->conn->alter_private = c;
1622 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1623 if (!NT_STATUS_IS_OK(c->status)) {
1627 event_add_timed(c->event_ctx, c,
1628 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1629 bind_timeout_handler, c);
1634 composite_error(c, c->status);
1638 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1640 NTSTATUS result = composite_wait(ctx);
1646 send a dcerpc alter_context request
1648 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1649 TALLOC_CTX *mem_ctx,
1650 const struct dcerpc_syntax_id *syntax,
1651 const struct dcerpc_syntax_id *transfer_syntax)
1653 struct composite_context *creq;
1654 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1655 return dcerpc_alter_context_recv(creq);