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"
31 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
33 static struct dcerpc_interface_list *dcerpc_pipes = NULL;
36 register a dcerpc client interface
38 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
40 struct dcerpc_interface_list *l = talloc(talloc_autofree_context(),
41 struct dcerpc_interface_list);
43 if (idl_iface_by_name (interface->name) != NULL) {
44 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
45 return NT_STATUS_OBJECT_NAME_COLLISION;
49 DLIST_ADD(dcerpc_pipes, l);
55 return the list of registered dcerpc_pipes
57 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
62 /* destroy a dcerpc connection */
63 static int dcerpc_connection_destructor(void *ptr)
65 struct dcerpc_connection *c = ptr;
66 if (c->transport.shutdown_pipe) {
67 c->transport.shutdown_pipe(c);
73 /* initialise a dcerpc connection.
74 the event context is optional
76 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
77 struct event_context *ev)
79 struct dcerpc_connection *c;
81 c = talloc_zero(mem_ctx, struct dcerpc_connection);
87 ev = event_context_init(c);
96 c->security_state.auth_info = NULL;
97 c->security_state.session_key = dcerpc_generic_session_key;
98 c->security_state.generic_state = NULL;
99 c->binding_string = NULL;
101 c->srv_max_xmit_frag = 0;
102 c->srv_max_recv_frag = 0;
105 talloc_set_destructor(c, dcerpc_connection_destructor);
110 /* initialise a dcerpc pipe. */
111 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
113 struct dcerpc_pipe *p;
115 p = talloc(mem_ctx, struct dcerpc_pipe);
120 p->conn = dcerpc_connection_init(p, ev);
121 if (p->conn == NULL) {
126 p->last_fault_code = 0;
128 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
130 ZERO_STRUCT(p->syntax);
131 ZERO_STRUCT(p->transfer_syntax);
138 choose the next call id to use
140 static uint32_t next_call_id(struct dcerpc_connection *c)
143 if (c->call_id == 0) {
149 /* we need to be able to get/set the fragment length without doing a full
151 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
153 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
154 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
156 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
160 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
162 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
163 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
165 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
169 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
171 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
172 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
174 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
180 setup for a ndr pull, also setting up any flags from the binding string
182 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
183 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
185 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
187 if (ndr == NULL) return ndr;
189 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
190 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
193 if (c->flags & DCERPC_NDR_REF_ALLOC) {
194 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
201 parse a data blob into a ncacn_packet structure. This handles both
202 input and output packets
204 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
205 struct ncacn_packet *pkt)
207 struct ndr_pull *ndr;
209 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
211 return NT_STATUS_NO_MEMORY;
214 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
215 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
218 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
222 generate a CONNECT level verifier
224 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
226 *blob = data_blob_talloc(mem_ctx, NULL, 16);
227 if (blob->data == NULL) {
228 return NT_STATUS_NO_MEMORY;
230 SIVAL(blob->data, 0, 1);
231 memset(blob->data+4, 0, 12);
236 check a CONNECT level verifier
238 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
240 if (blob->length != 16 ||
241 IVAL(blob->data, 0) != 1) {
242 return NT_STATUS_ACCESS_DENIED;
248 parse a possibly signed blob into a dcerpc request packet structure
250 static NTSTATUS ncacn_pull_request_sign(struct dcerpc_connection *c,
251 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
252 struct ncacn_packet *pkt)
254 struct ndr_pull *ndr;
256 struct dcerpc_auth auth;
259 /* non-signed packets are simpler */
260 if (!c->security_state.auth_info ||
261 !c->security_state.generic_state) {
262 return ncacn_pull(c, blob, mem_ctx, pkt);
265 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
267 return NT_STATUS_NO_MEMORY;
270 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
271 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
274 /* pull the basic packet */
275 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
276 if (!NT_STATUS_IS_OK(status)) {
280 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
284 if (pkt->auth_length == 0 &&
285 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
289 auth_blob.length = 8 + pkt->auth_length;
291 /* check for a valid length */
292 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
293 return NT_STATUS_INFO_LENGTH_MISMATCH;
297 pkt->u.response.stub_and_verifier.data +
298 pkt->u.response.stub_and_verifier.length - auth_blob.length;
299 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
301 /* pull the auth structure */
302 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
304 return NT_STATUS_NO_MEMORY;
307 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
308 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
311 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
312 if (!NT_STATUS_IS_OK(status)) {
317 /* check signature or unseal the packet */
318 switch (c->security_state.auth_info->auth_level) {
319 case DCERPC_AUTH_LEVEL_PRIVACY:
320 status = gensec_unseal_packet(c->security_state.generic_state,
322 blob->data + DCERPC_REQUEST_LENGTH,
323 pkt->u.response.stub_and_verifier.length,
325 blob->length - auth.credentials.length,
327 memcpy(pkt->u.response.stub_and_verifier.data,
328 blob->data + DCERPC_REQUEST_LENGTH,
329 pkt->u.response.stub_and_verifier.length);
332 case DCERPC_AUTH_LEVEL_INTEGRITY:
333 status = gensec_check_packet(c->security_state.generic_state,
335 pkt->u.response.stub_and_verifier.data,
336 pkt->u.response.stub_and_verifier.length,
338 blob->length - auth.credentials.length,
342 case DCERPC_AUTH_LEVEL_CONNECT:
343 status = dcerpc_check_connect_verifier(&auth.credentials);
346 case DCERPC_AUTH_LEVEL_NONE:
350 status = NT_STATUS_INVALID_LEVEL;
354 /* remove the indicated amount of paddiing */
355 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
356 return NT_STATUS_INFO_LENGTH_MISMATCH;
358 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
365 push a dcerpc request packet into a blob, possibly signing it.
367 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
368 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
369 struct ncacn_packet *pkt)
372 struct ndr_push *ndr;
374 size_t payload_length;
376 /* non-signed packets are simpler */
377 if (!c->security_state.auth_info ||
378 !c->security_state.generic_state) {
379 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
382 ndr = ndr_push_init_ctx(mem_ctx);
384 return NT_STATUS_NO_MEMORY;
387 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
388 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
391 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
392 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
395 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
396 if (!NT_STATUS_IS_OK(status)) {
400 /* pad to 16 byte multiple in the payload portion of the
401 packet. This matches what w2k3 does */
402 c->security_state.auth_info->auth_pad_length =
403 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
404 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
406 payload_length = pkt->u.request.stub_and_verifier.length +
407 c->security_state.auth_info->auth_pad_length;
409 /* sign or seal the packet */
410 switch (c->security_state.auth_info->auth_level) {
411 case DCERPC_AUTH_LEVEL_PRIVACY:
412 case DCERPC_AUTH_LEVEL_INTEGRITY:
413 c->security_state.auth_info->credentials
414 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
416 data_blob_clear(&c->security_state.auth_info->credentials);
419 case DCERPC_AUTH_LEVEL_CONNECT:
420 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
423 case DCERPC_AUTH_LEVEL_NONE:
424 c->security_state.auth_info->credentials = data_blob(NULL, 0);
428 status = NT_STATUS_INVALID_LEVEL;
432 if (!NT_STATUS_IS_OK(status)) {
436 /* add the auth verifier */
437 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
438 if (!NT_STATUS_IS_OK(status)) {
442 /* extract the whole packet as a blob */
443 *blob = ndr_push_blob(ndr);
445 /* fill in the fragment length and auth_length, we can't fill
446 in these earlier as we don't know the signature length (it
447 could be variable length) */
448 dcerpc_set_frag_length(blob, blob->length);
449 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
451 /* sign or seal the packet */
452 switch (c->security_state.auth_info->auth_level) {
453 case DCERPC_AUTH_LEVEL_PRIVACY:
454 status = gensec_seal_packet(c->security_state.generic_state,
456 blob->data + DCERPC_REQUEST_LENGTH,
460 c->security_state.auth_info->credentials.length,
462 if (!NT_STATUS_IS_OK(status)) {
465 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
468 case DCERPC_AUTH_LEVEL_INTEGRITY:
469 status = gensec_sign_packet(c->security_state.generic_state,
471 blob->data + DCERPC_REQUEST_LENGTH,
475 c->security_state.auth_info->credentials.length,
477 if (!NT_STATUS_IS_OK(status)) {
480 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
483 case DCERPC_AUTH_LEVEL_CONNECT:
486 case DCERPC_AUTH_LEVEL_NONE:
487 c->security_state.auth_info->credentials = data_blob(NULL, 0);
491 status = NT_STATUS_INVALID_LEVEL;
495 data_blob_free(&c->security_state.auth_info->credentials);
502 fill in the fixed values in a dcerpc header
504 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
507 pkt->rpc_vers_minor = 0;
508 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
511 pkt->drep[0] = DCERPC_DREP_LE;
519 hold the state of pending full requests
521 struct full_request_state {
522 struct dcerpc_connection *c;
523 DATA_BLOB *reply_blob;
528 receive a reply to a full request
530 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob,
533 struct full_request_state *state = talloc_get_type(c->full_request_private,
534 struct full_request_state);
536 /* it timed out earlier */
540 if (!NT_STATUS_IS_OK(status)) {
541 state->status = status;
544 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
545 state->reply_blob = NULL;
549 handle timeouts of full dcerpc requests
551 static void dcerpc_full_timeout_handler(struct event_context *ev, struct timed_event *te,
552 struct timeval t, void *private)
554 struct full_request_state *state = talloc_get_type(private,
555 struct full_request_state);
556 state->status = NT_STATUS_IO_TIMEOUT;
557 state->c->full_request_private = NULL;
561 perform a single pdu synchronous request - used for the bind code
562 this cannot be mixed with normal async requests
564 static NTSTATUS full_request(struct dcerpc_connection *c,
566 DATA_BLOB *request_blob,
567 DATA_BLOB *reply_blob)
569 struct full_request_state *state = talloc(mem_ctx, struct full_request_state);
573 return NT_STATUS_NO_MEMORY;
576 state->reply_blob = reply_blob;
577 state->status = NT_STATUS_OK;
580 c->transport.recv_data = full_request_recv;
581 c->full_request_private = state;
583 status = c->transport.send_request(c, request_blob, True);
584 if (!NT_STATUS_IS_OK(status)) {
588 event_add_timed(c->event_ctx, state,
589 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
590 dcerpc_full_timeout_handler, state);
592 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
593 if (event_loop_once(c->event_ctx) != 0) {
594 return NT_STATUS_CONNECTION_DISCONNECTED;
598 c->full_request_private = NULL;
600 return state->status;
604 map a bind nak reason to a NTSTATUS
606 static NTSTATUS dcerpc_map_reason(uint16_t reason)
609 case DCERPC_BIND_REASON_ASYNTAX:
610 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
612 return NT_STATUS_UNSUCCESSFUL;
617 perform a bind using the given syntax
619 the auth_info structure is updated with the reply authentication info
622 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
624 const struct dcerpc_syntax_id *syntax,
625 const struct dcerpc_syntax_id *transfer_syntax)
627 struct ncacn_packet pkt;
632 p->transfer_syntax = *transfer_syntax;
634 init_ncacn_hdr(p->conn, &pkt);
636 pkt.ptype = DCERPC_PKT_BIND;
637 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
638 pkt.call_id = p->conn->call_id;
641 pkt.u.bind.max_xmit_frag = 5840;
642 pkt.u.bind.max_recv_frag = 5840;
643 pkt.u.bind.assoc_group_id = 0;
644 pkt.u.bind.num_contexts = 1;
645 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
646 if (!pkt.u.bind.ctx_list) {
647 return NT_STATUS_NO_MEMORY;
649 pkt.u.bind.ctx_list[0].context_id = p->context_id;
650 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
651 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
652 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
653 pkt.u.bind.auth_info = data_blob(NULL, 0);
655 /* construct the NDR form of the packet */
656 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
657 if (!NT_STATUS_IS_OK(status)) {
661 /* send it on its way */
662 status = full_request(p->conn, mem_ctx, &blob, &blob);
663 if (!NT_STATUS_IS_OK(status)) {
667 /* unmarshall the NDR */
668 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
669 if (!NT_STATUS_IS_OK(status)) {
673 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
674 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
675 return dcerpc_map_reason(pkt.u.bind_nak.reject_reason);
678 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
679 pkt.u.bind_ack.num_results == 0 ||
680 pkt.u.bind_ack.ctx_list[0].result != 0) {
681 return NT_STATUS_UNSUCCESSFUL;
684 p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
685 p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
687 /* the bind_ack might contain a reply set of credentials */
688 if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
689 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
691 p->conn->security_state.auth_info,
692 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
699 perform a continued bind (and auth3)
701 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
704 struct ncacn_packet pkt;
708 init_ncacn_hdr(c, &pkt);
710 pkt.ptype = DCERPC_PKT_AUTH3;
711 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
712 pkt.call_id = next_call_id(c);
714 pkt.u.auth3._pad = 0;
715 pkt.u.auth3.auth_info = data_blob(NULL, 0);
717 /* construct the NDR form of the packet */
718 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
719 if (!NT_STATUS_IS_OK(status)) {
723 /* send it on its way */
724 status = c->transport.send_request(c, &blob, False);
725 if (!NT_STATUS_IS_OK(status)) {
733 /* perform a dcerpc bind, using the uuid as the key */
734 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
736 const char *uuid, uint_t version)
738 struct dcerpc_syntax_id syntax;
739 struct dcerpc_syntax_id transfer_syntax;
742 status = GUID_from_string(uuid, &syntax.uuid);
743 if (!NT_STATUS_IS_OK(status)) {
744 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
747 syntax.if_version = version;
749 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
750 if (!NT_STATUS_IS_OK(status)) {
753 transfer_syntax.if_version = NDR_GUID_VERSION;
755 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
759 process a fragment received from the transport layer during a
762 This function frees the data
764 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
768 struct ncacn_packet pkt;
769 struct rpc_request *req;
772 if (!NT_STATUS_IS_OK(status)) {
773 data_blob_free(data);
775 /* all pending requests get the error */
778 req->state = RPC_REQUEST_DONE;
779 req->status = status;
780 DLIST_REMOVE(c->pending, req);
781 if (req->async.callback) {
782 req->async.callback(req);
790 status = ncacn_pull_request_sign(c, data, data->data, &pkt);
792 /* find the matching request. Notice we match before we check
793 the status. this is ok as a pending call_id can never be
795 for (req=c->pending;req;req=req->next) {
796 if (pkt.call_id == req->call_id) break;
800 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
801 data_blob_free(data);
805 if (!NT_STATUS_IS_OK(status)) {
806 req->status = status;
810 if (pkt.ptype == DCERPC_PKT_FAULT) {
811 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
812 req->fault_code = pkt.u.fault.status;
813 req->status = NT_STATUS_NET_WRITE_FAULT;
817 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
818 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
820 req->fault_code = DCERPC_FAULT_OTHER;
821 req->status = NT_STATUS_NET_WRITE_FAULT;
825 length = pkt.u.response.stub_and_verifier.length;
828 req->payload.data = talloc_realloc(req,
831 req->payload.length + length);
832 if (!req->payload.data) {
833 req->status = NT_STATUS_NO_MEMORY;
836 memcpy(req->payload.data+req->payload.length,
837 pkt.u.response.stub_and_verifier.data, length);
838 req->payload.length += length;
841 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
842 c->transport.send_read(c);
843 data_blob_free(data);
847 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
848 req->flags |= DCERPC_PULL_BIGENDIAN;
850 req->flags &= ~DCERPC_PULL_BIGENDIAN;
855 /* we've got the full payload */
856 req->state = RPC_REQUEST_DONE;
857 DLIST_REMOVE(c->pending, req);
858 data_blob_free(data);
859 if (req->async.callback) {
860 req->async.callback(req);
863 if (c->request_queue != NULL) {
864 dcerpc_ship_next_request(c);
869 handle timeouts of individual dcerpc requests
871 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
872 struct timeval t, void *private)
874 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
876 if (req->state != RPC_REQUEST_PENDING) {
880 req->status = NT_STATUS_IO_TIMEOUT;
881 req->state = RPC_REQUEST_DONE;
882 DLIST_REMOVE(req->p->conn->pending, req);
883 if (req->async.callback) {
884 req->async.callback(req);
890 make sure requests are cleaned up
892 static int dcerpc_req_destructor(void *ptr)
894 struct rpc_request *req = ptr;
895 DLIST_REMOVE(req->p->conn->pending, req);
900 perform the send side of a async dcerpc request
902 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
903 const struct GUID *object,
906 DATA_BLOB *stub_data)
908 struct rpc_request *req;
910 p->conn->transport.recv_data = dcerpc_request_recv_data;
912 req = talloc(p, struct rpc_request);
918 req->call_id = next_call_id(p->conn);
919 req->status = NT_STATUS_OK;
920 req->state = RPC_REQUEST_PENDING;
921 req->payload = data_blob(NULL, 0);
924 req->async_call = async;
925 req->async.callback = NULL;
927 if (object != NULL) {
928 req->object = talloc_memdup(req, object, sizeof(*object));
929 if (req->object == NULL) {
938 req->request_data.length = stub_data->length;
939 req->request_data.data = talloc_reference(req, stub_data->data);
940 if (req->request_data.data == NULL) {
944 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
946 dcerpc_ship_next_request(p->conn);
948 if (p->request_timeout) {
949 event_add_timed(dcerpc_event_context(p), req,
950 timeval_current_ofs(p->request_timeout, 0),
951 dcerpc_timeout_handler, req);
954 talloc_set_destructor(req, dcerpc_req_destructor);
959 Send a request using the transport
962 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
964 struct rpc_request *req;
965 struct dcerpc_pipe *p;
966 DATA_BLOB *stub_data;
967 struct ncacn_packet pkt;
969 uint32_t remaining, chunk_size;
970 BOOL first_packet = True;
972 req = c->request_queue;
978 stub_data = &req->request_data;
980 if (!req->async_call && (c->pending != NULL)) {
984 DLIST_REMOVE(c->request_queue, req);
985 DLIST_ADD(c->pending, req);
987 init_ncacn_hdr(p->conn, &pkt);
989 remaining = stub_data->length;
991 /* we can write a full max_recv_frag size, minus the dcerpc
992 request header size */
993 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
995 pkt.ptype = DCERPC_PKT_REQUEST;
996 pkt.call_id = req->call_id;
999 pkt.u.request.alloc_hint = remaining;
1000 pkt.u.request.context_id = p->context_id;
1001 pkt.u.request.opnum = req->opnum;
1004 pkt.u.request.object.object = *req->object;
1005 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1006 chunk_size -= ndr_size_GUID(req->object,0);
1009 /* we send a series of pdus without waiting for a reply */
1010 while (remaining > 0 || first_packet) {
1011 uint32_t chunk = MIN(chunk_size, remaining);
1012 BOOL last_frag = False;
1014 first_packet = False;
1015 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1017 if (remaining == stub_data->length) {
1018 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1020 if (chunk == remaining) {
1021 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1025 pkt.u.request.stub_and_verifier.data = stub_data->data +
1026 (stub_data->length - remaining);
1027 pkt.u.request.stub_and_verifier.length = chunk;
1029 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1030 if (!NT_STATUS_IS_OK(req->status)) {
1031 req->state = RPC_REQUEST_DONE;
1032 DLIST_REMOVE(p->conn->pending, req);
1036 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1037 if (!NT_STATUS_IS_OK(req->status)) {
1038 req->state = RPC_REQUEST_DONE;
1039 DLIST_REMOVE(p->conn->pending, req);
1048 return the event context for a dcerpc pipe
1049 used by callers who wish to operate asynchronously
1051 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1053 return p->conn->event_ctx;
1059 perform the receive side of a async dcerpc request
1061 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1062 TALLOC_CTX *mem_ctx,
1063 DATA_BLOB *stub_data)
1067 while (req->state == RPC_REQUEST_PENDING) {
1068 struct event_context *ctx = dcerpc_event_context(req->p);
1069 if (event_loop_once(ctx) != 0) {
1070 return NT_STATUS_CONNECTION_DISCONNECTED;
1073 *stub_data = req->payload;
1074 status = req->status;
1075 if (stub_data->data) {
1076 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1078 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1079 req->p->last_fault_code = req->fault_code;
1086 perform a full request/response pair on a dcerpc pipe
1088 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1089 struct GUID *object,
1092 TALLOC_CTX *mem_ctx,
1093 DATA_BLOB *stub_data_in,
1094 DATA_BLOB *stub_data_out)
1096 struct rpc_request *req;
1098 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1100 return NT_STATUS_NO_MEMORY;
1103 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1108 this is a paranoid NDR validator. For every packet we push onto the wire
1109 we pull it back again, then push it again. Then we compare the raw NDR data
1110 for that to the NDR we initially generated. If they don't match then we know
1111 we must have a bug in either the pull or push side of our code
1113 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1114 TALLOC_CTX *mem_ctx,
1117 ndr_push_flags_fn_t ndr_push,
1118 ndr_pull_flags_fn_t ndr_pull)
1121 struct ndr_pull *pull;
1122 struct ndr_push *push;
1126 st = talloc_size(mem_ctx, struct_size);
1128 return NT_STATUS_NO_MEMORY;
1131 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1133 return NT_STATUS_NO_MEMORY;
1135 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1137 status = ndr_pull(pull, NDR_IN, st);
1138 if (!NT_STATUS_IS_OK(status)) {
1139 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1140 "failed input validation pull - %s",
1144 push = ndr_push_init_ctx(mem_ctx);
1146 return NT_STATUS_NO_MEMORY;
1149 status = ndr_push(push, NDR_IN, st);
1150 if (!NT_STATUS_IS_OK(status)) {
1151 return ndr_push_error(push, NDR_ERR_VALIDATE,
1152 "failed input validation push - %s",
1156 blob2 = ndr_push_blob(push);
1158 if (!data_blob_equal(&blob, &blob2)) {
1159 DEBUG(3,("original:\n"));
1160 dump_data(3, blob.data, blob.length);
1161 DEBUG(3,("secondary:\n"));
1162 dump_data(3, blob2.data, blob2.length);
1163 return ndr_push_error(push, NDR_ERR_VALIDATE,
1164 "failed input validation data - %s",
1168 return NT_STATUS_OK;
1172 this is a paranoid NDR input validator. For every packet we pull
1173 from the wire we push it back again then pull and push it
1174 again. Then we compare the raw NDR data for that to the NDR we
1175 initially generated. If they don't match then we know we must have a
1176 bug in either the pull or push side of our code
1178 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1179 TALLOC_CTX *mem_ctx,
1182 ndr_push_flags_fn_t ndr_push,
1183 ndr_pull_flags_fn_t ndr_pull)
1186 struct ndr_pull *pull;
1187 struct ndr_push *push;
1189 DATA_BLOB blob, blob2;
1191 st = talloc_size(mem_ctx, struct_size);
1193 return NT_STATUS_NO_MEMORY;
1195 memcpy(st, struct_ptr, struct_size);
1197 push = ndr_push_init_ctx(mem_ctx);
1199 return NT_STATUS_NO_MEMORY;
1202 status = ndr_push(push, NDR_OUT, struct_ptr);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 return ndr_push_error(push, NDR_ERR_VALIDATE,
1205 "failed output validation push - %s",
1209 blob = ndr_push_blob(push);
1211 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1213 return NT_STATUS_NO_MEMORY;
1216 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1217 status = ndr_pull(pull, NDR_OUT, st);
1218 if (!NT_STATUS_IS_OK(status)) {
1219 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1220 "failed output validation pull - %s",
1224 push = ndr_push_init_ctx(mem_ctx);
1226 return NT_STATUS_NO_MEMORY;
1229 status = ndr_push(push, NDR_OUT, st);
1230 if (!NT_STATUS_IS_OK(status)) {
1231 return ndr_push_error(push, NDR_ERR_VALIDATE,
1232 "failed output validation push2 - %s",
1236 blob2 = ndr_push_blob(push);
1238 if (!data_blob_equal(&blob, &blob2)) {
1239 DEBUG(3,("original:\n"));
1240 dump_data(3, blob.data, blob.length);
1241 DEBUG(3,("secondary:\n"));
1242 dump_data(3, blob2.data, blob2.length);
1243 return ndr_push_error(push, NDR_ERR_VALIDATE,
1244 "failed output validation data - %s",
1248 return NT_STATUS_OK;
1253 send a rpc request given a dcerpc_call structure
1255 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1256 const struct GUID *object,
1257 const struct dcerpc_interface_table *table,
1259 TALLOC_CTX *mem_ctx,
1262 const struct dcerpc_interface_call *call;
1263 struct ndr_push *push;
1266 struct rpc_request *req;
1268 call = &table->calls[opnum];
1270 /* setup for a ndr_push_* call */
1271 push = ndr_push_init_ctx(mem_ctx);
1276 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1277 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1280 /* push the structure into a blob */
1281 status = call->ndr_push(push, NDR_IN, r);
1282 if (!NT_STATUS_IS_OK(status)) {
1283 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1284 nt_errstr(status)));
1289 /* retrieve the blob */
1290 request = ndr_push_blob(push);
1292 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1293 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1294 call->ndr_push, call->ndr_pull);
1295 if (!NT_STATUS_IS_OK(status)) {
1296 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1297 nt_errstr(status)));
1303 DEBUG(10,("rpc request data:\n"));
1304 dump_data(10, request.data, request.length);
1306 /* make the actual dcerpc request */
1307 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1311 req->ndr.table = table;
1312 req->ndr.opnum = opnum;
1313 req->ndr.struct_ptr = r;
1314 req->ndr.mem_ctx = mem_ctx;
1323 receive the answer from a dcerpc_ndr_request_send()
1325 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1327 struct dcerpc_pipe *p = req->p;
1330 struct ndr_pull *pull;
1332 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1333 void *r = req->ndr.struct_ptr;
1334 uint32_t opnum = req->ndr.opnum;
1335 const struct dcerpc_interface_table *table = req->ndr.table;
1336 const struct dcerpc_interface_call *call = &table->calls[opnum];
1338 /* make sure the recv code doesn't free the request, as we
1339 need to grab the flags element before it is freed */
1340 talloc_increase_ref_count(req);
1342 status = dcerpc_request_recv(req, mem_ctx, &response);
1343 if (!NT_STATUS_IS_OK(status)) {
1349 /* prepare for ndr_pull_* */
1350 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1353 return NT_STATUS_NO_MEMORY;
1357 pull->data = talloc_steal(pull, pull->data);
1361 if (flags & DCERPC_PULL_BIGENDIAN) {
1362 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1365 DEBUG(10,("rpc reply data:\n"));
1366 dump_data(10, pull->data, pull->data_size);
1368 /* pull the structure from the blob */
1369 status = call->ndr_pull(pull, NDR_OUT, r);
1370 if (!NT_STATUS_IS_OK(status)) {
1371 dcerpc_log_packet(table, opnum, NDR_OUT,
1376 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1377 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1378 call->ndr_push, call->ndr_pull);
1379 if (!NT_STATUS_IS_OK(status)) {
1380 dcerpc_log_packet(table, opnum, NDR_OUT,
1386 if (pull->offset != pull->data_size) {
1387 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1388 pull->data_size - pull->offset));
1389 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1390 but it turns out that early versions of NT
1391 (specifically NT3.1) add junk onto the end of rpc
1392 packets, so if we want to interoperate at all with
1393 those versions then we need to ignore this error */
1396 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1398 return NT_STATUS_OK;
1403 a useful helper function for synchronous rpc requests
1405 this can be used when you have ndr push/pull functions in the
1408 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1409 const struct GUID *object,
1410 const struct dcerpc_interface_table *table,
1412 TALLOC_CTX *mem_ctx,
1415 struct rpc_request *req;
1417 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1419 return NT_STATUS_NO_MEMORY;
1422 return dcerpc_ndr_request_recv(req);
1427 a useful function for retrieving the server name we connected to
1429 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1431 if (!p->conn->transport.peer_name) {
1434 return p->conn->transport.peer_name(p->conn);
1439 get the dcerpc auth_level for a open connection
1441 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1445 if (c->flags & DCERPC_SEAL) {
1446 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1447 } else if (c->flags & DCERPC_SIGN) {
1448 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1449 } else if (c->flags & DCERPC_CONNECT) {
1450 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1452 auth_level = DCERPC_AUTH_LEVEL_NONE;
1459 send a dcerpc alter_context request
1461 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1462 TALLOC_CTX *mem_ctx,
1463 const struct dcerpc_syntax_id *syntax,
1464 const struct dcerpc_syntax_id *transfer_syntax)
1466 struct ncacn_packet pkt;
1470 p->syntax = *syntax;
1471 p->transfer_syntax = *transfer_syntax;
1473 init_ncacn_hdr(p->conn, &pkt);
1475 pkt.ptype = DCERPC_PKT_ALTER;
1476 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1477 pkt.call_id = p->conn->call_id;
1478 pkt.auth_length = 0;
1480 pkt.u.alter.max_xmit_frag = 5840;
1481 pkt.u.alter.max_recv_frag = 5840;
1482 pkt.u.alter.assoc_group_id = 0;
1483 pkt.u.alter.num_contexts = 1;
1484 pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1485 if (!pkt.u.alter.ctx_list) {
1486 return NT_STATUS_NO_MEMORY;
1488 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1489 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1490 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1491 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1492 pkt.u.alter.auth_info = data_blob(NULL, 0);
1494 /* construct the NDR form of the packet */
1495 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1496 if (!NT_STATUS_IS_OK(status)) {
1500 /* send it on its way */
1501 status = full_request(p->conn, mem_ctx, &blob, &blob);
1502 if (!NT_STATUS_IS_OK(status)) {
1506 /* unmarshall the NDR */
1507 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
1508 if (!NT_STATUS_IS_OK(status)) {
1512 if (pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1513 pkt.u.alter_resp.num_results == 1 &&
1514 pkt.u.alter_resp.ctx_list[0].result != 0) {
1515 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1516 pkt.u.alter_resp.ctx_list[0].reason));
1517 return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason);
1520 if (pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1521 pkt.u.alter_resp.num_results == 0 ||
1522 pkt.u.alter_resp.ctx_list[0].result != 0) {
1523 return NT_STATUS_UNSUCCESSFUL;
1526 /* the alter_resp might contain a reply set of credentials */
1527 if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) {
1528 status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info,
1530 p->conn->security_state.auth_info,
1531 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);