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 the event context is optional
73 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
74 struct event_context *ev)
76 struct dcerpc_connection *c;
78 c = talloc_zero(mem_ctx, struct dcerpc_connection);
84 ev = event_context_init(c);
93 c->security_state.auth_info = NULL;
94 c->security_state.session_key = dcerpc_generic_session_key;
95 c->security_state.generic_state = NULL;
96 c->binding_string = NULL;
98 c->srv_max_xmit_frag = 0;
99 c->srv_max_recv_frag = 0;
102 talloc_set_destructor(c, dcerpc_connection_destructor);
107 /* initialise a dcerpc pipe. */
108 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
110 struct dcerpc_pipe *p;
112 p = talloc(mem_ctx, struct dcerpc_pipe);
117 p->conn = dcerpc_connection_init(p, ev);
118 if (p->conn == NULL) {
123 p->last_fault_code = 0;
125 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
127 ZERO_STRUCT(p->syntax);
128 ZERO_STRUCT(p->transfer_syntax);
135 choose the next call id to use
137 static uint32_t next_call_id(struct dcerpc_connection *c)
140 if (c->call_id == 0) {
146 /* we need to be able to get/set the fragment length without doing a full
148 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
150 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
151 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
153 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
157 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
159 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
160 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
162 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
166 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
168 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
169 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
171 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
177 setup for a ndr pull, also setting up any flags from the binding string
179 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
180 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
182 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
184 if (ndr == NULL) return ndr;
186 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
187 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
190 if (c->flags & DCERPC_NDR_REF_ALLOC) {
191 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
198 parse a data blob into a ncacn_packet structure. This handles both
199 input and output packets
201 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
202 struct ncacn_packet *pkt)
204 struct ndr_pull *ndr;
206 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
208 return NT_STATUS_NO_MEMORY;
211 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
212 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
215 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
219 generate a CONNECT level verifier
221 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
223 *blob = data_blob_talloc(mem_ctx, NULL, 16);
224 if (blob->data == NULL) {
225 return NT_STATUS_NO_MEMORY;
227 SIVAL(blob->data, 0, 1);
228 memset(blob->data+4, 0, 12);
233 check a CONNECT level verifier
235 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
237 if (blob->length != 16 ||
238 IVAL(blob->data, 0) != 1) {
239 return NT_STATUS_ACCESS_DENIED;
245 parse a possibly signed blob into a dcerpc request packet structure
247 static NTSTATUS ncacn_pull_request_sign(struct dcerpc_connection *c,
248 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
249 struct ncacn_packet *pkt)
251 struct ndr_pull *ndr;
253 struct dcerpc_auth auth;
256 /* non-signed packets are simpler */
257 if (!c->security_state.auth_info ||
258 !c->security_state.generic_state) {
259 return ncacn_pull(c, blob, mem_ctx, pkt);
262 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
264 return NT_STATUS_NO_MEMORY;
267 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
268 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
271 /* pull the basic packet */
272 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
273 if (!NT_STATUS_IS_OK(status)) {
277 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
281 if (pkt->auth_length == 0 &&
282 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
286 auth_blob.length = 8 + pkt->auth_length;
288 /* check for a valid length */
289 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
290 return NT_STATUS_INFO_LENGTH_MISMATCH;
294 pkt->u.response.stub_and_verifier.data +
295 pkt->u.response.stub_and_verifier.length - auth_blob.length;
296 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
298 /* pull the auth structure */
299 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
301 return NT_STATUS_NO_MEMORY;
304 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
305 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
308 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
309 if (!NT_STATUS_IS_OK(status)) {
314 /* check signature or unseal the packet */
315 switch (c->security_state.auth_info->auth_level) {
316 case DCERPC_AUTH_LEVEL_PRIVACY:
317 status = gensec_unseal_packet(c->security_state.generic_state,
319 blob->data + DCERPC_REQUEST_LENGTH,
320 pkt->u.response.stub_and_verifier.length,
322 blob->length - auth.credentials.length,
324 memcpy(pkt->u.response.stub_and_verifier.data,
325 blob->data + DCERPC_REQUEST_LENGTH,
326 pkt->u.response.stub_and_verifier.length);
329 case DCERPC_AUTH_LEVEL_INTEGRITY:
330 status = gensec_check_packet(c->security_state.generic_state,
332 pkt->u.response.stub_and_verifier.data,
333 pkt->u.response.stub_and_verifier.length,
335 blob->length - auth.credentials.length,
339 case DCERPC_AUTH_LEVEL_CONNECT:
340 status = dcerpc_check_connect_verifier(&auth.credentials);
343 case DCERPC_AUTH_LEVEL_NONE:
347 status = NT_STATUS_INVALID_LEVEL;
351 /* remove the indicated amount of paddiing */
352 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
353 return NT_STATUS_INFO_LENGTH_MISMATCH;
355 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
362 push a dcerpc request packet into a blob, possibly signing it.
364 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
365 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
366 struct ncacn_packet *pkt)
369 struct ndr_push *ndr;
372 /* non-signed packets are simpler */
373 if (!c->security_state.auth_info ||
374 !c->security_state.generic_state) {
375 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
378 ndr = ndr_push_init_ctx(mem_ctx);
380 return NT_STATUS_NO_MEMORY;
383 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
384 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
387 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
388 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
391 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
392 if (!NT_STATUS_IS_OK(status)) {
396 /* pad to 16 byte multiple in the payload portion of the
397 packet. This matches what w2k3 does */
398 c->security_state.auth_info->auth_pad_length =
399 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
400 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
402 /* sign or seal the packet */
403 switch (c->security_state.auth_info->auth_level) {
404 case DCERPC_AUTH_LEVEL_PRIVACY:
405 case DCERPC_AUTH_LEVEL_INTEGRITY:
406 c->security_state.auth_info->credentials
407 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state));
408 data_blob_clear(&c->security_state.auth_info->credentials);
411 case DCERPC_AUTH_LEVEL_CONNECT:
412 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
415 case DCERPC_AUTH_LEVEL_NONE:
416 c->security_state.auth_info->credentials = data_blob(NULL, 0);
420 status = NT_STATUS_INVALID_LEVEL;
424 if (!NT_STATUS_IS_OK(status)) {
428 /* add the auth verifier */
429 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
430 if (!NT_STATUS_IS_OK(status)) {
434 /* extract the whole packet as a blob */
435 *blob = ndr_push_blob(ndr);
437 /* fill in the fragment length and auth_length, we can't fill
438 in these earlier as we don't know the signature length (it
439 could be variable length) */
440 dcerpc_set_frag_length(blob, blob->length);
441 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
443 /* sign or seal the packet */
444 switch (c->security_state.auth_info->auth_level) {
445 case DCERPC_AUTH_LEVEL_PRIVACY:
446 status = gensec_seal_packet(c->security_state.generic_state,
448 blob->data + DCERPC_REQUEST_LENGTH,
449 pkt->u.request.stub_and_verifier.length +
450 c->security_state.auth_info->auth_pad_length,
453 c->security_state.auth_info->credentials.length,
455 if (!NT_STATUS_IS_OK(status)) {
458 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
461 case DCERPC_AUTH_LEVEL_INTEGRITY:
462 status = gensec_sign_packet(c->security_state.generic_state,
464 blob->data + DCERPC_REQUEST_LENGTH,
465 pkt->u.request.stub_and_verifier.length +
466 c->security_state.auth_info->auth_pad_length,
469 c->security_state.auth_info->credentials.length,
471 if (!NT_STATUS_IS_OK(status)) {
474 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
477 case DCERPC_AUTH_LEVEL_CONNECT:
480 case DCERPC_AUTH_LEVEL_NONE:
481 c->security_state.auth_info->credentials = data_blob(NULL, 0);
485 status = NT_STATUS_INVALID_LEVEL;
489 data_blob_free(&c->security_state.auth_info->credentials);
496 fill in the fixed values in a dcerpc header
498 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
501 pkt->rpc_vers_minor = 0;
502 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
505 pkt->drep[0] = DCERPC_DREP_LE;
513 hold the state of pending full requests
515 struct full_request_state {
516 DATA_BLOB *reply_blob;
521 receive a reply to a full request
523 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob,
526 struct full_request_state *state = c->full_request_private;
528 if (!NT_STATUS_IS_OK(status)) {
529 state->status = status;
532 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
533 state->reply_blob = NULL;
537 handle timeouts of full dcerpc requests
539 static void dcerpc_full_timeout_handler(struct event_context *ev, struct timed_event *te,
540 struct timeval t, void *private)
542 struct full_request_state *state = talloc_get_type(private,
543 struct full_request_state);
544 state->status = NT_STATUS_IO_TIMEOUT;
548 perform a single pdu synchronous request - used for the bind code
549 this cannot be mixed with normal async requests
551 static NTSTATUS full_request(struct dcerpc_connection *c,
553 DATA_BLOB *request_blob,
554 DATA_BLOB *reply_blob)
556 struct full_request_state *state = talloc(mem_ctx, struct full_request_state);
560 return NT_STATUS_NO_MEMORY;
563 state->reply_blob = reply_blob;
564 state->status = NT_STATUS_OK;
566 c->transport.recv_data = full_request_recv;
567 c->full_request_private = state;
569 status = c->transport.send_request(c, request_blob, True);
570 if (!NT_STATUS_IS_OK(status)) {
574 event_add_timed(c->event_ctx, state,
575 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
576 dcerpc_full_timeout_handler, state);
578 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
579 if (event_loop_once(c->event_ctx) != 0) {
580 return NT_STATUS_CONNECTION_DISCONNECTED;
584 return state->status;
588 map a bind nak reason to a NTSTATUS
590 static NTSTATUS dcerpc_map_reason(uint16_t reason)
593 case DCERPC_BIND_REASON_ASYNTAX:
594 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
596 return NT_STATUS_UNSUCCESSFUL;
601 perform a bind using the given syntax
603 the auth_info structure is updated with the reply authentication info
606 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
608 const struct dcerpc_syntax_id *syntax,
609 const struct dcerpc_syntax_id *transfer_syntax)
611 struct ncacn_packet pkt;
616 p->transfer_syntax = *transfer_syntax;
618 init_ncacn_hdr(p->conn, &pkt);
620 pkt.ptype = DCERPC_PKT_BIND;
621 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
622 pkt.call_id = p->conn->call_id;
625 pkt.u.bind.max_xmit_frag = 5840;
626 pkt.u.bind.max_recv_frag = 5840;
627 pkt.u.bind.assoc_group_id = 0;
628 pkt.u.bind.num_contexts = 1;
629 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
630 if (!pkt.u.bind.ctx_list) {
631 return NT_STATUS_NO_MEMORY;
633 pkt.u.bind.ctx_list[0].context_id = p->context_id;
634 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
635 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
636 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
637 pkt.u.bind.auth_info = data_blob(NULL, 0);
639 /* construct the NDR form of the packet */
640 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
641 if (!NT_STATUS_IS_OK(status)) {
645 /* send it on its way */
646 status = full_request(p->conn, mem_ctx, &blob, &blob);
647 if (!NT_STATUS_IS_OK(status)) {
651 /* unmarshall the NDR */
652 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
653 if (!NT_STATUS_IS_OK(status)) {
657 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
658 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
659 return dcerpc_map_reason(pkt.u.bind_nak.reject_reason);
662 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
663 pkt.u.bind_ack.num_results == 0 ||
664 pkt.u.bind_ack.ctx_list[0].result != 0) {
665 return NT_STATUS_UNSUCCESSFUL;
668 p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
669 p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
671 /* the bind_ack might contain a reply set of credentials */
672 if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
673 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
675 p->conn->security_state.auth_info,
676 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
683 perform a continued bind (and auth3)
685 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
688 struct ncacn_packet pkt;
692 init_ncacn_hdr(c, &pkt);
694 pkt.ptype = DCERPC_PKT_AUTH3;
695 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
696 pkt.call_id = next_call_id(c);
698 pkt.u.auth3._pad = 0;
699 pkt.u.auth3.auth_info = data_blob(NULL, 0);
701 /* construct the NDR form of the packet */
702 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
703 if (!NT_STATUS_IS_OK(status)) {
707 /* send it on its way */
708 status = c->transport.send_request(c, &blob, False);
709 if (!NT_STATUS_IS_OK(status)) {
717 /* perform a dcerpc bind, using the uuid as the key */
718 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
720 const char *uuid, uint_t version)
722 struct dcerpc_syntax_id syntax;
723 struct dcerpc_syntax_id transfer_syntax;
726 status = GUID_from_string(uuid, &syntax.uuid);
727 if (!NT_STATUS_IS_OK(status)) {
728 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
731 syntax.if_version = version;
733 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
734 if (!NT_STATUS_IS_OK(status)) {
737 transfer_syntax.if_version = NDR_GUID_VERSION;
739 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
743 process a fragment received from the transport layer during a
746 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
750 struct ncacn_packet pkt;
751 struct rpc_request *req;
754 if (!NT_STATUS_IS_OK(status)) {
755 /* all pending requests get the error */
758 req->state = RPC_REQUEST_DONE;
759 req->status = status;
760 DLIST_REMOVE(c->pending, req);
761 if (req->async.callback) {
762 req->async.callback(req);
770 status = ncacn_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
772 /* find the matching request. Notice we match before we check
773 the status. this is ok as a pending call_id can never be
775 for (req=c->pending;req;req=req->next) {
776 if (pkt.call_id == req->call_id) break;
780 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
784 if (!NT_STATUS_IS_OK(status)) {
785 req->status = status;
786 req->state = RPC_REQUEST_DONE;
787 DLIST_REMOVE(c->pending, req);
788 if (req->async.callback) {
789 req->async.callback(req);
794 if (pkt.ptype == DCERPC_PKT_FAULT) {
795 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
796 req->fault_code = pkt.u.fault.status;
797 req->status = NT_STATUS_NET_WRITE_FAULT;
798 req->state = RPC_REQUEST_DONE;
799 DLIST_REMOVE(c->pending, req);
800 if (req->async.callback) {
801 req->async.callback(req);
806 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
807 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
809 req->fault_code = DCERPC_FAULT_OTHER;
810 req->status = NT_STATUS_NET_WRITE_FAULT;
811 req->state = RPC_REQUEST_DONE;
812 DLIST_REMOVE(c->pending, req);
813 if (req->async.callback) {
814 req->async.callback(req);
819 length = pkt.u.response.stub_and_verifier.length;
822 req->payload.data = talloc_realloc(req,
825 req->payload.length + length);
826 if (!req->payload.data) {
827 req->status = NT_STATUS_NO_MEMORY;
828 req->state = RPC_REQUEST_DONE;
829 DLIST_REMOVE(c->pending, req);
830 if (req->async.callback) {
831 req->async.callback(req);
835 memcpy(req->payload.data+req->payload.length,
836 pkt.u.response.stub_and_verifier.data, length);
837 req->payload.length += length;
840 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
841 c->transport.send_read(c);
845 /* we've got the full payload */
846 req->state = RPC_REQUEST_DONE;
847 DLIST_REMOVE(c->pending, req);
849 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
850 req->flags |= DCERPC_PULL_BIGENDIAN;
852 req->flags &= ~DCERPC_PULL_BIGENDIAN;
855 if (req->async.callback) {
856 req->async.callback(req);
861 handle timeouts of individual dcerpc requests
863 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
864 struct timeval t, void *private)
866 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
868 if (req->state != RPC_REQUEST_PENDING) {
872 req->status = NT_STATUS_IO_TIMEOUT;
873 req->state = RPC_REQUEST_DONE;
874 DLIST_REMOVE(req->p->conn->pending, req);
875 if (req->async.callback) {
876 req->async.callback(req);
882 make sure requests are cleaned up
884 static int dcerpc_req_destructor(void *ptr)
886 struct rpc_request *req = ptr;
887 DLIST_REMOVE(req->p->conn->pending, req);
892 perform the send side of a async dcerpc request
894 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
895 const struct GUID *object,
897 DATA_BLOB *stub_data)
899 struct rpc_request *req;
900 struct ncacn_packet pkt;
902 uint32_t remaining, chunk_size;
903 BOOL first_packet = True;
905 p->conn->transport.recv_data = dcerpc_request_recv_data;
907 req = talloc(p, struct rpc_request);
913 req->call_id = next_call_id(p->conn);
914 req->status = NT_STATUS_OK;
915 req->state = RPC_REQUEST_PENDING;
916 req->payload = data_blob(NULL, 0);
919 req->async.callback = NULL;
921 init_ncacn_hdr(p->conn, &pkt);
923 remaining = stub_data->length;
925 /* we can write a full max_recv_frag size, minus the dcerpc
926 request header size */
927 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
929 pkt.ptype = DCERPC_PKT_REQUEST;
930 pkt.call_id = req->call_id;
933 pkt.u.request.alloc_hint = remaining;
934 pkt.u.request.context_id = p->context_id;
935 pkt.u.request.opnum = opnum;
938 pkt.u.request.object.object = *object;
939 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
940 chunk_size -= ndr_size_GUID(object,0);
943 DLIST_ADD(p->conn->pending, req);
945 /* we send a series of pdus without waiting for a reply */
946 while (remaining > 0 || first_packet) {
947 uint32_t chunk = MIN(chunk_size, remaining);
948 BOOL last_frag = False;
950 first_packet = False;
951 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
953 if (remaining == stub_data->length) {
954 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
956 if (chunk == remaining) {
957 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
961 pkt.u.request.stub_and_verifier.data = stub_data->data +
962 (stub_data->length - remaining);
963 pkt.u.request.stub_and_verifier.length = chunk;
965 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
966 if (!NT_STATUS_IS_OK(req->status)) {
967 req->state = RPC_REQUEST_DONE;
968 DLIST_REMOVE(p->conn->pending, req);
972 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
973 if (!NT_STATUS_IS_OK(req->status)) {
974 req->state = RPC_REQUEST_DONE;
975 DLIST_REMOVE(p->conn->pending, req);
982 if (p->request_timeout) {
983 event_add_timed(dcerpc_event_context(p), req,
984 timeval_current_ofs(p->request_timeout, 0),
985 dcerpc_timeout_handler, req);
988 talloc_set_destructor(req, dcerpc_req_destructor);
994 return the event context for a dcerpc pipe
995 used by callers who wish to operate asynchronously
997 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
999 return p->conn->event_ctx;
1005 perform the receive side of a async dcerpc request
1007 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1008 TALLOC_CTX *mem_ctx,
1009 DATA_BLOB *stub_data)
1013 while (req->state == RPC_REQUEST_PENDING) {
1014 struct event_context *ctx = dcerpc_event_context(req->p);
1015 if (event_loop_once(ctx) != 0) {
1016 return NT_STATUS_CONNECTION_DISCONNECTED;
1019 *stub_data = req->payload;
1020 status = req->status;
1021 if (stub_data->data) {
1022 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1024 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1025 req->p->last_fault_code = req->fault_code;
1032 perform a full request/response pair on a dcerpc pipe
1034 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1035 struct GUID *object,
1037 TALLOC_CTX *mem_ctx,
1038 DATA_BLOB *stub_data_in,
1039 DATA_BLOB *stub_data_out)
1041 struct rpc_request *req;
1043 req = dcerpc_request_send(p, object, opnum, stub_data_in);
1045 return NT_STATUS_NO_MEMORY;
1048 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1053 this is a paranoid NDR validator. For every packet we push onto the wire
1054 we pull it back again, then push it again. Then we compare the raw NDR data
1055 for that to the NDR we initially generated. If they don't match then we know
1056 we must have a bug in either the pull or push side of our code
1058 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1059 TALLOC_CTX *mem_ctx,
1062 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1063 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1066 struct ndr_pull *pull;
1067 struct ndr_push *push;
1071 st = talloc_size(mem_ctx, struct_size);
1073 return NT_STATUS_NO_MEMORY;
1076 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1078 return NT_STATUS_NO_MEMORY;
1080 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1082 status = ndr_pull(pull, NDR_IN, st);
1083 if (!NT_STATUS_IS_OK(status)) {
1084 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1085 "failed input validation pull - %s",
1089 push = ndr_push_init_ctx(mem_ctx);
1091 return NT_STATUS_NO_MEMORY;
1094 status = ndr_push(push, NDR_IN, st);
1095 if (!NT_STATUS_IS_OK(status)) {
1096 return ndr_push_error(push, NDR_ERR_VALIDATE,
1097 "failed input validation push - %s",
1101 blob2 = ndr_push_blob(push);
1103 if (!data_blob_equal(&blob, &blob2)) {
1104 DEBUG(3,("original:\n"));
1105 dump_data(3, blob.data, blob.length);
1106 DEBUG(3,("secondary:\n"));
1107 dump_data(3, blob2.data, blob2.length);
1108 return ndr_push_error(push, NDR_ERR_VALIDATE,
1109 "failed input validation data - %s",
1113 return NT_STATUS_OK;
1117 this is a paranoid NDR input validator. For every packet we pull
1118 from the wire we push it back again then pull and push it
1119 again. Then we compare the raw NDR data for that to the NDR we
1120 initially generated. If they don't match then we know we must have a
1121 bug in either the pull or push side of our code
1123 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1124 TALLOC_CTX *mem_ctx,
1127 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1128 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1131 struct ndr_pull *pull;
1132 struct ndr_push *push;
1134 DATA_BLOB blob, blob2;
1136 st = talloc_size(mem_ctx, struct_size);
1138 return NT_STATUS_NO_MEMORY;
1140 memcpy(st, struct_ptr, struct_size);
1142 push = ndr_push_init_ctx(mem_ctx);
1144 return NT_STATUS_NO_MEMORY;
1147 status = ndr_push(push, NDR_OUT, struct_ptr);
1148 if (!NT_STATUS_IS_OK(status)) {
1149 return ndr_push_error(push, NDR_ERR_VALIDATE,
1150 "failed output validation push - %s",
1154 blob = ndr_push_blob(push);
1156 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1158 return NT_STATUS_NO_MEMORY;
1161 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1162 status = ndr_pull(pull, NDR_OUT, st);
1163 if (!NT_STATUS_IS_OK(status)) {
1164 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1165 "failed output validation pull - %s",
1169 push = ndr_push_init_ctx(mem_ctx);
1171 return NT_STATUS_NO_MEMORY;
1174 status = ndr_push(push, NDR_OUT, st);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 return ndr_push_error(push, NDR_ERR_VALIDATE,
1177 "failed output validation push2 - %s",
1181 blob2 = ndr_push_blob(push);
1183 if (!data_blob_equal(&blob, &blob2)) {
1184 DEBUG(3,("original:\n"));
1185 dump_data(3, blob.data, blob.length);
1186 DEBUG(3,("secondary:\n"));
1187 dump_data(3, blob2.data, blob2.length);
1188 return ndr_push_error(push, NDR_ERR_VALIDATE,
1189 "failed output validation data - %s",
1193 return NT_STATUS_OK;
1198 send a rpc request given a dcerpc_call structure
1200 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1201 const struct GUID *object,
1202 const struct dcerpc_interface_table *table,
1204 TALLOC_CTX *mem_ctx,
1207 const struct dcerpc_interface_call *call;
1208 struct ndr_push *push;
1211 struct rpc_request *req;
1213 call = &table->calls[opnum];
1215 /* setup for a ndr_push_* call */
1216 push = ndr_push_init_ctx(mem_ctx);
1221 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1222 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1225 /* push the structure into a blob */
1226 status = call->ndr_push(push, NDR_IN, r);
1227 if (!NT_STATUS_IS_OK(status)) {
1228 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1229 nt_errstr(status)));
1234 /* retrieve the blob */
1235 request = ndr_push_blob(push);
1237 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1238 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1239 call->ndr_push, call->ndr_pull);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1242 nt_errstr(status)));
1248 DEBUG(10,("rpc request data:\n"));
1249 dump_data(10, request.data, request.length);
1251 /* make the actual dcerpc request */
1252 req = dcerpc_request_send(p, object, opnum, &request);
1255 req->ndr.table = table;
1256 req->ndr.opnum = opnum;
1257 req->ndr.struct_ptr = r;
1258 req->ndr.mem_ctx = mem_ctx;
1267 receive the answer from a dcerpc_ndr_request_send()
1269 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1271 struct dcerpc_pipe *p = req->p;
1274 struct ndr_pull *pull;
1276 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1277 void *r = req->ndr.struct_ptr;
1278 uint32_t opnum = req->ndr.opnum;
1279 const struct dcerpc_interface_table *table = req->ndr.table;
1280 const struct dcerpc_interface_call *call = &table->calls[opnum];
1282 /* make sure the recv code doesn't free the request, as we
1283 need to grab the flags element before it is freed */
1284 talloc_increase_ref_count(req);
1286 status = dcerpc_request_recv(req, mem_ctx, &response);
1287 if (!NT_STATUS_IS_OK(status)) {
1293 /* prepare for ndr_pull_* */
1294 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1297 return NT_STATUS_NO_MEMORY;
1301 pull->data = talloc_steal(pull, pull->data);
1305 if (flags & DCERPC_PULL_BIGENDIAN) {
1306 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1309 DEBUG(10,("rpc reply data:\n"));
1310 dump_data(10, pull->data, pull->data_size);
1312 /* pull the structure from the blob */
1313 status = call->ndr_pull(pull, NDR_OUT, r);
1314 if (!NT_STATUS_IS_OK(status)) {
1315 dcerpc_log_packet(table, opnum, NDR_OUT,
1320 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1321 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1322 call->ndr_push, call->ndr_pull);
1323 if (!NT_STATUS_IS_OK(status)) {
1324 dcerpc_log_packet(table, opnum, NDR_OUT,
1330 if (pull->offset != pull->data_size) {
1331 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1332 pull->data_size - pull->offset));
1333 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1334 but it turns out that early versions of NT
1335 (specifically NT3.1) add junk onto the end of rpc
1336 packets, so if we want to interoperate at all with
1337 those versions then we need to ignore this error */
1340 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1342 return NT_STATUS_OK;
1347 a useful helper function for synchronous rpc requests
1349 this can be used when you have ndr push/pull functions in the
1352 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1353 const struct GUID *object,
1354 const struct dcerpc_interface_table *table,
1356 TALLOC_CTX *mem_ctx,
1359 struct rpc_request *req;
1361 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1363 return NT_STATUS_NO_MEMORY;
1366 return dcerpc_ndr_request_recv(req);
1371 a useful function for retrieving the server name we connected to
1373 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1375 if (!p->conn->transport.peer_name) {
1378 return p->conn->transport.peer_name(p->conn);
1383 get the dcerpc auth_level for a open connection
1385 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1389 if (c->flags & DCERPC_SEAL) {
1390 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1391 } else if (c->flags & DCERPC_SIGN) {
1392 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1393 } else if (c->flags & DCERPC_CONNECT) {
1394 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1396 auth_level = DCERPC_AUTH_LEVEL_NONE;
1403 send a dcerpc alter_context request
1405 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1406 TALLOC_CTX *mem_ctx,
1407 const struct dcerpc_syntax_id *syntax,
1408 const struct dcerpc_syntax_id *transfer_syntax)
1410 struct ncacn_packet pkt;
1414 p->syntax = *syntax;
1415 p->transfer_syntax = *transfer_syntax;
1417 init_ncacn_hdr(p->conn, &pkt);
1419 pkt.ptype = DCERPC_PKT_ALTER;
1420 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1421 pkt.call_id = p->conn->call_id;
1422 pkt.auth_length = 0;
1424 pkt.u.alter.max_xmit_frag = 5840;
1425 pkt.u.alter.max_recv_frag = 5840;
1426 pkt.u.alter.assoc_group_id = 0;
1427 pkt.u.alter.num_contexts = 1;
1428 pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1429 if (!pkt.u.alter.ctx_list) {
1430 return NT_STATUS_NO_MEMORY;
1432 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1433 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1434 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1435 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1436 pkt.u.alter.auth_info = data_blob(NULL, 0);
1438 /* construct the NDR form of the packet */
1439 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1440 if (!NT_STATUS_IS_OK(status)) {
1444 /* send it on its way */
1445 status = full_request(p->conn, mem_ctx, &blob, &blob);
1446 if (!NT_STATUS_IS_OK(status)) {
1450 /* unmarshall the NDR */
1451 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
1452 if (!NT_STATUS_IS_OK(status)) {
1456 if (pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1457 pkt.u.alter_resp.num_results == 1 &&
1458 pkt.u.alter_resp.ctx_list[0].result != 0) {
1459 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1460 pkt.u.alter_resp.ctx_list[0].reason));
1461 return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason);
1464 if (pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1465 pkt.u.alter_resp.num_results == 0 ||
1466 pkt.u.alter_resp.ctx_list[0].result != 0) {
1467 return NT_STATUS_UNSUCCESSFUL;
1470 /* the alter_resp might contain a reply set of credentials */
1471 if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) {
1472 status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info,
1474 p->conn->security_state.auth_info,
1475 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);