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 struct dcerpc_interface_list *dcerpc_pipes = NULL;
34 register a dcerpc client interface
36 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
38 struct dcerpc_interface_list *l = talloc(talloc_autofree_context(),
39 struct dcerpc_interface_list);
41 if (idl_iface_by_name (interface->name) != NULL) {
42 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
43 return NT_STATUS_OBJECT_NAME_COLLISION;
47 DLIST_ADD(dcerpc_pipes, l);
53 return the list of registered dcerpc_pipes
55 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
60 /* destroy a dcerpc connection */
61 static int dcerpc_connection_destructor(void *ptr)
63 struct dcerpc_connection *c = ptr;
64 if (c->transport.shutdown_pipe) {
65 c->transport.shutdown_pipe(c);
71 /* initialise a dcerpc connection.
72 the event context is optional
74 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
75 struct event_context *ev)
77 struct dcerpc_connection *c;
79 c = talloc_zero(mem_ctx, struct dcerpc_connection);
85 ev = event_context_init(c);
94 c->security_state.auth_info = NULL;
95 c->security_state.session_key = dcerpc_generic_session_key;
96 c->security_state.generic_state = NULL;
97 c->binding_string = NULL;
99 c->srv_max_xmit_frag = 0;
100 c->srv_max_recv_frag = 0;
103 talloc_set_destructor(c, dcerpc_connection_destructor);
108 /* initialise a dcerpc pipe. */
109 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
111 struct dcerpc_pipe *p;
113 p = talloc(mem_ctx, struct dcerpc_pipe);
118 p->conn = dcerpc_connection_init(p, ev);
119 if (p->conn == NULL) {
124 p->last_fault_code = 0;
126 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
128 ZERO_STRUCT(p->syntax);
129 ZERO_STRUCT(p->transfer_syntax);
136 choose the next call id to use
138 static uint32_t next_call_id(struct dcerpc_connection *c)
141 if (c->call_id == 0) {
147 /* we need to be able to get/set the fragment length without doing a full
149 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
151 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
152 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
154 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
158 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
160 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
161 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
163 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
167 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
169 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
170 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
172 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
178 setup for a ndr pull, also setting up any flags from the binding string
180 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
181 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
183 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
185 if (ndr == NULL) return ndr;
187 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
188 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
191 if (c->flags & DCERPC_NDR_REF_ALLOC) {
192 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
199 parse a data blob into a ncacn_packet structure. This handles both
200 input and output packets
202 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
203 struct ncacn_packet *pkt)
205 struct ndr_pull *ndr;
207 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
209 return NT_STATUS_NO_MEMORY;
212 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
213 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
216 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
220 generate a CONNECT level verifier
222 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
224 *blob = data_blob_talloc(mem_ctx, NULL, 16);
225 if (blob->data == NULL) {
226 return NT_STATUS_NO_MEMORY;
228 SIVAL(blob->data, 0, 1);
229 memset(blob->data+4, 0, 12);
234 check a CONNECT level verifier
236 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
238 if (blob->length != 16 ||
239 IVAL(blob->data, 0) != 1) {
240 return NT_STATUS_ACCESS_DENIED;
246 parse a possibly signed blob into a dcerpc request packet structure
248 static NTSTATUS ncacn_pull_request_sign(struct dcerpc_connection *c,
249 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
250 struct ncacn_packet *pkt)
252 struct ndr_pull *ndr;
254 struct dcerpc_auth auth;
257 /* non-signed packets are simpler */
258 if (!c->security_state.auth_info ||
259 !c->security_state.generic_state) {
260 return ncacn_pull(c, blob, mem_ctx, pkt);
263 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
265 return NT_STATUS_NO_MEMORY;
268 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
269 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
272 /* pull the basic packet */
273 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
274 if (!NT_STATUS_IS_OK(status)) {
278 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
282 if (pkt->auth_length == 0 &&
283 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
287 auth_blob.length = 8 + pkt->auth_length;
289 /* check for a valid length */
290 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
291 return NT_STATUS_INFO_LENGTH_MISMATCH;
295 pkt->u.response.stub_and_verifier.data +
296 pkt->u.response.stub_and_verifier.length - auth_blob.length;
297 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
299 /* pull the auth structure */
300 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
302 return NT_STATUS_NO_MEMORY;
305 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
306 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
309 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
310 if (!NT_STATUS_IS_OK(status)) {
315 /* check signature or unseal the packet */
316 switch (c->security_state.auth_info->auth_level) {
317 case DCERPC_AUTH_LEVEL_PRIVACY:
318 status = gensec_unseal_packet(c->security_state.generic_state,
320 blob->data + DCERPC_REQUEST_LENGTH,
321 pkt->u.response.stub_and_verifier.length,
323 blob->length - auth.credentials.length,
325 memcpy(pkt->u.response.stub_and_verifier.data,
326 blob->data + DCERPC_REQUEST_LENGTH,
327 pkt->u.response.stub_and_verifier.length);
330 case DCERPC_AUTH_LEVEL_INTEGRITY:
331 status = gensec_check_packet(c->security_state.generic_state,
333 pkt->u.response.stub_and_verifier.data,
334 pkt->u.response.stub_and_verifier.length,
336 blob->length - auth.credentials.length,
340 case DCERPC_AUTH_LEVEL_CONNECT:
341 status = dcerpc_check_connect_verifier(&auth.credentials);
344 case DCERPC_AUTH_LEVEL_NONE:
348 status = NT_STATUS_INVALID_LEVEL;
352 /* remove the indicated amount of paddiing */
353 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
354 return NT_STATUS_INFO_LENGTH_MISMATCH;
356 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
363 push a dcerpc request packet into a blob, possibly signing it.
365 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
366 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
367 struct ncacn_packet *pkt)
370 struct ndr_push *ndr;
372 size_t payload_length;
374 /* non-signed packets are simpler */
375 if (!c->security_state.auth_info ||
376 !c->security_state.generic_state) {
377 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
380 ndr = ndr_push_init_ctx(mem_ctx);
382 return NT_STATUS_NO_MEMORY;
385 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
386 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
389 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
390 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
393 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
394 if (!NT_STATUS_IS_OK(status)) {
398 /* pad to 16 byte multiple in the payload portion of the
399 packet. This matches what w2k3 does */
400 c->security_state.auth_info->auth_pad_length =
401 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
402 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
404 payload_length = pkt->u.request.stub_and_verifier.length +
405 c->security_state.auth_info->auth_pad_length;
407 /* sign or seal the packet */
408 switch (c->security_state.auth_info->auth_level) {
409 case DCERPC_AUTH_LEVEL_PRIVACY:
410 case DCERPC_AUTH_LEVEL_INTEGRITY:
411 c->security_state.auth_info->credentials
412 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
414 data_blob_clear(&c->security_state.auth_info->credentials);
417 case DCERPC_AUTH_LEVEL_CONNECT:
418 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
421 case DCERPC_AUTH_LEVEL_NONE:
422 c->security_state.auth_info->credentials = data_blob(NULL, 0);
426 status = NT_STATUS_INVALID_LEVEL;
430 if (!NT_STATUS_IS_OK(status)) {
434 /* add the auth verifier */
435 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
436 if (!NT_STATUS_IS_OK(status)) {
440 /* extract the whole packet as a blob */
441 *blob = ndr_push_blob(ndr);
443 /* fill in the fragment length and auth_length, we can't fill
444 in these earlier as we don't know the signature length (it
445 could be variable length) */
446 dcerpc_set_frag_length(blob, blob->length);
447 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
449 /* sign or seal the packet */
450 switch (c->security_state.auth_info->auth_level) {
451 case DCERPC_AUTH_LEVEL_PRIVACY:
452 status = gensec_seal_packet(c->security_state.generic_state,
454 blob->data + DCERPC_REQUEST_LENGTH,
458 c->security_state.auth_info->credentials.length,
460 if (!NT_STATUS_IS_OK(status)) {
463 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
466 case DCERPC_AUTH_LEVEL_INTEGRITY:
467 status = gensec_sign_packet(c->security_state.generic_state,
469 blob->data + DCERPC_REQUEST_LENGTH,
473 c->security_state.auth_info->credentials.length,
475 if (!NT_STATUS_IS_OK(status)) {
478 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
481 case DCERPC_AUTH_LEVEL_CONNECT:
484 case DCERPC_AUTH_LEVEL_NONE:
485 c->security_state.auth_info->credentials = data_blob(NULL, 0);
489 status = NT_STATUS_INVALID_LEVEL;
493 data_blob_free(&c->security_state.auth_info->credentials);
500 fill in the fixed values in a dcerpc header
502 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
505 pkt->rpc_vers_minor = 0;
506 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
509 pkt->drep[0] = DCERPC_DREP_LE;
517 hold the state of pending full requests
519 struct full_request_state {
520 struct dcerpc_connection *c;
521 DATA_BLOB *reply_blob;
526 receive a reply to a full request
528 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob,
531 struct full_request_state *state = talloc_get_type(c->full_request_private,
532 struct full_request_state);
534 /* it timed out earlier */
538 if (!NT_STATUS_IS_OK(status)) {
539 state->status = status;
542 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
543 state->reply_blob = NULL;
547 handle timeouts of full dcerpc requests
549 static void dcerpc_full_timeout_handler(struct event_context *ev, struct timed_event *te,
550 struct timeval t, void *private)
552 struct full_request_state *state = talloc_get_type(private,
553 struct full_request_state);
554 state->status = NT_STATUS_IO_TIMEOUT;
555 state->c->full_request_private = NULL;
559 perform a single pdu synchronous request - used for the bind code
560 this cannot be mixed with normal async requests
562 static NTSTATUS full_request(struct dcerpc_connection *c,
564 DATA_BLOB *request_blob,
565 DATA_BLOB *reply_blob)
567 struct full_request_state *state = talloc(mem_ctx, struct full_request_state);
571 return NT_STATUS_NO_MEMORY;
574 state->reply_blob = reply_blob;
575 state->status = NT_STATUS_OK;
578 c->transport.recv_data = full_request_recv;
579 c->full_request_private = state;
581 status = c->transport.send_request(c, request_blob, True);
582 if (!NT_STATUS_IS_OK(status)) {
586 event_add_timed(c->event_ctx, state,
587 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
588 dcerpc_full_timeout_handler, state);
590 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
591 if (event_loop_once(c->event_ctx) != 0) {
592 return NT_STATUS_CONNECTION_DISCONNECTED;
596 c->full_request_private = NULL;
598 return state->status;
602 map a bind nak reason to a NTSTATUS
604 static NTSTATUS dcerpc_map_reason(uint16_t reason)
607 case DCERPC_BIND_REASON_ASYNTAX:
608 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
610 return NT_STATUS_UNSUCCESSFUL;
615 perform a bind using the given syntax
617 the auth_info structure is updated with the reply authentication info
620 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
622 const struct dcerpc_syntax_id *syntax,
623 const struct dcerpc_syntax_id *transfer_syntax)
625 struct ncacn_packet pkt;
630 p->transfer_syntax = *transfer_syntax;
632 init_ncacn_hdr(p->conn, &pkt);
634 pkt.ptype = DCERPC_PKT_BIND;
635 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
636 pkt.call_id = p->conn->call_id;
639 pkt.u.bind.max_xmit_frag = 5840;
640 pkt.u.bind.max_recv_frag = 5840;
641 pkt.u.bind.assoc_group_id = 0;
642 pkt.u.bind.num_contexts = 1;
643 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
644 if (!pkt.u.bind.ctx_list) {
645 return NT_STATUS_NO_MEMORY;
647 pkt.u.bind.ctx_list[0].context_id = p->context_id;
648 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
649 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
650 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
651 pkt.u.bind.auth_info = data_blob(NULL, 0);
653 /* construct the NDR form of the packet */
654 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
655 if (!NT_STATUS_IS_OK(status)) {
659 /* send it on its way */
660 status = full_request(p->conn, mem_ctx, &blob, &blob);
661 if (!NT_STATUS_IS_OK(status)) {
665 /* unmarshall the NDR */
666 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
667 if (!NT_STATUS_IS_OK(status)) {
671 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
672 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
673 return dcerpc_map_reason(pkt.u.bind_nak.reject_reason);
676 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
677 pkt.u.bind_ack.num_results == 0 ||
678 pkt.u.bind_ack.ctx_list[0].result != 0) {
679 return NT_STATUS_UNSUCCESSFUL;
682 p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
683 p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
685 /* the bind_ack might contain a reply set of credentials */
686 if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
687 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
689 p->conn->security_state.auth_info,
690 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
697 perform a continued bind (and auth3)
699 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
702 struct ncacn_packet pkt;
706 init_ncacn_hdr(c, &pkt);
708 pkt.ptype = DCERPC_PKT_AUTH3;
709 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
710 pkt.call_id = next_call_id(c);
712 pkt.u.auth3._pad = 0;
713 pkt.u.auth3.auth_info = data_blob(NULL, 0);
715 /* construct the NDR form of the packet */
716 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
717 if (!NT_STATUS_IS_OK(status)) {
721 /* send it on its way */
722 status = c->transport.send_request(c, &blob, False);
723 if (!NT_STATUS_IS_OK(status)) {
731 /* perform a dcerpc bind, using the uuid as the key */
732 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
734 const char *uuid, uint_t version)
736 struct dcerpc_syntax_id syntax;
737 struct dcerpc_syntax_id transfer_syntax;
740 status = GUID_from_string(uuid, &syntax.uuid);
741 if (!NT_STATUS_IS_OK(status)) {
742 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
745 syntax.if_version = version;
747 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
748 if (!NT_STATUS_IS_OK(status)) {
751 transfer_syntax.if_version = NDR_GUID_VERSION;
753 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
757 process a fragment received from the transport layer during a
760 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
764 struct ncacn_packet pkt;
765 struct rpc_request *req;
768 if (!NT_STATUS_IS_OK(status)) {
769 /* all pending requests get the error */
772 req->state = RPC_REQUEST_DONE;
773 req->status = status;
774 DLIST_REMOVE(c->pending, req);
775 if (req->async.callback) {
776 req->async.callback(req);
784 status = ncacn_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
786 /* find the matching request. Notice we match before we check
787 the status. this is ok as a pending call_id can never be
789 for (req=c->pending;req;req=req->next) {
790 if (pkt.call_id == req->call_id) break;
794 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
798 if (!NT_STATUS_IS_OK(status)) {
799 req->status = status;
800 req->state = RPC_REQUEST_DONE;
801 DLIST_REMOVE(c->pending, req);
802 if (req->async.callback) {
803 req->async.callback(req);
808 if (pkt.ptype == DCERPC_PKT_FAULT) {
809 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
810 req->fault_code = pkt.u.fault.status;
811 req->status = NT_STATUS_NET_WRITE_FAULT;
812 req->state = RPC_REQUEST_DONE;
813 DLIST_REMOVE(c->pending, req);
814 if (req->async.callback) {
815 req->async.callback(req);
820 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
821 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
823 req->fault_code = DCERPC_FAULT_OTHER;
824 req->status = NT_STATUS_NET_WRITE_FAULT;
825 req->state = RPC_REQUEST_DONE;
826 DLIST_REMOVE(c->pending, req);
827 if (req->async.callback) {
828 req->async.callback(req);
833 length = pkt.u.response.stub_and_verifier.length;
836 req->payload.data = talloc_realloc(req,
839 req->payload.length + length);
840 if (!req->payload.data) {
841 req->status = NT_STATUS_NO_MEMORY;
842 req->state = RPC_REQUEST_DONE;
843 DLIST_REMOVE(c->pending, req);
844 if (req->async.callback) {
845 req->async.callback(req);
849 memcpy(req->payload.data+req->payload.length,
850 pkt.u.response.stub_and_verifier.data, length);
851 req->payload.length += length;
854 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
855 c->transport.send_read(c);
859 /* we've got the full payload */
860 req->state = RPC_REQUEST_DONE;
861 DLIST_REMOVE(c->pending, req);
863 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
864 req->flags |= DCERPC_PULL_BIGENDIAN;
866 req->flags &= ~DCERPC_PULL_BIGENDIAN;
869 if (req->async.callback) {
870 req->async.callback(req);
875 handle timeouts of individual dcerpc requests
877 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
878 struct timeval t, void *private)
880 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
882 if (req->state != RPC_REQUEST_PENDING) {
886 req->status = NT_STATUS_IO_TIMEOUT;
887 req->state = RPC_REQUEST_DONE;
888 DLIST_REMOVE(req->p->conn->pending, req);
889 if (req->async.callback) {
890 req->async.callback(req);
896 make sure requests are cleaned up
898 static int dcerpc_req_destructor(void *ptr)
900 struct rpc_request *req = ptr;
901 DLIST_REMOVE(req->p->conn->pending, req);
906 perform the send side of a async dcerpc request
908 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
909 const struct GUID *object,
911 DATA_BLOB *stub_data)
913 struct rpc_request *req;
914 struct ncacn_packet pkt;
916 uint32_t remaining, chunk_size;
917 BOOL first_packet = True;
919 p->conn->transport.recv_data = dcerpc_request_recv_data;
921 req = talloc(p, struct rpc_request);
927 req->call_id = next_call_id(p->conn);
928 req->status = NT_STATUS_OK;
929 req->state = RPC_REQUEST_PENDING;
930 req->payload = data_blob(NULL, 0);
933 req->async.callback = NULL;
935 init_ncacn_hdr(p->conn, &pkt);
937 remaining = stub_data->length;
939 /* we can write a full max_recv_frag size, minus the dcerpc
940 request header size */
941 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
943 pkt.ptype = DCERPC_PKT_REQUEST;
944 pkt.call_id = req->call_id;
947 pkt.u.request.alloc_hint = remaining;
948 pkt.u.request.context_id = p->context_id;
949 pkt.u.request.opnum = opnum;
952 pkt.u.request.object.object = *object;
953 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
954 chunk_size -= ndr_size_GUID(object,0);
957 DLIST_ADD(p->conn->pending, req);
959 /* we send a series of pdus without waiting for a reply */
960 while (remaining > 0 || first_packet) {
961 uint32_t chunk = MIN(chunk_size, remaining);
962 BOOL last_frag = False;
964 first_packet = False;
965 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
967 if (remaining == stub_data->length) {
968 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
970 if (chunk == remaining) {
971 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
975 pkt.u.request.stub_and_verifier.data = stub_data->data +
976 (stub_data->length - remaining);
977 pkt.u.request.stub_and_verifier.length = chunk;
979 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
980 if (!NT_STATUS_IS_OK(req->status)) {
981 req->state = RPC_REQUEST_DONE;
982 DLIST_REMOVE(p->conn->pending, req);
986 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
987 if (!NT_STATUS_IS_OK(req->status)) {
988 req->state = RPC_REQUEST_DONE;
989 DLIST_REMOVE(p->conn->pending, req);
996 if (p->request_timeout) {
997 event_add_timed(dcerpc_event_context(p), req,
998 timeval_current_ofs(p->request_timeout, 0),
999 dcerpc_timeout_handler, req);
1002 talloc_set_destructor(req, dcerpc_req_destructor);
1008 return the event context for a dcerpc pipe
1009 used by callers who wish to operate asynchronously
1011 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1013 return p->conn->event_ctx;
1019 perform the receive side of a async dcerpc request
1021 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1022 TALLOC_CTX *mem_ctx,
1023 DATA_BLOB *stub_data)
1027 while (req->state == RPC_REQUEST_PENDING) {
1028 struct event_context *ctx = dcerpc_event_context(req->p);
1029 if (event_loop_once(ctx) != 0) {
1030 return NT_STATUS_CONNECTION_DISCONNECTED;
1033 *stub_data = req->payload;
1034 status = req->status;
1035 if (stub_data->data) {
1036 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1038 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1039 req->p->last_fault_code = req->fault_code;
1046 perform a full request/response pair on a dcerpc pipe
1048 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1049 struct GUID *object,
1051 TALLOC_CTX *mem_ctx,
1052 DATA_BLOB *stub_data_in,
1053 DATA_BLOB *stub_data_out)
1055 struct rpc_request *req;
1057 req = dcerpc_request_send(p, object, opnum, stub_data_in);
1059 return NT_STATUS_NO_MEMORY;
1062 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1067 this is a paranoid NDR validator. For every packet we push onto the wire
1068 we pull it back again, then push it again. Then we compare the raw NDR data
1069 for that to the NDR we initially generated. If they don't match then we know
1070 we must have a bug in either the pull or push side of our code
1072 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1073 TALLOC_CTX *mem_ctx,
1076 ndr_push_flags_fn_t ndr_push,
1077 ndr_pull_flags_fn_t ndr_pull)
1080 struct ndr_pull *pull;
1081 struct ndr_push *push;
1085 st = talloc_size(mem_ctx, struct_size);
1087 return NT_STATUS_NO_MEMORY;
1090 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1092 return NT_STATUS_NO_MEMORY;
1094 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1096 status = ndr_pull(pull, NDR_IN, st);
1097 if (!NT_STATUS_IS_OK(status)) {
1098 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1099 "failed input validation pull - %s",
1103 push = ndr_push_init_ctx(mem_ctx);
1105 return NT_STATUS_NO_MEMORY;
1108 status = ndr_push(push, NDR_IN, st);
1109 if (!NT_STATUS_IS_OK(status)) {
1110 return ndr_push_error(push, NDR_ERR_VALIDATE,
1111 "failed input validation push - %s",
1115 blob2 = ndr_push_blob(push);
1117 if (!data_blob_equal(&blob, &blob2)) {
1118 DEBUG(3,("original:\n"));
1119 dump_data(3, blob.data, blob.length);
1120 DEBUG(3,("secondary:\n"));
1121 dump_data(3, blob2.data, blob2.length);
1122 return ndr_push_error(push, NDR_ERR_VALIDATE,
1123 "failed input validation data - %s",
1127 return NT_STATUS_OK;
1131 this is a paranoid NDR input validator. For every packet we pull
1132 from the wire we push it back again then pull and push it
1133 again. Then we compare the raw NDR data for that to the NDR we
1134 initially generated. If they don't match then we know we must have a
1135 bug in either the pull or push side of our code
1137 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1138 TALLOC_CTX *mem_ctx,
1141 ndr_push_flags_fn_t ndr_push,
1142 ndr_pull_flags_fn_t ndr_pull)
1145 struct ndr_pull *pull;
1146 struct ndr_push *push;
1148 DATA_BLOB blob, blob2;
1150 st = talloc_size(mem_ctx, struct_size);
1152 return NT_STATUS_NO_MEMORY;
1154 memcpy(st, struct_ptr, struct_size);
1156 push = ndr_push_init_ctx(mem_ctx);
1158 return NT_STATUS_NO_MEMORY;
1161 status = ndr_push(push, NDR_OUT, struct_ptr);
1162 if (!NT_STATUS_IS_OK(status)) {
1163 return ndr_push_error(push, NDR_ERR_VALIDATE,
1164 "failed output validation push - %s",
1168 blob = ndr_push_blob(push);
1170 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1172 return NT_STATUS_NO_MEMORY;
1175 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1176 status = ndr_pull(pull, NDR_OUT, st);
1177 if (!NT_STATUS_IS_OK(status)) {
1178 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1179 "failed output validation pull - %s",
1183 push = ndr_push_init_ctx(mem_ctx);
1185 return NT_STATUS_NO_MEMORY;
1188 status = ndr_push(push, NDR_OUT, st);
1189 if (!NT_STATUS_IS_OK(status)) {
1190 return ndr_push_error(push, NDR_ERR_VALIDATE,
1191 "failed output validation push2 - %s",
1195 blob2 = ndr_push_blob(push);
1197 if (!data_blob_equal(&blob, &blob2)) {
1198 DEBUG(3,("original:\n"));
1199 dump_data(3, blob.data, blob.length);
1200 DEBUG(3,("secondary:\n"));
1201 dump_data(3, blob2.data, blob2.length);
1202 return ndr_push_error(push, NDR_ERR_VALIDATE,
1203 "failed output validation data - %s",
1207 return NT_STATUS_OK;
1212 send a rpc request given a dcerpc_call structure
1214 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1215 const struct GUID *object,
1216 const struct dcerpc_interface_table *table,
1218 TALLOC_CTX *mem_ctx,
1221 const struct dcerpc_interface_call *call;
1222 struct ndr_push *push;
1225 struct rpc_request *req;
1227 call = &table->calls[opnum];
1229 /* setup for a ndr_push_* call */
1230 push = ndr_push_init_ctx(mem_ctx);
1235 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1236 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1239 /* push the structure into a blob */
1240 status = call->ndr_push(push, NDR_IN, r);
1241 if (!NT_STATUS_IS_OK(status)) {
1242 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1243 nt_errstr(status)));
1248 /* retrieve the blob */
1249 request = ndr_push_blob(push);
1251 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1252 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1253 call->ndr_push, call->ndr_pull);
1254 if (!NT_STATUS_IS_OK(status)) {
1255 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1256 nt_errstr(status)));
1262 DEBUG(10,("rpc request data:\n"));
1263 dump_data(10, request.data, request.length);
1265 /* make the actual dcerpc request */
1266 req = dcerpc_request_send(p, object, opnum, &request);
1269 req->ndr.table = table;
1270 req->ndr.opnum = opnum;
1271 req->ndr.struct_ptr = r;
1272 req->ndr.mem_ctx = mem_ctx;
1281 receive the answer from a dcerpc_ndr_request_send()
1283 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1285 struct dcerpc_pipe *p = req->p;
1288 struct ndr_pull *pull;
1290 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1291 void *r = req->ndr.struct_ptr;
1292 uint32_t opnum = req->ndr.opnum;
1293 const struct dcerpc_interface_table *table = req->ndr.table;
1294 const struct dcerpc_interface_call *call = &table->calls[opnum];
1296 /* make sure the recv code doesn't free the request, as we
1297 need to grab the flags element before it is freed */
1298 talloc_increase_ref_count(req);
1300 status = dcerpc_request_recv(req, mem_ctx, &response);
1301 if (!NT_STATUS_IS_OK(status)) {
1307 /* prepare for ndr_pull_* */
1308 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1311 return NT_STATUS_NO_MEMORY;
1315 pull->data = talloc_steal(pull, pull->data);
1319 if (flags & DCERPC_PULL_BIGENDIAN) {
1320 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1323 DEBUG(10,("rpc reply data:\n"));
1324 dump_data(10, pull->data, pull->data_size);
1326 /* pull the structure from the blob */
1327 status = call->ndr_pull(pull, NDR_OUT, r);
1328 if (!NT_STATUS_IS_OK(status)) {
1329 dcerpc_log_packet(table, opnum, NDR_OUT,
1334 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1335 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1336 call->ndr_push, call->ndr_pull);
1337 if (!NT_STATUS_IS_OK(status)) {
1338 dcerpc_log_packet(table, opnum, NDR_OUT,
1344 if (pull->offset != pull->data_size) {
1345 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1346 pull->data_size - pull->offset));
1347 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1348 but it turns out that early versions of NT
1349 (specifically NT3.1) add junk onto the end of rpc
1350 packets, so if we want to interoperate at all with
1351 those versions then we need to ignore this error */
1354 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1356 return NT_STATUS_OK;
1361 a useful helper function for synchronous rpc requests
1363 this can be used when you have ndr push/pull functions in the
1366 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1367 const struct GUID *object,
1368 const struct dcerpc_interface_table *table,
1370 TALLOC_CTX *mem_ctx,
1373 struct rpc_request *req;
1375 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1377 return NT_STATUS_NO_MEMORY;
1380 return dcerpc_ndr_request_recv(req);
1385 a useful function for retrieving the server name we connected to
1387 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1389 if (!p->conn->transport.peer_name) {
1392 return p->conn->transport.peer_name(p->conn);
1397 get the dcerpc auth_level for a open connection
1399 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1403 if (c->flags & DCERPC_SEAL) {
1404 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1405 } else if (c->flags & DCERPC_SIGN) {
1406 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1407 } else if (c->flags & DCERPC_CONNECT) {
1408 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1410 auth_level = DCERPC_AUTH_LEVEL_NONE;
1417 send a dcerpc alter_context request
1419 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1420 TALLOC_CTX *mem_ctx,
1421 const struct dcerpc_syntax_id *syntax,
1422 const struct dcerpc_syntax_id *transfer_syntax)
1424 struct ncacn_packet pkt;
1428 p->syntax = *syntax;
1429 p->transfer_syntax = *transfer_syntax;
1431 init_ncacn_hdr(p->conn, &pkt);
1433 pkt.ptype = DCERPC_PKT_ALTER;
1434 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1435 pkt.call_id = p->conn->call_id;
1436 pkt.auth_length = 0;
1438 pkt.u.alter.max_xmit_frag = 5840;
1439 pkt.u.alter.max_recv_frag = 5840;
1440 pkt.u.alter.assoc_group_id = 0;
1441 pkt.u.alter.num_contexts = 1;
1442 pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1443 if (!pkt.u.alter.ctx_list) {
1444 return NT_STATUS_NO_MEMORY;
1446 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1447 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1448 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1449 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1450 pkt.u.alter.auth_info = data_blob(NULL, 0);
1452 /* construct the NDR form of the packet */
1453 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1454 if (!NT_STATUS_IS_OK(status)) {
1458 /* send it on its way */
1459 status = full_request(p->conn, mem_ctx, &blob, &blob);
1460 if (!NT_STATUS_IS_OK(status)) {
1464 /* unmarshall the NDR */
1465 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
1466 if (!NT_STATUS_IS_OK(status)) {
1470 if (pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1471 pkt.u.alter_resp.num_results == 1 &&
1472 pkt.u.alter_resp.ctx_list[0].result != 0) {
1473 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1474 pkt.u.alter_resp.ctx_list[0].reason));
1475 return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason);
1478 if (pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1479 pkt.u.alter_resp.num_results == 0 ||
1480 pkt.u.alter_resp.ctx_list[0].result != 0) {
1481 return NT_STATUS_UNSUCCESSFUL;
1484 /* the alter_resp might contain a reply set of credentials */
1485 if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) {
1486 status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info,
1488 p->conn->security_state.auth_info,
1489 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);