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 "lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
33 NTSTATUS dcerpc_init(void)
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *c)
45 if (c->transport.shutdown_pipe) {
46 c->transport.shutdown_pipe(c);
52 /* initialise a dcerpc connection.
53 the event context is optional
55 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
56 struct event_context *ev)
58 struct dcerpc_connection *c;
60 c = talloc_zero(mem_ctx, struct dcerpc_connection);
66 ev = event_context_init(c);
75 if (!talloc_reference(c, ev)) {
80 c->security_state.auth_info = NULL;
81 c->security_state.session_key = dcerpc_generic_session_key;
82 c->security_state.generic_state = NULL;
83 c->binding_string = NULL;
85 c->srv_max_xmit_frag = 0;
86 c->srv_max_recv_frag = 0;
89 talloc_set_destructor(c, dcerpc_connection_destructor);
94 /* initialise a dcerpc pipe. */
95 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
97 struct dcerpc_pipe *p;
99 p = talloc(mem_ctx, struct dcerpc_pipe);
104 p->conn = dcerpc_connection_init(p, ev);
105 if (p->conn == NULL) {
110 p->last_fault_code = 0;
112 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
115 ZERO_STRUCT(p->syntax);
116 ZERO_STRUCT(p->transfer_syntax);
123 choose the next call id to use
125 static uint32_t next_call_id(struct dcerpc_connection *c)
128 if (c->call_id == 0) {
134 /* we need to be able to get/set the fragment length without doing a full
136 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
138 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
139 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
141 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
145 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
147 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
148 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
150 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
154 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
156 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
157 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
159 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
165 setup for a ndr pull, also setting up any flags from the binding string
167 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
168 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
170 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
172 if (ndr == NULL) return ndr;
174 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
175 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
178 if (c->flags & DCERPC_NDR_REF_ALLOC) {
179 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
186 parse a data blob into a ncacn_packet structure. This handles both
187 input and output packets
189 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
190 struct ncacn_packet *pkt)
192 struct ndr_pull *ndr;
194 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
196 return NT_STATUS_NO_MEMORY;
199 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
200 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
203 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
207 generate a CONNECT level verifier
209 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
211 *blob = data_blob_talloc(mem_ctx, NULL, 16);
212 if (blob->data == NULL) {
213 return NT_STATUS_NO_MEMORY;
215 SIVAL(blob->data, 0, 1);
216 memset(blob->data+4, 0, 12);
221 check a CONNECT level verifier
223 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
225 if (blob->length != 16 ||
226 IVAL(blob->data, 0) != 1) {
227 return NT_STATUS_ACCESS_DENIED;
233 parse the authentication information on a dcerpc response packet
235 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
236 DATA_BLOB *raw_packet,
237 struct ncacn_packet *pkt)
239 struct ndr_pull *ndr;
241 struct dcerpc_auth auth;
244 if (pkt->auth_length == 0 &&
245 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
249 auth_blob.length = 8 + pkt->auth_length;
251 /* check for a valid length */
252 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
253 return NT_STATUS_INFO_LENGTH_MISMATCH;
257 pkt->u.response.stub_and_verifier.data +
258 pkt->u.response.stub_and_verifier.length - auth_blob.length;
259 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
261 /* pull the auth structure */
262 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
264 return NT_STATUS_NO_MEMORY;
267 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
268 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
271 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
272 if (!NT_STATUS_IS_OK(status)) {
276 /* check signature or unseal the packet */
277 switch (c->security_state.auth_info->auth_level) {
278 case DCERPC_AUTH_LEVEL_PRIVACY:
279 status = gensec_unseal_packet(c->security_state.generic_state,
281 raw_packet->data + DCERPC_REQUEST_LENGTH,
282 pkt->u.response.stub_and_verifier.length,
284 raw_packet->length - auth.credentials.length,
286 memcpy(pkt->u.response.stub_and_verifier.data,
287 raw_packet->data + DCERPC_REQUEST_LENGTH,
288 pkt->u.response.stub_and_verifier.length);
291 case DCERPC_AUTH_LEVEL_INTEGRITY:
292 status = gensec_check_packet(c->security_state.generic_state,
294 pkt->u.response.stub_and_verifier.data,
295 pkt->u.response.stub_and_verifier.length,
297 raw_packet->length - auth.credentials.length,
301 case DCERPC_AUTH_LEVEL_CONNECT:
302 status = dcerpc_check_connect_verifier(&auth.credentials);
305 case DCERPC_AUTH_LEVEL_NONE:
309 status = NT_STATUS_INVALID_LEVEL;
313 /* remove the indicated amount of paddiing */
314 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
315 return NT_STATUS_INFO_LENGTH_MISMATCH;
317 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
324 push a dcerpc request packet into a blob, possibly signing it.
326 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
327 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
328 struct ncacn_packet *pkt)
331 struct ndr_push *ndr;
333 size_t payload_length;
335 /* non-signed packets are simpler */
336 if (!c->security_state.auth_info ||
337 !c->security_state.generic_state) {
338 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
341 ndr = ndr_push_init_ctx(mem_ctx);
343 return NT_STATUS_NO_MEMORY;
346 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
347 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
350 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
351 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
354 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
355 if (!NT_STATUS_IS_OK(status)) {
359 /* pad to 16 byte multiple in the payload portion of the
360 packet. This matches what w2k3 does */
361 c->security_state.auth_info->auth_pad_length =
362 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
363 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
365 payload_length = pkt->u.request.stub_and_verifier.length +
366 c->security_state.auth_info->auth_pad_length;
368 /* sign or seal the packet */
369 switch (c->security_state.auth_info->auth_level) {
370 case DCERPC_AUTH_LEVEL_PRIVACY:
371 case DCERPC_AUTH_LEVEL_INTEGRITY:
372 /* We hope this length is accruate. If must be if the
373 * GENSEC mech does AEAD signing of the packet
375 c->security_state.auth_info->credentials
376 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
378 data_blob_clear(&c->security_state.auth_info->credentials);
381 case DCERPC_AUTH_LEVEL_CONNECT:
382 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
385 case DCERPC_AUTH_LEVEL_NONE:
386 c->security_state.auth_info->credentials = data_blob(NULL, 0);
390 status = NT_STATUS_INVALID_LEVEL;
394 if (!NT_STATUS_IS_OK(status)) {
398 /* add the auth verifier */
399 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
400 if (!NT_STATUS_IS_OK(status)) {
404 /* extract the whole packet as a blob */
405 *blob = ndr_push_blob(ndr);
407 /* fill in the fragment length and auth_length, we can't fill
408 in these earlier as we don't know the signature length (it
409 could be variable length) */
410 dcerpc_set_frag_length(blob, blob->length);
411 /* We hope this value is accruate. If must be if the GENSEC
412 * mech does AEAD signing of the packet headers */
413 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
415 /* sign or seal the packet */
416 switch (c->security_state.auth_info->auth_level) {
417 case DCERPC_AUTH_LEVEL_PRIVACY:
418 status = gensec_seal_packet(c->security_state.generic_state,
420 blob->data + DCERPC_REQUEST_LENGTH,
424 c->security_state.auth_info->credentials.length,
426 if (!NT_STATUS_IS_OK(status)) {
429 blob->length -= c->security_state.auth_info->credentials.length;
430 status = data_blob_append(mem_ctx, blob,
431 creds2.data, creds2.length);
432 if (!NT_STATUS_IS_OK(status)) {
435 dcerpc_set_auth_length(blob, creds2.length);
436 if (c->security_state.auth_info->credentials.length == 0) {
437 /* this is needed for krb5 only, to correct the total packet
439 dcerpc_set_frag_length(blob,
440 dcerpc_get_frag_length(blob)
445 case DCERPC_AUTH_LEVEL_INTEGRITY:
446 status = gensec_sign_packet(c->security_state.generic_state,
448 blob->data + DCERPC_REQUEST_LENGTH,
452 c->security_state.auth_info->credentials.length,
454 if (!NT_STATUS_IS_OK(status)) {
457 blob->length -= c->security_state.auth_info->credentials.length;
458 status = data_blob_append(mem_ctx, blob,
459 creds2.data, creds2.length);
460 if (!NT_STATUS_IS_OK(status)) {
463 dcerpc_set_auth_length(blob, creds2.length);
464 if (c->security_state.auth_info->credentials.length == 0) {
465 /* this is needed for krb5 only, to correct the total packet
467 dcerpc_set_frag_length(blob,
468 dcerpc_get_frag_length(blob)
473 case DCERPC_AUTH_LEVEL_CONNECT:
476 case DCERPC_AUTH_LEVEL_NONE:
477 c->security_state.auth_info->credentials = data_blob(NULL, 0);
481 status = NT_STATUS_INVALID_LEVEL;
485 data_blob_free(&c->security_state.auth_info->credentials);
492 fill in the fixed values in a dcerpc header
494 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
497 pkt->rpc_vers_minor = 0;
498 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
501 pkt->drep[0] = DCERPC_DREP_LE;
509 map a bind nak reason to a NTSTATUS
511 static NTSTATUS dcerpc_map_reason(uint16_t reason)
514 case DCERPC_BIND_REASON_ASYNTAX:
515 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
516 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
517 return NT_STATUS_INVALID_PARAMETER;
519 return NT_STATUS_UNSUCCESSFUL;
523 a bind or alter context has failed
525 static void dcerpc_composite_fail(struct rpc_request *req)
527 struct composite_context *c = talloc_get_type(req->async.private,
528 struct composite_context);
529 composite_error(c, req->status);
533 remove requests from the pending or queued queues
535 static int dcerpc_req_dequeue(struct rpc_request *req)
537 switch (req->state) {
538 case RPC_REQUEST_QUEUED:
539 DLIST_REMOVE(req->p->conn->request_queue, req);
541 case RPC_REQUEST_PENDING:
542 DLIST_REMOVE(req->p->conn->pending, req);
544 case RPC_REQUEST_DONE:
552 mark the dcerpc connection dead. All outstanding requests get an error
554 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
556 /* all pending requests get the error */
557 while (conn->pending) {
558 struct rpc_request *req = conn->pending;
559 dcerpc_req_dequeue(req);
560 req->state = RPC_REQUEST_DONE;
561 req->status = status;
562 if (req->async.callback) {
563 req->async.callback(req);
569 forward declarations of the recv_data handlers for the types of
570 packets we need to handle
572 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
573 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
576 receive a dcerpc reply from the transport. Here we work out what
577 type of reply it is (normal request, bind or alter context) and
578 dispatch to the appropriate handler
580 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
582 struct ncacn_packet pkt;
584 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
585 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
588 /* the transport may be telling us of a severe error, such as
590 if (!NT_STATUS_IS_OK(status)) {
591 data_blob_free(blob);
592 dcerpc_connection_dead(conn, status);
596 /* parse the basic packet to work out what type of response this is */
597 status = ncacn_pull(conn, blob, blob->data, &pkt);
598 if (!NT_STATUS_IS_OK(status)) {
599 data_blob_free(blob);
600 dcerpc_connection_dead(conn, status);
603 dcerpc_request_recv_data(conn, blob, &pkt);
608 Receive a bind reply from the transport
610 static void dcerpc_bind_recv_handler(struct rpc_request *req,
611 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
613 struct composite_context *c;
614 struct dcerpc_connection *conn;
616 c = talloc_get_type(req->async.private, struct composite_context);
618 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
619 DEBUG(2,("dcerpc: bind_nak reason %d\n",
620 pkt->u.bind_nak.reject_reason));
621 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
626 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
627 (pkt->u.bind_ack.num_results == 0) ||
628 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
629 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
635 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
636 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
638 /* the bind_ack might contain a reply set of credentials */
639 if (conn->security_state.auth_info &&
640 pkt->u.bind_ack.auth_info.length) {
641 c->status = ndr_pull_struct_blob(
642 &pkt->u.bind_ack.auth_info, conn,
643 conn->security_state.auth_info,
644 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
645 if (!composite_is_ok(c)) return;
648 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
654 handle timeouts of individual dcerpc requests
656 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
657 struct timeval t, void *private)
659 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
661 if (req->state == RPC_REQUEST_DONE) {
665 dcerpc_req_dequeue(req);
667 req->status = NT_STATUS_IO_TIMEOUT;
668 req->state = RPC_REQUEST_DONE;
669 if (req->async.callback) {
670 req->async.callback(req);
675 send a async dcerpc bind request
677 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
679 const struct dcerpc_syntax_id *syntax,
680 const struct dcerpc_syntax_id *transfer_syntax)
682 struct composite_context *c;
683 struct ncacn_packet pkt;
685 struct rpc_request *req;
687 c = composite_create(mem_ctx,p->conn->event_ctx);
688 if (c == NULL) return NULL;
693 p->transfer_syntax = *transfer_syntax;
695 init_ncacn_hdr(p->conn, &pkt);
697 pkt.ptype = DCERPC_PKT_BIND;
698 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
699 pkt.call_id = p->conn->call_id;
702 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
703 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
706 pkt.u.bind.max_xmit_frag = 5840;
707 pkt.u.bind.max_recv_frag = 5840;
708 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
709 pkt.u.bind.num_contexts = 1;
710 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
711 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
712 pkt.u.bind.ctx_list[0].context_id = p->context_id;
713 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
714 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
715 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
716 pkt.u.bind.auth_info = data_blob(NULL, 0);
718 /* construct the NDR form of the packet */
719 c->status = ncacn_push_auth(&blob, c, &pkt,
720 p->conn->security_state.auth_info);
721 if (!composite_is_ok(c)) return c;
723 p->conn->transport.recv_data = dcerpc_recv_data;
726 * we allocate a dcerpc_request so we can be in the same
727 * request queue as normal requests
729 req = talloc_zero(c, struct rpc_request);
730 if (composite_nomem(req, c)) return c;
732 req->state = RPC_REQUEST_PENDING;
733 req->call_id = pkt.call_id;
734 req->async.private = c;
735 req->async.callback = dcerpc_composite_fail;
737 req->recv_handler = dcerpc_bind_recv_handler;
738 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
739 talloc_set_destructor(req, dcerpc_req_dequeue);
741 c->status = p->conn->transport.send_request(p->conn, &blob,
743 if (!composite_is_ok(c)) return c;
745 event_add_timed(c->event_ctx, req,
746 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
747 dcerpc_timeout_handler, req);
753 recv side of async dcerpc bind request
755 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
757 NTSTATUS result = composite_wait(ctx);
763 perform a continued bind (and auth3)
765 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
768 struct ncacn_packet pkt;
772 init_ncacn_hdr(c, &pkt);
774 pkt.ptype = DCERPC_PKT_AUTH3;
775 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
776 pkt.call_id = next_call_id(c);
778 pkt.u.auth3._pad = 0;
779 pkt.u.auth3.auth_info = data_blob(NULL, 0);
781 /* construct the NDR form of the packet */
782 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
783 if (!NT_STATUS_IS_OK(status)) {
787 /* send it on its way */
788 status = c->transport.send_request(c, &blob, False);
789 if (!NT_STATUS_IS_OK(status)) {
798 process a fragment received from the transport layer during a
801 This function frees the data
803 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
804 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
806 struct rpc_request *req;
808 NTSTATUS status = NT_STATUS_OK;
811 if this is an authenticated connection then parse and check
812 the auth info. We have to do this before finding the
813 matching packet, as the request structure might have been
814 removed due to a timeout, but if it has been we still need
815 to run the auth routines so that we don't get the sign/seal
816 info out of step with the server
818 if (c->security_state.auth_info && c->security_state.generic_state &&
819 pkt->ptype == DCERPC_PKT_RESPONSE) {
820 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
823 /* find the matching request */
824 for (req=c->pending;req;req=req->next) {
825 if (pkt->call_id == req->call_id) break;
829 /* useful for testing certain vendors RPC servers */
830 if (req == NULL && c->pending && pkt->call_id == 0) {
831 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
837 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
838 data_blob_free(raw_packet);
842 talloc_steal(req, raw_packet->data);
844 if (req->recv_handler != NULL) {
845 dcerpc_req_dequeue(req);
846 req->state = RPC_REQUEST_DONE;
847 req->recv_handler(req, raw_packet, pkt);
851 if (pkt->ptype == DCERPC_PKT_FAULT) {
852 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
853 req->fault_code = pkt->u.fault.status;
854 req->status = NT_STATUS_NET_WRITE_FAULT;
858 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
859 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
861 req->fault_code = DCERPC_FAULT_OTHER;
862 req->status = NT_STATUS_NET_WRITE_FAULT;
866 /* now check the status from the auth routines, and if it failed then fail
867 this request accordingly */
868 if (!NT_STATUS_IS_OK(status)) {
869 req->status = status;
873 length = pkt->u.response.stub_and_verifier.length;
876 req->payload.data = talloc_realloc(req,
879 req->payload.length + length);
880 if (!req->payload.data) {
881 req->status = NT_STATUS_NO_MEMORY;
884 memcpy(req->payload.data+req->payload.length,
885 pkt->u.response.stub_and_verifier.data, length);
886 req->payload.length += length;
889 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
890 c->transport.send_read(c);
894 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
895 req->flags |= DCERPC_PULL_BIGENDIAN;
897 req->flags &= ~DCERPC_PULL_BIGENDIAN;
902 /* we've got the full payload */
903 req->state = RPC_REQUEST_DONE;
904 DLIST_REMOVE(c->pending, req);
906 if (c->request_queue != NULL) {
907 /* We have to look at shipping further requests before calling
908 * the async function, that one might close the pipe */
909 dcerpc_ship_next_request(c);
912 if (req->async.callback) {
913 req->async.callback(req);
918 perform the send side of a async dcerpc request
920 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
921 const struct GUID *object,
924 DATA_BLOB *stub_data)
926 struct rpc_request *req;
928 p->conn->transport.recv_data = dcerpc_recv_data;
930 req = talloc(p, struct rpc_request);
936 req->call_id = next_call_id(p->conn);
937 req->status = NT_STATUS_OK;
938 req->state = RPC_REQUEST_QUEUED;
939 req->payload = data_blob(NULL, 0);
942 req->async_call = async;
943 req->async.callback = NULL;
944 req->async.private = NULL;
945 req->recv_handler = NULL;
947 if (object != NULL) {
948 req->object = talloc_memdup(req, object, sizeof(*object));
949 if (req->object == NULL) {
958 req->request_data.length = stub_data->length;
959 req->request_data.data = talloc_reference(req, stub_data->data);
960 if (req->request_data.length && req->request_data.data == NULL) {
964 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
965 talloc_set_destructor(req, dcerpc_req_dequeue);
967 dcerpc_ship_next_request(p->conn);
969 if (p->request_timeout) {
970 event_add_timed(dcerpc_event_context(p), req,
971 timeval_current_ofs(p->request_timeout, 0),
972 dcerpc_timeout_handler, req);
979 Send a request using the transport
982 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
984 struct rpc_request *req;
985 struct dcerpc_pipe *p;
986 DATA_BLOB *stub_data;
987 struct ncacn_packet pkt;
989 uint32_t remaining, chunk_size;
990 BOOL first_packet = True;
992 req = c->request_queue;
998 stub_data = &req->request_data;
1000 if (!req->async_call && (c->pending != NULL)) {
1004 DLIST_REMOVE(c->request_queue, req);
1005 DLIST_ADD(c->pending, req);
1006 req->state = RPC_REQUEST_PENDING;
1008 init_ncacn_hdr(p->conn, &pkt);
1010 remaining = stub_data->length;
1012 /* we can write a full max_recv_frag size, minus the dcerpc
1013 request header size */
1014 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1016 pkt.ptype = DCERPC_PKT_REQUEST;
1017 pkt.call_id = req->call_id;
1018 pkt.auth_length = 0;
1020 pkt.u.request.alloc_hint = remaining;
1021 pkt.u.request.context_id = p->context_id;
1022 pkt.u.request.opnum = req->opnum;
1025 pkt.u.request.object.object = *req->object;
1026 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1027 chunk_size -= ndr_size_GUID(req->object,0);
1030 /* we send a series of pdus without waiting for a reply */
1031 while (remaining > 0 || first_packet) {
1032 uint32_t chunk = MIN(chunk_size, remaining);
1033 BOOL last_frag = False;
1035 first_packet = False;
1036 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1038 if (remaining == stub_data->length) {
1039 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1041 if (chunk == remaining) {
1042 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1046 pkt.u.request.stub_and_verifier.data = stub_data->data +
1047 (stub_data->length - remaining);
1048 pkt.u.request.stub_and_verifier.length = chunk;
1050 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1051 if (!NT_STATUS_IS_OK(req->status)) {
1052 req->state = RPC_REQUEST_DONE;
1053 DLIST_REMOVE(p->conn->pending, req);
1057 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1058 if (!NT_STATUS_IS_OK(req->status)) {
1059 req->state = RPC_REQUEST_DONE;
1060 DLIST_REMOVE(p->conn->pending, req);
1069 return the event context for a dcerpc pipe
1070 used by callers who wish to operate asynchronously
1072 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1074 return p->conn->event_ctx;
1080 perform the receive side of a async dcerpc request
1082 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1083 TALLOC_CTX *mem_ctx,
1084 DATA_BLOB *stub_data)
1088 while (req->state != RPC_REQUEST_DONE) {
1089 struct event_context *ctx = dcerpc_event_context(req->p);
1090 if (event_loop_once(ctx) != 0) {
1091 return NT_STATUS_CONNECTION_DISCONNECTED;
1094 *stub_data = req->payload;
1095 status = req->status;
1096 if (stub_data->data) {
1097 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1099 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1100 req->p->last_fault_code = req->fault_code;
1107 perform a full request/response pair on a dcerpc pipe
1109 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1110 struct GUID *object,
1113 TALLOC_CTX *mem_ctx,
1114 DATA_BLOB *stub_data_in,
1115 DATA_BLOB *stub_data_out)
1117 struct rpc_request *req;
1119 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1121 return NT_STATUS_NO_MEMORY;
1124 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1129 this is a paranoid NDR validator. For every packet we push onto the wire
1130 we pull it back again, then push it again. Then we compare the raw NDR data
1131 for that to the NDR we initially generated. If they don't match then we know
1132 we must have a bug in either the pull or push side of our code
1134 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1135 TALLOC_CTX *mem_ctx,
1138 ndr_push_flags_fn_t ndr_push,
1139 ndr_pull_flags_fn_t ndr_pull)
1142 struct ndr_pull *pull;
1143 struct ndr_push *push;
1147 st = talloc_size(mem_ctx, struct_size);
1149 return NT_STATUS_NO_MEMORY;
1152 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1154 return NT_STATUS_NO_MEMORY;
1156 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1158 status = ndr_pull(pull, NDR_IN, st);
1159 if (!NT_STATUS_IS_OK(status)) {
1160 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1161 "failed input validation pull - %s",
1165 push = ndr_push_init_ctx(mem_ctx);
1167 return NT_STATUS_NO_MEMORY;
1170 status = ndr_push(push, NDR_IN, st);
1171 if (!NT_STATUS_IS_OK(status)) {
1172 return ndr_push_error(push, NDR_ERR_VALIDATE,
1173 "failed input validation push - %s",
1177 blob2 = ndr_push_blob(push);
1179 if (!data_blob_equal(&blob, &blob2)) {
1180 DEBUG(3,("original:\n"));
1181 dump_data(3, blob.data, blob.length);
1182 DEBUG(3,("secondary:\n"));
1183 dump_data(3, blob2.data, blob2.length);
1184 return ndr_push_error(push, NDR_ERR_VALIDATE,
1185 "failed input validation data - %s",
1189 return NT_STATUS_OK;
1193 this is a paranoid NDR input validator. For every packet we pull
1194 from the wire we push it back again then pull and push it
1195 again. Then we compare the raw NDR data for that to the NDR we
1196 initially generated. If they don't match then we know we must have a
1197 bug in either the pull or push side of our code
1199 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1200 struct ndr_pull *pull_in,
1203 ndr_push_flags_fn_t ndr_push,
1204 ndr_pull_flags_fn_t ndr_pull,
1205 ndr_print_function_t ndr_print)
1208 struct ndr_pull *pull;
1209 struct ndr_push *push;
1211 DATA_BLOB blob, blob2;
1212 TALLOC_CTX *mem_ctx = pull_in;
1215 st = talloc_size(mem_ctx, struct_size);
1217 return NT_STATUS_NO_MEMORY;
1219 memcpy(st, struct_ptr, struct_size);
1221 push = ndr_push_init_ctx(mem_ctx);
1223 return NT_STATUS_NO_MEMORY;
1226 status = ndr_push(push, NDR_OUT, struct_ptr);
1227 if (!NT_STATUS_IS_OK(status)) {
1228 return ndr_push_error(push, NDR_ERR_VALIDATE,
1229 "failed output validation push - %s",
1233 blob = ndr_push_blob(push);
1235 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1237 return NT_STATUS_NO_MEMORY;
1240 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1241 status = ndr_pull(pull, NDR_OUT, st);
1242 if (!NT_STATUS_IS_OK(status)) {
1243 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1244 "failed output validation pull - %s",
1248 push = ndr_push_init_ctx(mem_ctx);
1250 return NT_STATUS_NO_MEMORY;
1253 status = ndr_push(push, NDR_OUT, st);
1254 if (!NT_STATUS_IS_OK(status)) {
1255 return ndr_push_error(push, NDR_ERR_VALIDATE,
1256 "failed output validation push2 - %s",
1260 blob2 = ndr_push_blob(push);
1262 if (!data_blob_equal(&blob, &blob2)) {
1263 DEBUG(3,("original:\n"));
1264 dump_data(3, blob.data, blob.length);
1265 DEBUG(3,("secondary:\n"));
1266 dump_data(3, blob2.data, blob2.length);
1267 return ndr_push_error(push, NDR_ERR_VALIDATE,
1268 "failed output validation data - %s",
1272 /* this checks the printed forms of the two structures, which effectively
1273 tests all of the value() attributes */
1274 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1275 NDR_OUT, struct_ptr);
1276 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1278 if (strcmp(s1, s2) != 0) {
1280 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1282 /* this is sometimes useful */
1283 printf("VALIDATE ERROR\n");
1284 file_save("wire.dat", s1, strlen(s1));
1285 file_save("gen.dat", s2, strlen(s2));
1286 system("diff -u wire.dat gen.dat");
1290 return NT_STATUS_OK;
1295 send a rpc request given a dcerpc_call structure
1297 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1298 const struct GUID *object,
1299 const struct dcerpc_interface_table *table,
1301 TALLOC_CTX *mem_ctx,
1304 const struct dcerpc_interface_call *call;
1305 struct ndr_push *push;
1308 struct rpc_request *req;
1310 call = &table->calls[opnum];
1312 /* setup for a ndr_push_* call */
1313 push = ndr_push_init_ctx(mem_ctx);
1318 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1319 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1322 /* push the structure into a blob */
1323 status = call->ndr_push(push, NDR_IN, r);
1324 if (!NT_STATUS_IS_OK(status)) {
1325 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1326 nt_errstr(status)));
1331 /* retrieve the blob */
1332 request = ndr_push_blob(push);
1334 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1335 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1336 call->ndr_push, call->ndr_pull);
1337 if (!NT_STATUS_IS_OK(status)) {
1338 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1339 nt_errstr(status)));
1345 DEBUG(10,("rpc request data:\n"));
1346 dump_data(10, request.data, request.length);
1348 /* make the actual dcerpc request */
1349 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1353 req->ndr.table = table;
1354 req->ndr.opnum = opnum;
1355 req->ndr.struct_ptr = r;
1356 req->ndr.mem_ctx = mem_ctx;
1365 receive the answer from a dcerpc_ndr_request_send()
1367 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1369 struct dcerpc_pipe *p = req->p;
1372 struct ndr_pull *pull;
1374 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1375 void *r = req->ndr.struct_ptr;
1376 uint32_t opnum = req->ndr.opnum;
1377 const struct dcerpc_interface_table *table = req->ndr.table;
1378 const struct dcerpc_interface_call *call = &table->calls[opnum];
1380 /* make sure the recv code doesn't free the request, as we
1381 need to grab the flags element before it is freed */
1382 if (talloc_reference(p, req) == NULL) {
1383 return NT_STATUS_NO_MEMORY;
1386 status = dcerpc_request_recv(req, mem_ctx, &response);
1387 if (!NT_STATUS_IS_OK(status)) {
1388 talloc_unlink(p, req);
1394 /* prepare for ndr_pull_* */
1395 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1397 talloc_unlink(p, req);
1398 return NT_STATUS_NO_MEMORY;
1402 pull->data = talloc_steal(pull, pull->data);
1404 talloc_unlink(p, req);
1406 if (flags & DCERPC_PULL_BIGENDIAN) {
1407 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1410 DEBUG(10,("rpc reply data:\n"));
1411 dump_data(10, pull->data, pull->data_size);
1413 /* pull the structure from the blob */
1414 status = call->ndr_pull(pull, NDR_OUT, r);
1415 if (!NT_STATUS_IS_OK(status)) {
1416 dcerpc_log_packet(table, opnum, NDR_OUT,
1421 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1422 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1423 call->ndr_push, call->ndr_pull,
1425 if (!NT_STATUS_IS_OK(status)) {
1426 dcerpc_log_packet(table, opnum, NDR_OUT,
1432 if (pull->offset != pull->data_size) {
1433 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1434 pull->data_size - pull->offset));
1435 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1436 but it turns out that early versions of NT
1437 (specifically NT3.1) add junk onto the end of rpc
1438 packets, so if we want to interoperate at all with
1439 those versions then we need to ignore this error */
1442 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1444 return NT_STATUS_OK;
1449 a useful helper function for synchronous rpc requests
1451 this can be used when you have ndr push/pull functions in the
1454 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1455 const struct GUID *object,
1456 const struct dcerpc_interface_table *table,
1458 TALLOC_CTX *mem_ctx,
1461 struct rpc_request *req;
1463 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1465 return NT_STATUS_NO_MEMORY;
1468 return dcerpc_ndr_request_recv(req);
1473 a useful function for retrieving the server name we connected to
1475 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1477 if (!p->conn->transport.peer_name) {
1480 return p->conn->transport.peer_name(p->conn);
1485 get the dcerpc auth_level for a open connection
1487 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1491 if (c->flags & DCERPC_SEAL) {
1492 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1493 } else if (c->flags & DCERPC_SIGN) {
1494 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1495 } else if (c->flags & DCERPC_CONNECT) {
1496 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1498 auth_level = DCERPC_AUTH_LEVEL_NONE;
1504 Receive an alter reply from the transport
1506 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1507 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1509 struct composite_context *c;
1510 struct dcerpc_pipe *recv_pipe;
1512 c = talloc_get_type(req->async.private, struct composite_context);
1513 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1515 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1516 pkt->u.alter_resp.num_results == 1 &&
1517 pkt->u.alter_resp.ctx_list[0].result != 0) {
1518 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1519 pkt->u.alter_resp.ctx_list[0].reason));
1520 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1524 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1525 pkt->u.alter_resp.num_results == 0 ||
1526 pkt->u.alter_resp.ctx_list[0].result != 0) {
1527 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1531 /* the alter_resp might contain a reply set of credentials */
1532 if (recv_pipe->conn->security_state.auth_info &&
1533 pkt->u.alter_resp.auth_info.length) {
1534 c->status = ndr_pull_struct_blob(
1535 &pkt->u.alter_resp.auth_info, recv_pipe,
1536 recv_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 ncacn_packet pkt;
1555 struct rpc_request *req;
1557 c = composite_create(mem_ctx, p->conn->event_ctx);
1558 if (c == NULL) return NULL;
1560 c->private_data = p;
1562 p->syntax = *syntax;
1563 p->transfer_syntax = *transfer_syntax;
1565 init_ncacn_hdr(p->conn, &pkt);
1567 pkt.ptype = DCERPC_PKT_ALTER;
1568 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1569 pkt.call_id = p->conn->call_id;
1570 pkt.auth_length = 0;
1572 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1573 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1576 pkt.u.alter.max_xmit_frag = 5840;
1577 pkt.u.alter.max_recv_frag = 5840;
1578 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1579 pkt.u.alter.num_contexts = 1;
1580 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1581 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1582 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1583 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1584 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1585 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1586 pkt.u.alter.auth_info = data_blob(NULL, 0);
1588 /* construct the NDR form of the packet */
1589 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1590 p->conn->security_state.auth_info);
1591 if (!composite_is_ok(c)) return c;
1593 p->conn->transport.recv_data = dcerpc_recv_data;
1596 * we allocate a dcerpc_request so we can be in the same
1597 * request queue as normal requests
1599 req = talloc_zero(c, struct rpc_request);
1600 if (composite_nomem(req, c)) return c;
1602 req->state = RPC_REQUEST_PENDING;
1603 req->call_id = pkt.call_id;
1604 req->async.private = c;
1605 req->async.callback = dcerpc_composite_fail;
1607 req->recv_handler = dcerpc_alter_recv_handler;
1608 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1609 talloc_set_destructor(req, dcerpc_req_dequeue);
1611 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1612 if (!composite_is_ok(c)) return c;
1614 event_add_timed(c->event_ctx, req,
1615 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1616 dcerpc_timeout_handler, req);
1621 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1623 NTSTATUS result = composite_wait(ctx);
1629 send a dcerpc alter_context request
1631 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1632 TALLOC_CTX *mem_ctx,
1633 const struct dcerpc_syntax_id *syntax,
1634 const struct dcerpc_syntax_id *transfer_syntax)
1636 struct composite_context *creq;
1637 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1638 return dcerpc_alter_context_recv(creq);