2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/gen_ndr/ndr_epmapper.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "libcli/composite/composite.h"
32 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
34 static struct dcerpc_interface_list *dcerpc_pipes = NULL;
37 register a dcerpc client interface
39 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
41 struct dcerpc_interface_list *l = talloc(talloc_autofree_context(),
42 struct dcerpc_interface_list);
44 if (idl_iface_by_name (interface->name) != NULL) {
45 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
46 return NT_STATUS_OBJECT_NAME_COLLISION;
50 DLIST_ADD(dcerpc_pipes, l);
56 return the list of registered dcerpc_pipes
58 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
63 /* destroy a dcerpc connection */
64 static int dcerpc_connection_destructor(void *ptr)
66 struct dcerpc_connection *c = ptr;
67 if (c->transport.shutdown_pipe) {
68 c->transport.shutdown_pipe(c);
74 /* initialise a dcerpc connection.
75 the event context is optional
77 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
78 struct event_context *ev)
80 struct dcerpc_connection *c;
82 c = talloc_zero(mem_ctx, struct dcerpc_connection);
88 ev = event_context_init(c);
97 c->security_state.auth_info = NULL;
98 c->security_state.session_key = dcerpc_generic_session_key;
99 c->security_state.generic_state = NULL;
100 c->binding_string = NULL;
102 c->srv_max_xmit_frag = 0;
103 c->srv_max_recv_frag = 0;
106 talloc_set_destructor(c, dcerpc_connection_destructor);
111 /* initialise a dcerpc pipe. */
112 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
114 struct dcerpc_pipe *p;
116 p = talloc(mem_ctx, struct dcerpc_pipe);
121 p->conn = dcerpc_connection_init(p, ev);
122 if (p->conn == NULL) {
127 p->last_fault_code = 0;
129 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
131 ZERO_STRUCT(p->syntax);
132 ZERO_STRUCT(p->transfer_syntax);
139 choose the next call id to use
141 static uint32_t next_call_id(struct dcerpc_connection *c)
144 if (c->call_id == 0) {
150 /* we need to be able to get/set the fragment length without doing a full
152 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
154 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
155 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
157 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
161 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
163 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
164 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
166 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
170 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
172 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
173 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
175 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
181 setup for a ndr pull, also setting up any flags from the binding string
183 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
184 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
186 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
188 if (ndr == NULL) return ndr;
190 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
191 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
194 if (c->flags & DCERPC_NDR_REF_ALLOC) {
195 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
202 parse a data blob into a ncacn_packet structure. This handles both
203 input and output packets
205 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
206 struct ncacn_packet *pkt)
208 struct ndr_pull *ndr;
210 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
212 return NT_STATUS_NO_MEMORY;
215 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
216 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
219 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
223 generate a CONNECT level verifier
225 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
227 *blob = data_blob_talloc(mem_ctx, NULL, 16);
228 if (blob->data == NULL) {
229 return NT_STATUS_NO_MEMORY;
231 SIVAL(blob->data, 0, 1);
232 memset(blob->data+4, 0, 12);
237 check a CONNECT level verifier
239 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
241 if (blob->length != 16 ||
242 IVAL(blob->data, 0) != 1) {
243 return NT_STATUS_ACCESS_DENIED;
249 parse a possibly signed blob into a dcerpc request packet structure
251 static NTSTATUS ncacn_pull_request_sign(struct dcerpc_connection *c,
252 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
253 struct ncacn_packet *pkt)
255 struct ndr_pull *ndr;
257 struct dcerpc_auth auth;
260 /* non-signed packets are simpler */
261 if (!c->security_state.auth_info ||
262 !c->security_state.generic_state) {
263 return ncacn_pull(c, blob, mem_ctx, pkt);
266 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
268 return NT_STATUS_NO_MEMORY;
271 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
272 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
275 /* pull the basic packet */
276 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
277 if (!NT_STATUS_IS_OK(status)) {
281 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
285 if (pkt->auth_length == 0 &&
286 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
290 auth_blob.length = 8 + pkt->auth_length;
292 /* check for a valid length */
293 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
294 return NT_STATUS_INFO_LENGTH_MISMATCH;
298 pkt->u.response.stub_and_verifier.data +
299 pkt->u.response.stub_and_verifier.length - auth_blob.length;
300 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
302 /* pull the auth structure */
303 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
305 return NT_STATUS_NO_MEMORY;
308 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
309 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
312 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
313 if (!NT_STATUS_IS_OK(status)) {
318 /* check signature or unseal the packet */
319 switch (c->security_state.auth_info->auth_level) {
320 case DCERPC_AUTH_LEVEL_PRIVACY:
321 status = gensec_unseal_packet(c->security_state.generic_state,
323 blob->data + DCERPC_REQUEST_LENGTH,
324 pkt->u.response.stub_and_verifier.length,
326 blob->length - auth.credentials.length,
328 memcpy(pkt->u.response.stub_and_verifier.data,
329 blob->data + DCERPC_REQUEST_LENGTH,
330 pkt->u.response.stub_and_verifier.length);
333 case DCERPC_AUTH_LEVEL_INTEGRITY:
334 status = gensec_check_packet(c->security_state.generic_state,
336 pkt->u.response.stub_and_verifier.data,
337 pkt->u.response.stub_and_verifier.length,
339 blob->length - auth.credentials.length,
343 case DCERPC_AUTH_LEVEL_CONNECT:
344 status = dcerpc_check_connect_verifier(&auth.credentials);
347 case DCERPC_AUTH_LEVEL_NONE:
351 status = NT_STATUS_INVALID_LEVEL;
355 /* remove the indicated amount of paddiing */
356 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
357 return NT_STATUS_INFO_LENGTH_MISMATCH;
359 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
366 push a dcerpc request packet into a blob, possibly signing it.
368 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
369 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
370 struct ncacn_packet *pkt)
373 struct ndr_push *ndr;
375 size_t payload_length;
377 /* non-signed packets are simpler */
378 if (!c->security_state.auth_info ||
379 !c->security_state.generic_state) {
380 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
383 ndr = ndr_push_init_ctx(mem_ctx);
385 return NT_STATUS_NO_MEMORY;
388 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
389 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
392 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
393 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
396 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
397 if (!NT_STATUS_IS_OK(status)) {
401 /* pad to 16 byte multiple in the payload portion of the
402 packet. This matches what w2k3 does */
403 c->security_state.auth_info->auth_pad_length =
404 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
405 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
407 payload_length = pkt->u.request.stub_and_verifier.length +
408 c->security_state.auth_info->auth_pad_length;
410 /* sign or seal the packet */
411 switch (c->security_state.auth_info->auth_level) {
412 case DCERPC_AUTH_LEVEL_PRIVACY:
413 case DCERPC_AUTH_LEVEL_INTEGRITY:
414 c->security_state.auth_info->credentials
415 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
417 data_blob_clear(&c->security_state.auth_info->credentials);
420 case DCERPC_AUTH_LEVEL_CONNECT:
421 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
424 case DCERPC_AUTH_LEVEL_NONE:
425 c->security_state.auth_info->credentials = data_blob(NULL, 0);
429 status = NT_STATUS_INVALID_LEVEL;
433 if (!NT_STATUS_IS_OK(status)) {
437 /* add the auth verifier */
438 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
439 if (!NT_STATUS_IS_OK(status)) {
443 /* extract the whole packet as a blob */
444 *blob = ndr_push_blob(ndr);
446 /* fill in the fragment length and auth_length, we can't fill
447 in these earlier as we don't know the signature length (it
448 could be variable length) */
449 dcerpc_set_frag_length(blob, blob->length);
450 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
452 /* sign or seal the packet */
453 switch (c->security_state.auth_info->auth_level) {
454 case DCERPC_AUTH_LEVEL_PRIVACY:
455 status = gensec_seal_packet(c->security_state.generic_state,
457 blob->data + DCERPC_REQUEST_LENGTH,
461 c->security_state.auth_info->credentials.length,
463 if (!NT_STATUS_IS_OK(status)) {
466 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
469 case DCERPC_AUTH_LEVEL_INTEGRITY:
470 status = gensec_sign_packet(c->security_state.generic_state,
472 blob->data + DCERPC_REQUEST_LENGTH,
476 c->security_state.auth_info->credentials.length,
478 if (!NT_STATUS_IS_OK(status)) {
481 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
484 case DCERPC_AUTH_LEVEL_CONNECT:
487 case DCERPC_AUTH_LEVEL_NONE:
488 c->security_state.auth_info->credentials = data_blob(NULL, 0);
492 status = NT_STATUS_INVALID_LEVEL;
496 data_blob_free(&c->security_state.auth_info->credentials);
503 fill in the fixed values in a dcerpc header
505 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
508 pkt->rpc_vers_minor = 0;
509 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
512 pkt->drep[0] = DCERPC_DREP_LE;
520 map a bind nak reason to a NTSTATUS
522 static NTSTATUS dcerpc_map_reason(uint16_t reason)
525 case DCERPC_BIND_REASON_ASYNTAX:
526 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
528 return NT_STATUS_UNSUCCESSFUL;
531 struct dcerpc_request_state {
532 struct dcerpc_pipe *pipe;
533 struct ncacn_packet pkt;
538 Receive a bind reply from the transport
541 static void bind_request_recv(struct dcerpc_connection *conn, DATA_BLOB *blob,
544 struct composite_context *c;
545 struct dcerpc_request_state *state;
547 if (conn->full_request_private == NULL) {
548 /* it timed out earlier */
551 c = talloc_get_type(conn->full_request_private,
552 struct composite_context);
553 state = talloc_get_type(c->private_data, struct dcerpc_request_state);
555 if (!NT_STATUS_IS_OK(status)) {
556 composite_error(c, status);
560 c->status = ncacn_pull(conn, blob, state, &state->pkt);
561 if (!composite_is_ok(c)) return;
563 if (state->pkt.ptype == DCERPC_PKT_BIND_NAK) {
564 DEBUG(2,("dcerpc: bind_nak reason %d\n",
565 state->pkt.u.bind_nak.reject_reason));
566 composite_error(c, dcerpc_map_reason(state->pkt.u.bind_nak.
571 if ((state->pkt.ptype != DCERPC_PKT_BIND_ACK) ||
572 (state->pkt.u.bind_ack.num_results == 0) ||
573 (state->pkt.u.bind_ack.ctx_list[0].result != 0)) {
574 composite_error(c, NT_STATUS_UNSUCCESSFUL);
578 conn->srv_max_xmit_frag = state->pkt.u.bind_ack.max_xmit_frag;
579 conn->srv_max_recv_frag = state->pkt.u.bind_ack.max_recv_frag;
581 /* the bind_ack might contain a reply set of credentials */
582 if (conn->security_state.auth_info &&
583 state->pkt.u.bind_ack.auth_info.length) {
584 c->status = ndr_pull_struct_blob(
585 &state->pkt.u.bind_ack.auth_info, state,
586 conn->security_state.auth_info,
587 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
588 if (!composite_is_ok(c)) return;
595 handle timeouts of dcerpc bind and alter context requests
597 static void bind_timeout_handler(struct event_context *ev,
598 struct timed_event *te,
599 struct timeval t, void *private)
601 struct composite_context *ctx =
602 talloc_get_type(private, struct composite_context);
603 struct dcerpc_request_state *state =
604 talloc_get_type(ctx->private_data,
605 struct dcerpc_request_state);
607 SMB_ASSERT(state->pipe->conn->full_request_private != NULL);
608 state->pipe->conn->full_request_private = NULL;
609 composite_error(ctx, NT_STATUS_IO_TIMEOUT);
612 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
614 const struct dcerpc_syntax_id *syntax,
615 const struct dcerpc_syntax_id *transfer_syntax)
617 struct composite_context *c;
618 struct dcerpc_request_state *state;
620 c = talloc_zero(mem_ctx, struct composite_context);
621 if (c == NULL) return NULL;
623 state = talloc(c, struct dcerpc_request_state);
625 c->status = NT_STATUS_NO_MEMORY;
629 c->state = COMPOSITE_STATE_IN_PROGRESS;
630 c->private_data = state;
631 c->event_ctx = p->conn->event_ctx;
636 p->transfer_syntax = *transfer_syntax;
638 init_ncacn_hdr(p->conn, &state->pkt);
640 state->pkt.ptype = DCERPC_PKT_BIND;
641 state->pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
642 state->pkt.call_id = p->conn->call_id;
643 state->pkt.auth_length = 0;
645 state->pkt.u.bind.max_xmit_frag = 5840;
646 state->pkt.u.bind.max_recv_frag = 5840;
647 state->pkt.u.bind.assoc_group_id = 0;
648 state->pkt.u.bind.num_contexts = 1;
649 state->pkt.u.bind.ctx_list =
650 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
651 if (state->pkt.u.bind.ctx_list == NULL) {
652 c->status = NT_STATUS_NO_MEMORY;
655 state->pkt.u.bind.ctx_list[0].context_id = p->context_id;
656 state->pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
657 state->pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
658 state->pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
659 state->pkt.u.bind.auth_info = data_blob(NULL, 0);
661 /* construct the NDR form of the packet */
662 c->status = ncacn_push_auth(&state->blob, mem_ctx, &state->pkt,
663 p->conn->security_state.auth_info);
664 if (!NT_STATUS_IS_OK(c->status)) {
668 p->conn->transport.recv_data = bind_request_recv;
669 p->conn->full_request_private = c;
671 c->status = p->conn->transport.send_request(p->conn, &state->blob,
673 if (!NT_STATUS_IS_OK(c->status)) {
677 event_add_timed(c->event_ctx, c,
678 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
679 bind_timeout_handler, c);
684 composite_trigger_error(c);
688 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
690 NTSTATUS result = composite_wait(ctx);
696 perform a bind using the given syntax
698 the auth_info structure is updated with the reply authentication info
701 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
703 const struct dcerpc_syntax_id *syntax,
704 const struct dcerpc_syntax_id *transfer_syntax)
706 struct composite_context *creq;
707 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
708 return dcerpc_bind_recv(creq);
712 perform a continued bind (and auth3)
714 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
717 struct ncacn_packet pkt;
721 init_ncacn_hdr(c, &pkt);
723 pkt.ptype = DCERPC_PKT_AUTH3;
724 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
725 pkt.call_id = next_call_id(c);
727 pkt.u.auth3._pad = 0;
728 pkt.u.auth3.auth_info = data_blob(NULL, 0);
730 /* construct the NDR form of the packet */
731 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
732 if (!NT_STATUS_IS_OK(status)) {
736 /* send it on its way */
737 status = c->transport.send_request(c, &blob, False);
738 if (!NT_STATUS_IS_OK(status)) {
746 NTSTATUS dcerpc_init_syntaxes(const char *uuid,
747 struct dcerpc_syntax_id *syntax,
748 struct dcerpc_syntax_id *transfer_syntax,
753 status = GUID_from_string(uuid, &syntax->uuid);
754 if (!NT_STATUS_IS_OK(status)) return status;
756 syntax->if_version = version;
758 status = GUID_from_string(NDR_GUID, &transfer_syntax->uuid);
759 if (!NT_STATUS_IS_OK(status)) return status;
761 transfer_syntax->if_version = NDR_GUID_VERSION;
766 /* perform a dcerpc bind, using the uuid as the key */
767 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
769 const char *uuid, uint_t version)
771 struct dcerpc_syntax_id syntax;
772 struct dcerpc_syntax_id transfer_syntax;
775 status = dcerpc_init_syntaxes(uuid, &syntax, &transfer_syntax,
777 if (!NT_STATUS_IS_OK(status)) {
778 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
782 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
787 process a fragment received from the transport layer during a
790 This function frees the data
792 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
796 struct ncacn_packet pkt;
797 struct rpc_request *req;
800 if (!NT_STATUS_IS_OK(status)) {
801 data_blob_free(data);
803 /* all pending requests get the error */
806 req->state = RPC_REQUEST_DONE;
807 req->status = status;
808 DLIST_REMOVE(c->pending, req);
809 if (req->async.callback) {
810 req->async.callback(req);
818 status = ncacn_pull_request_sign(c, data, data->data, &pkt);
820 /* find the matching request. Notice we match before we check
821 the status. this is ok as a pending call_id can never be
823 for (req=c->pending;req;req=req->next) {
824 if (pkt.call_id == req->call_id) break;
828 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
829 data_blob_free(data);
833 if (!NT_STATUS_IS_OK(status)) {
834 req->status = status;
838 if (pkt.ptype == DCERPC_PKT_FAULT) {
839 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
840 req->fault_code = pkt.u.fault.status;
841 req->status = NT_STATUS_NET_WRITE_FAULT;
845 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
846 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
848 req->fault_code = DCERPC_FAULT_OTHER;
849 req->status = NT_STATUS_NET_WRITE_FAULT;
853 length = pkt.u.response.stub_and_verifier.length;
856 req->payload.data = talloc_realloc(req,
859 req->payload.length + length);
860 if (!req->payload.data) {
861 req->status = NT_STATUS_NO_MEMORY;
864 memcpy(req->payload.data+req->payload.length,
865 pkt.u.response.stub_and_verifier.data, length);
866 req->payload.length += length;
869 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
870 c->transport.send_read(c);
871 data_blob_free(data);
875 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
876 req->flags |= DCERPC_PULL_BIGENDIAN;
878 req->flags &= ~DCERPC_PULL_BIGENDIAN;
883 /* we've got the full payload */
884 req->state = RPC_REQUEST_DONE;
885 DLIST_REMOVE(c->pending, req);
886 data_blob_free(data);
888 if (c->request_queue != NULL) {
889 /* We have to look at shipping further requests before calling
890 * the async function, that one might close the pipe */
891 dcerpc_ship_next_request(c);
894 if (req->async.callback) {
895 req->async.callback(req);
900 handle timeouts of individual dcerpc requests
902 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
903 struct timeval t, void *private)
905 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
907 if (req->state != RPC_REQUEST_PENDING) {
911 req->status = NT_STATUS_IO_TIMEOUT;
912 req->state = RPC_REQUEST_DONE;
913 DLIST_REMOVE(req->p->conn->pending, req);
914 if (req->async.callback) {
915 req->async.callback(req);
921 make sure requests are cleaned up
923 static int dcerpc_req_destructor(void *ptr)
925 struct rpc_request *req = ptr;
926 DLIST_REMOVE(req->p->conn->pending, req);
931 perform the send side of a async dcerpc request
933 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
934 const struct GUID *object,
937 DATA_BLOB *stub_data)
939 struct rpc_request *req;
941 p->conn->transport.recv_data = dcerpc_request_recv_data;
943 req = talloc(p, struct rpc_request);
949 req->call_id = next_call_id(p->conn);
950 req->status = NT_STATUS_OK;
951 req->state = RPC_REQUEST_PENDING;
952 req->payload = data_blob(NULL, 0);
955 req->async_call = async;
956 req->async.callback = NULL;
958 if (object != NULL) {
959 req->object = talloc_memdup(req, object, sizeof(*object));
960 if (req->object == NULL) {
969 req->request_data.length = stub_data->length;
970 req->request_data.data = talloc_reference(req, stub_data->data);
971 if (req->request_data.data == NULL) {
975 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
977 dcerpc_ship_next_request(p->conn);
979 if (p->request_timeout) {
980 event_add_timed(dcerpc_event_context(p), req,
981 timeval_current_ofs(p->request_timeout, 0),
982 dcerpc_timeout_handler, req);
985 talloc_set_destructor(req, dcerpc_req_destructor);
990 Send a request using the transport
993 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
995 struct rpc_request *req;
996 struct dcerpc_pipe *p;
997 DATA_BLOB *stub_data;
998 struct ncacn_packet pkt;
1000 uint32_t remaining, chunk_size;
1001 BOOL first_packet = True;
1003 req = c->request_queue;
1009 stub_data = &req->request_data;
1011 if (!req->async_call && (c->pending != NULL)) {
1015 DLIST_REMOVE(c->request_queue, req);
1016 DLIST_ADD(c->pending, req);
1018 init_ncacn_hdr(p->conn, &pkt);
1020 remaining = stub_data->length;
1022 /* we can write a full max_recv_frag size, minus the dcerpc
1023 request header size */
1024 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1026 pkt.ptype = DCERPC_PKT_REQUEST;
1027 pkt.call_id = req->call_id;
1028 pkt.auth_length = 0;
1030 pkt.u.request.alloc_hint = remaining;
1031 pkt.u.request.context_id = p->context_id;
1032 pkt.u.request.opnum = req->opnum;
1035 pkt.u.request.object.object = *req->object;
1036 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1037 chunk_size -= ndr_size_GUID(req->object,0);
1040 /* we send a series of pdus without waiting for a reply */
1041 while (remaining > 0 || first_packet) {
1042 uint32_t chunk = MIN(chunk_size, remaining);
1043 BOOL last_frag = False;
1045 first_packet = False;
1046 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1048 if (remaining == stub_data->length) {
1049 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1051 if (chunk == remaining) {
1052 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1056 pkt.u.request.stub_and_verifier.data = stub_data->data +
1057 (stub_data->length - remaining);
1058 pkt.u.request.stub_and_verifier.length = chunk;
1060 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1061 if (!NT_STATUS_IS_OK(req->status)) {
1062 req->state = RPC_REQUEST_DONE;
1063 DLIST_REMOVE(p->conn->pending, req);
1067 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1068 if (!NT_STATUS_IS_OK(req->status)) {
1069 req->state = RPC_REQUEST_DONE;
1070 DLIST_REMOVE(p->conn->pending, req);
1079 return the event context for a dcerpc pipe
1080 used by callers who wish to operate asynchronously
1082 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1084 return p->conn->event_ctx;
1090 perform the receive side of a async dcerpc request
1092 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1093 TALLOC_CTX *mem_ctx,
1094 DATA_BLOB *stub_data)
1098 while (req->state == RPC_REQUEST_PENDING) {
1099 struct event_context *ctx = dcerpc_event_context(req->p);
1100 if (event_loop_once(ctx) != 0) {
1101 return NT_STATUS_CONNECTION_DISCONNECTED;
1104 *stub_data = req->payload;
1105 status = req->status;
1106 if (stub_data->data) {
1107 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1109 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1110 req->p->last_fault_code = req->fault_code;
1117 perform a full request/response pair on a dcerpc pipe
1119 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1120 struct GUID *object,
1123 TALLOC_CTX *mem_ctx,
1124 DATA_BLOB *stub_data_in,
1125 DATA_BLOB *stub_data_out)
1127 struct rpc_request *req;
1129 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1131 return NT_STATUS_NO_MEMORY;
1134 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1139 this is a paranoid NDR validator. For every packet we push onto the wire
1140 we pull it back again, then push it again. Then we compare the raw NDR data
1141 for that to the NDR we initially generated. If they don't match then we know
1142 we must have a bug in either the pull or push side of our code
1144 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1145 TALLOC_CTX *mem_ctx,
1148 ndr_push_flags_fn_t ndr_push,
1149 ndr_pull_flags_fn_t ndr_pull)
1152 struct ndr_pull *pull;
1153 struct ndr_push *push;
1157 st = talloc_size(mem_ctx, struct_size);
1159 return NT_STATUS_NO_MEMORY;
1162 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1164 return NT_STATUS_NO_MEMORY;
1166 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1168 status = ndr_pull(pull, NDR_IN, st);
1169 if (!NT_STATUS_IS_OK(status)) {
1170 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1171 "failed input validation pull - %s",
1175 push = ndr_push_init_ctx(mem_ctx);
1177 return NT_STATUS_NO_MEMORY;
1180 status = ndr_push(push, NDR_IN, st);
1181 if (!NT_STATUS_IS_OK(status)) {
1182 return ndr_push_error(push, NDR_ERR_VALIDATE,
1183 "failed input validation push - %s",
1187 blob2 = ndr_push_blob(push);
1189 if (!data_blob_equal(&blob, &blob2)) {
1190 DEBUG(3,("original:\n"));
1191 dump_data(3, blob.data, blob.length);
1192 DEBUG(3,("secondary:\n"));
1193 dump_data(3, blob2.data, blob2.length);
1194 return ndr_push_error(push, NDR_ERR_VALIDATE,
1195 "failed input validation data - %s",
1199 return NT_STATUS_OK;
1203 this is a paranoid NDR input validator. For every packet we pull
1204 from the wire we push it back again then pull and push it
1205 again. Then we compare the raw NDR data for that to the NDR we
1206 initially generated. If they don't match then we know we must have a
1207 bug in either the pull or push side of our code
1209 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1210 TALLOC_CTX *mem_ctx,
1213 ndr_push_flags_fn_t ndr_push,
1214 ndr_pull_flags_fn_t ndr_pull)
1217 struct ndr_pull *pull;
1218 struct ndr_push *push;
1220 DATA_BLOB blob, blob2;
1222 st = talloc_size(mem_ctx, struct_size);
1224 return NT_STATUS_NO_MEMORY;
1226 memcpy(st, struct_ptr, struct_size);
1228 push = ndr_push_init_ctx(mem_ctx);
1230 return NT_STATUS_NO_MEMORY;
1233 status = ndr_push(push, NDR_OUT, struct_ptr);
1234 if (!NT_STATUS_IS_OK(status)) {
1235 return ndr_push_error(push, NDR_ERR_VALIDATE,
1236 "failed output validation push - %s",
1240 blob = ndr_push_blob(push);
1242 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1244 return NT_STATUS_NO_MEMORY;
1247 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1248 status = ndr_pull(pull, NDR_OUT, st);
1249 if (!NT_STATUS_IS_OK(status)) {
1250 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1251 "failed output validation pull - %s",
1255 push = ndr_push_init_ctx(mem_ctx);
1257 return NT_STATUS_NO_MEMORY;
1260 status = ndr_push(push, NDR_OUT, st);
1261 if (!NT_STATUS_IS_OK(status)) {
1262 return ndr_push_error(push, NDR_ERR_VALIDATE,
1263 "failed output validation push2 - %s",
1267 blob2 = ndr_push_blob(push);
1269 if (!data_blob_equal(&blob, &blob2)) {
1270 DEBUG(3,("original:\n"));
1271 dump_data(3, blob.data, blob.length);
1272 DEBUG(3,("secondary:\n"));
1273 dump_data(3, blob2.data, blob2.length);
1274 return ndr_push_error(push, NDR_ERR_VALIDATE,
1275 "failed output validation data - %s",
1279 return NT_STATUS_OK;
1284 send a rpc request given a dcerpc_call structure
1286 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1287 const struct GUID *object,
1288 const struct dcerpc_interface_table *table,
1290 TALLOC_CTX *mem_ctx,
1293 const struct dcerpc_interface_call *call;
1294 struct ndr_push *push;
1297 struct rpc_request *req;
1299 call = &table->calls[opnum];
1301 /* setup for a ndr_push_* call */
1302 push = ndr_push_init_ctx(mem_ctx);
1307 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1308 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1311 /* push the structure into a blob */
1312 status = call->ndr_push(push, NDR_IN, r);
1313 if (!NT_STATUS_IS_OK(status)) {
1314 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1315 nt_errstr(status)));
1320 /* retrieve the blob */
1321 request = ndr_push_blob(push);
1323 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1324 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1325 call->ndr_push, call->ndr_pull);
1326 if (!NT_STATUS_IS_OK(status)) {
1327 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1328 nt_errstr(status)));
1334 DEBUG(10,("rpc request data:\n"));
1335 dump_data(10, request.data, request.length);
1337 /* make the actual dcerpc request */
1338 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1342 req->ndr.table = table;
1343 req->ndr.opnum = opnum;
1344 req->ndr.struct_ptr = r;
1345 req->ndr.mem_ctx = mem_ctx;
1354 receive the answer from a dcerpc_ndr_request_send()
1356 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1358 struct dcerpc_pipe *p = req->p;
1361 struct ndr_pull *pull;
1363 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1364 void *r = req->ndr.struct_ptr;
1365 uint32_t opnum = req->ndr.opnum;
1366 const struct dcerpc_interface_table *table = req->ndr.table;
1367 const struct dcerpc_interface_call *call = &table->calls[opnum];
1369 /* make sure the recv code doesn't free the request, as we
1370 need to grab the flags element before it is freed */
1371 talloc_increase_ref_count(req);
1373 status = dcerpc_request_recv(req, mem_ctx, &response);
1374 if (!NT_STATUS_IS_OK(status)) {
1380 /* prepare for ndr_pull_* */
1381 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1384 return NT_STATUS_NO_MEMORY;
1388 pull->data = talloc_steal(pull, pull->data);
1392 if (flags & DCERPC_PULL_BIGENDIAN) {
1393 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1396 DEBUG(10,("rpc reply data:\n"));
1397 dump_data(10, pull->data, pull->data_size);
1399 /* pull the structure from the blob */
1400 status = call->ndr_pull(pull, NDR_OUT, r);
1401 if (!NT_STATUS_IS_OK(status)) {
1402 dcerpc_log_packet(table, opnum, NDR_OUT,
1407 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1408 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1409 call->ndr_push, call->ndr_pull);
1410 if (!NT_STATUS_IS_OK(status)) {
1411 dcerpc_log_packet(table, opnum, NDR_OUT,
1417 if (pull->offset != pull->data_size) {
1418 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1419 pull->data_size - pull->offset));
1420 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1421 but it turns out that early versions of NT
1422 (specifically NT3.1) add junk onto the end of rpc
1423 packets, so if we want to interoperate at all with
1424 those versions then we need to ignore this error */
1427 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1429 return NT_STATUS_OK;
1434 a useful helper function for synchronous rpc requests
1436 this can be used when you have ndr push/pull functions in the
1439 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1440 const struct GUID *object,
1441 const struct dcerpc_interface_table *table,
1443 TALLOC_CTX *mem_ctx,
1446 struct rpc_request *req;
1448 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1450 return NT_STATUS_NO_MEMORY;
1453 return dcerpc_ndr_request_recv(req);
1458 a useful function for retrieving the server name we connected to
1460 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1462 if (!p->conn->transport.peer_name) {
1465 return p->conn->transport.peer_name(p->conn);
1470 get the dcerpc auth_level for a open connection
1472 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1476 if (c->flags & DCERPC_SEAL) {
1477 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1478 } else if (c->flags & DCERPC_SIGN) {
1479 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1480 } else if (c->flags & DCERPC_CONNECT) {
1481 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1483 auth_level = DCERPC_AUTH_LEVEL_NONE;
1489 Receive an alter reply from the transport
1491 static void alter_request_recv(struct dcerpc_connection *conn, DATA_BLOB *blob,
1494 struct composite_context *c;
1495 struct dcerpc_request_state *state;
1497 if (conn->full_request_private == NULL) {
1498 /* it timed out earlier */
1502 c = talloc_get_type(conn->full_request_private,
1503 struct composite_context);
1504 state = talloc_get_type(c->private_data, struct dcerpc_request_state);
1506 if (!NT_STATUS_IS_OK(status)) {
1507 composite_error(c, status);
1511 /* unmarshall the NDR */
1512 c->status = ncacn_pull(state->pipe->conn, blob, state, &state->pkt);
1513 if (!composite_is_ok(c)) return;
1515 if (state->pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1516 state->pkt.u.alter_resp.num_results == 1 &&
1517 state->pkt.u.alter_resp.ctx_list[0].result != 0) {
1518 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1519 state->pkt.u.alter_resp.ctx_list[0].reason));
1520 composite_error(c, dcerpc_map_reason(state->pkt.u.alter_resp.ctx_list[0].reason));
1524 if (state->pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1525 state->pkt.u.alter_resp.num_results == 0 ||
1526 state->pkt.u.alter_resp.ctx_list[0].result != 0) {
1527 composite_error(c, NT_STATUS_UNSUCCESSFUL);
1531 /* the alter_resp might contain a reply set of credentials */
1532 if (state->pipe->conn->security_state.auth_info &&
1533 state->pkt.u.alter_resp.auth_info.length) {
1534 c->status = ndr_pull_struct_blob(
1535 &state->pkt.u.alter_resp.auth_info, state,
1536 state->pipe->conn->security_state.auth_info,
1537 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1538 if (!composite_is_ok(c)) return;
1545 send a dcerpc alter_context request
1547 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1548 TALLOC_CTX *mem_ctx,
1549 const struct dcerpc_syntax_id *syntax,
1550 const struct dcerpc_syntax_id *transfer_syntax)
1552 struct composite_context *c;
1553 struct dcerpc_request_state *state;
1555 c = talloc_zero(mem_ctx, struct composite_context);
1556 if (c == NULL) return NULL;
1558 state = talloc(c, struct dcerpc_request_state);
1559 if (state == NULL) {
1560 c->status = NT_STATUS_NO_MEMORY;
1564 c->state = COMPOSITE_STATE_IN_PROGRESS;
1565 c->private_data = state;
1566 c->event_ctx = p->conn->event_ctx;
1570 p->syntax = *syntax;
1571 p->transfer_syntax = *transfer_syntax;
1573 init_ncacn_hdr(p->conn, &state->pkt);
1575 state->pkt.ptype = DCERPC_PKT_ALTER;
1576 state->pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1577 state->pkt.call_id = p->conn->call_id;
1578 state->pkt.auth_length = 0;
1580 state->pkt.u.alter.max_xmit_frag = 5840;
1581 state->pkt.u.alter.max_recv_frag = 5840;
1582 state->pkt.u.alter.assoc_group_id = 0;
1583 state->pkt.u.alter.num_contexts = 1;
1584 state->pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1585 struct dcerpc_ctx_list, 1);
1586 if (state->pkt.u.alter.ctx_list == NULL) {
1587 c->status = NT_STATUS_NO_MEMORY;
1590 state->pkt.u.alter.ctx_list[0].context_id = p->context_id;
1591 state->pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1592 state->pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1593 state->pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1594 state->pkt.u.alter.auth_info = data_blob(NULL, 0);
1596 /* construct the NDR form of the packet */
1597 c->status = ncacn_push_auth(&state->blob, mem_ctx, &state->pkt,
1598 p->conn->security_state.auth_info);
1599 if (!NT_STATUS_IS_OK(c->status)) {
1603 p->conn->transport.recv_data = alter_request_recv;
1604 p->conn->full_request_private = c;
1606 c->status = p->conn->transport.send_request(p->conn, &state->blob,
1608 if (!NT_STATUS_IS_OK(c->status)) {
1612 event_add_timed(c->event_ctx, c,
1613 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1614 bind_timeout_handler, c);
1619 composite_trigger_error(c);
1623 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1625 NTSTATUS result = composite_wait(ctx);
1631 send a dcerpc alter_context request
1633 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1634 TALLOC_CTX *mem_ctx,
1635 const struct dcerpc_syntax_id *syntax,
1636 const struct dcerpc_syntax_id *transfer_syntax)
1638 struct composite_context *creq;
1639 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1640 return dcerpc_alter_context_recv(creq);