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;
114 ZERO_STRUCT(p->syntax);
115 ZERO_STRUCT(p->transfer_syntax);
122 choose the next call id to use
124 static uint32_t next_call_id(struct dcerpc_connection *c)
127 if (c->call_id == 0) {
133 /* we need to be able to get/set the fragment length without doing a full
135 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
137 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
138 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
140 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
144 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
146 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
147 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
149 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
153 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
155 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
156 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
158 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
164 setup for a ndr pull, also setting up any flags from the binding string
166 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
167 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
169 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
171 if (ndr == NULL) return ndr;
173 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
174 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
177 if (c->flags & DCERPC_NDR_REF_ALLOC) {
178 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
185 parse a data blob into a ncacn_packet structure. This handles both
186 input and output packets
188 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
189 struct ncacn_packet *pkt)
191 struct ndr_pull *ndr;
193 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
195 return NT_STATUS_NO_MEMORY;
198 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
199 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
202 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
206 generate a CONNECT level verifier
208 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
210 *blob = data_blob_talloc(mem_ctx, NULL, 16);
211 if (blob->data == NULL) {
212 return NT_STATUS_NO_MEMORY;
214 SIVAL(blob->data, 0, 1);
215 memset(blob->data+4, 0, 12);
220 check a CONNECT level verifier
222 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
224 if (blob->length != 16 ||
225 IVAL(blob->data, 0) != 1) {
226 return NT_STATUS_ACCESS_DENIED;
232 parse the authentication information on a dcerpc response packet
234 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
235 DATA_BLOB *raw_packet,
236 struct ncacn_packet *pkt)
238 struct ndr_pull *ndr;
240 struct dcerpc_auth auth;
243 if (pkt->auth_length == 0 &&
244 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
248 auth_blob.length = 8 + pkt->auth_length;
250 /* check for a valid length */
251 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
252 return NT_STATUS_INFO_LENGTH_MISMATCH;
256 pkt->u.response.stub_and_verifier.data +
257 pkt->u.response.stub_and_verifier.length - auth_blob.length;
258 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
260 /* pull the auth structure */
261 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
263 return NT_STATUS_NO_MEMORY;
266 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
267 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
270 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
271 if (!NT_STATUS_IS_OK(status)) {
275 /* check signature or unseal the packet */
276 switch (c->security_state.auth_info->auth_level) {
277 case DCERPC_AUTH_LEVEL_PRIVACY:
278 status = gensec_unseal_packet(c->security_state.generic_state,
280 raw_packet->data + DCERPC_REQUEST_LENGTH,
281 pkt->u.response.stub_and_verifier.length,
283 raw_packet->length - auth.credentials.length,
285 memcpy(pkt->u.response.stub_and_verifier.data,
286 raw_packet->data + DCERPC_REQUEST_LENGTH,
287 pkt->u.response.stub_and_verifier.length);
290 case DCERPC_AUTH_LEVEL_INTEGRITY:
291 status = gensec_check_packet(c->security_state.generic_state,
293 pkt->u.response.stub_and_verifier.data,
294 pkt->u.response.stub_and_verifier.length,
296 raw_packet->length - auth.credentials.length,
300 case DCERPC_AUTH_LEVEL_CONNECT:
301 status = dcerpc_check_connect_verifier(&auth.credentials);
304 case DCERPC_AUTH_LEVEL_NONE:
308 status = NT_STATUS_INVALID_LEVEL;
312 /* remove the indicated amount of paddiing */
313 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
314 return NT_STATUS_INFO_LENGTH_MISMATCH;
316 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
323 push a dcerpc request packet into a blob, possibly signing it.
325 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
326 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
327 struct ncacn_packet *pkt)
330 struct ndr_push *ndr;
332 size_t payload_length;
334 /* non-signed packets are simpler */
335 if (!c->security_state.auth_info ||
336 !c->security_state.generic_state) {
337 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
340 ndr = ndr_push_init_ctx(mem_ctx);
342 return NT_STATUS_NO_MEMORY;
345 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
346 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
349 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
350 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
353 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
354 if (!NT_STATUS_IS_OK(status)) {
358 /* pad to 16 byte multiple in the payload portion of the
359 packet. This matches what w2k3 does */
360 c->security_state.auth_info->auth_pad_length =
361 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
362 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
364 payload_length = pkt->u.request.stub_and_verifier.length +
365 c->security_state.auth_info->auth_pad_length;
367 /* sign or seal the packet */
368 switch (c->security_state.auth_info->auth_level) {
369 case DCERPC_AUTH_LEVEL_PRIVACY:
370 case DCERPC_AUTH_LEVEL_INTEGRITY:
371 /* We hope this length is accruate. If must be if the
372 * GENSEC mech does AEAD signing of the packet
374 c->security_state.auth_info->credentials
375 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
377 data_blob_clear(&c->security_state.auth_info->credentials);
380 case DCERPC_AUTH_LEVEL_CONNECT:
381 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
384 case DCERPC_AUTH_LEVEL_NONE:
385 c->security_state.auth_info->credentials = data_blob(NULL, 0);
389 status = NT_STATUS_INVALID_LEVEL;
393 if (!NT_STATUS_IS_OK(status)) {
397 /* add the auth verifier */
398 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
399 if (!NT_STATUS_IS_OK(status)) {
403 /* extract the whole packet as a blob */
404 *blob = ndr_push_blob(ndr);
406 /* fill in the fragment length and auth_length, we can't fill
407 in these earlier as we don't know the signature length (it
408 could be variable length) */
409 dcerpc_set_frag_length(blob, blob->length);
410 /* We hope this value is accruate. If must be if the GENSEC
411 * mech does AEAD signing of the packet headers */
412 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
414 /* sign or seal the packet */
415 switch (c->security_state.auth_info->auth_level) {
416 case DCERPC_AUTH_LEVEL_PRIVACY:
417 status = gensec_seal_packet(c->security_state.generic_state,
419 blob->data + DCERPC_REQUEST_LENGTH,
423 c->security_state.auth_info->credentials.length,
425 if (!NT_STATUS_IS_OK(status)) {
428 blob->length -= c->security_state.auth_info->credentials.length;
429 status = data_blob_append(mem_ctx, blob,
430 creds2.data, creds2.length);
431 if (!NT_STATUS_IS_OK(status)) {
434 dcerpc_set_auth_length(blob, creds2.length);
435 if (c->security_state.auth_info->credentials.length == 0) {
436 /* this is needed for krb5 only, to correct the total packet
438 dcerpc_set_frag_length(blob,
439 dcerpc_get_frag_length(blob)
444 case DCERPC_AUTH_LEVEL_INTEGRITY:
445 status = gensec_sign_packet(c->security_state.generic_state,
447 blob->data + DCERPC_REQUEST_LENGTH,
451 c->security_state.auth_info->credentials.length,
453 if (!NT_STATUS_IS_OK(status)) {
456 blob->length -= c->security_state.auth_info->credentials.length;
457 status = data_blob_append(mem_ctx, blob,
458 creds2.data, creds2.length);
459 if (!NT_STATUS_IS_OK(status)) {
462 dcerpc_set_auth_length(blob, creds2.length);
463 if (c->security_state.auth_info->credentials.length == 0) {
464 /* this is needed for krb5 only, to correct the total packet
466 dcerpc_set_frag_length(blob,
467 dcerpc_get_frag_length(blob)
472 case DCERPC_AUTH_LEVEL_CONNECT:
475 case DCERPC_AUTH_LEVEL_NONE:
476 c->security_state.auth_info->credentials = data_blob(NULL, 0);
480 status = NT_STATUS_INVALID_LEVEL;
484 data_blob_free(&c->security_state.auth_info->credentials);
491 fill in the fixed values in a dcerpc header
493 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
496 pkt->rpc_vers_minor = 0;
497 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
500 pkt->drep[0] = DCERPC_DREP_LE;
508 map a bind nak reason to a NTSTATUS
510 static NTSTATUS dcerpc_map_reason(uint16_t reason)
513 case DCERPC_BIND_REASON_ASYNTAX:
514 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
515 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
516 return NT_STATUS_INVALID_PARAMETER;
518 return NT_STATUS_UNSUCCESSFUL;
522 a bind or alter context has failed
524 static void dcerpc_composite_fail(struct rpc_request *req)
526 struct composite_context *c = talloc_get_type(req->async.private,
527 struct composite_context);
528 composite_error(c, req->status);
532 mark the dcerpc connection dead. All outstanding requests get an error
534 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
536 /* all pending requests get the error */
537 while (conn->pending) {
538 struct rpc_request *req = conn->pending;
539 req->state = RPC_REQUEST_DONE;
540 req->status = status;
541 DLIST_REMOVE(conn->pending, req);
542 if (req->async.callback) {
543 req->async.callback(req);
549 forward declarations of the recv_data handlers for the types of
550 packets we need to handle
552 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
553 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
556 receive a dcerpc reply from the transport. Here we work out what
557 type of reply it is (normal request, bind or alter context) and
558 dispatch to the appropriate handler
560 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
562 struct ncacn_packet pkt;
564 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
565 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
568 /* the transport may be telling us of a severe error, such as
570 if (!NT_STATUS_IS_OK(status)) {
571 data_blob_free(blob);
572 dcerpc_connection_dead(conn, status);
576 /* parse the basic packet to work out what type of response this is */
577 status = ncacn_pull(conn, blob, blob->data, &pkt);
578 if (!NT_STATUS_IS_OK(status)) {
579 data_blob_free(blob);
580 dcerpc_connection_dead(conn, status);
583 dcerpc_request_recv_data(conn, blob, &pkt);
588 Receive a bind reply from the transport
590 static void dcerpc_bind_recv_handler(struct rpc_request *req,
591 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
593 struct composite_context *c;
594 struct dcerpc_connection *conn;
596 c = talloc_get_type(req->async.private, struct composite_context);
598 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
599 DEBUG(2,("dcerpc: bind_nak reason %d\n",
600 pkt->u.bind_nak.reject_reason));
601 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
606 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
607 (pkt->u.bind_ack.num_results == 0) ||
608 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
609 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
615 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
616 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
618 /* the bind_ack might contain a reply set of credentials */
619 if (conn->security_state.auth_info &&
620 pkt->u.bind_ack.auth_info.length) {
621 c->status = ndr_pull_struct_blob(
622 &pkt->u.bind_ack.auth_info, conn,
623 conn->security_state.auth_info,
624 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
625 if (!composite_is_ok(c)) return;
628 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
634 handle timeouts of individual dcerpc requests
636 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
637 struct timeval t, void *private)
639 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
641 if (req->state != RPC_REQUEST_PENDING) {
645 req->status = NT_STATUS_IO_TIMEOUT;
646 req->state = RPC_REQUEST_DONE;
647 DLIST_REMOVE(req->p->conn->pending, req);
648 if (req->async.callback) {
649 req->async.callback(req);
654 send a async dcerpc bind request
656 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
658 const struct dcerpc_syntax_id *syntax,
659 const struct dcerpc_syntax_id *transfer_syntax)
661 struct composite_context *c;
662 struct ncacn_packet pkt;
664 struct rpc_request *req;
666 c = composite_create(mem_ctx,p->conn->event_ctx);
667 if (c == NULL) return NULL;
672 p->transfer_syntax = *transfer_syntax;
674 init_ncacn_hdr(p->conn, &pkt);
676 pkt.ptype = DCERPC_PKT_BIND;
677 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
678 pkt.call_id = p->conn->call_id;
681 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
682 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
685 pkt.u.bind.max_xmit_frag = 5840;
686 pkt.u.bind.max_recv_frag = 5840;
687 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
688 pkt.u.bind.num_contexts = 1;
689 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
690 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
691 pkt.u.bind.ctx_list[0].context_id = p->context_id;
692 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
693 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
694 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
695 pkt.u.bind.auth_info = data_blob(NULL, 0);
697 /* construct the NDR form of the packet */
698 c->status = ncacn_push_auth(&blob, c, &pkt,
699 p->conn->security_state.auth_info);
700 if (!composite_is_ok(c)) return c;
702 p->conn->transport.recv_data = dcerpc_recv_data;
705 * we allocate a dcerpc_request so we can be in the same
706 * request queue as normal requests
708 req = talloc_zero(c, struct rpc_request);
709 if (composite_nomem(req, c)) return c;
711 req->state = RPC_REQUEST_PENDING;
712 req->call_id = pkt.call_id;
713 req->async.private = c;
714 req->async.callback = dcerpc_composite_fail;
716 req->recv_handler = dcerpc_bind_recv_handler;
717 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
719 c->status = p->conn->transport.send_request(p->conn, &blob,
721 if (!composite_is_ok(c)) return c;
723 event_add_timed(c->event_ctx, req,
724 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
725 dcerpc_timeout_handler, req);
731 recv side of async dcerpc bind request
733 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
735 NTSTATUS result = composite_wait(ctx);
741 perform a continued bind (and auth3)
743 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
746 struct ncacn_packet pkt;
750 init_ncacn_hdr(c, &pkt);
752 pkt.ptype = DCERPC_PKT_AUTH3;
753 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
754 pkt.call_id = next_call_id(c);
756 pkt.u.auth3._pad = 0;
757 pkt.u.auth3.auth_info = data_blob(NULL, 0);
759 /* construct the NDR form of the packet */
760 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
761 if (!NT_STATUS_IS_OK(status)) {
765 /* send it on its way */
766 status = c->transport.send_request(c, &blob, False);
767 if (!NT_STATUS_IS_OK(status)) {
776 process a fragment received from the transport layer during a
779 This function frees the data
781 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
782 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
784 struct rpc_request *req;
786 NTSTATUS status = NT_STATUS_OK;
789 if this is an authenticated connection then parse and check
790 the auth info. We have to do this before finding the
791 matching packet, as the request structure might have been
792 removed due to a timeout, but if it has been we still need
793 to run the auth routines so that we don't get the sign/seal
794 info out of step with the server
796 if (c->security_state.auth_info && c->security_state.generic_state &&
797 pkt->ptype == DCERPC_PKT_RESPONSE) {
798 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
801 /* find the matching request */
802 for (req=c->pending;req;req=req->next) {
803 if (pkt->call_id == req->call_id) break;
807 /* useful for testing certain vendors RPC servers */
808 if (req == NULL && c->pending && pkt->call_id == 0) {
809 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
815 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
816 data_blob_free(raw_packet);
820 talloc_steal(req, raw_packet->data);
822 if (req->recv_handler != NULL) {
823 req->state = RPC_REQUEST_DONE;
824 DLIST_REMOVE(c->pending, req);
825 req->recv_handler(req, raw_packet, pkt);
829 if (pkt->ptype == DCERPC_PKT_FAULT) {
830 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
831 req->fault_code = pkt->u.fault.status;
832 req->status = NT_STATUS_NET_WRITE_FAULT;
836 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
837 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
839 req->fault_code = DCERPC_FAULT_OTHER;
840 req->status = NT_STATUS_NET_WRITE_FAULT;
844 /* now check the status from the auth routines, and if it failed then fail
845 this request accordingly */
846 if (!NT_STATUS_IS_OK(status)) {
847 req->status = status;
851 length = pkt->u.response.stub_and_verifier.length;
854 req->payload.data = talloc_realloc(req,
857 req->payload.length + length);
858 if (!req->payload.data) {
859 req->status = NT_STATUS_NO_MEMORY;
862 memcpy(req->payload.data+req->payload.length,
863 pkt->u.response.stub_and_verifier.data, length);
864 req->payload.length += length;
867 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
868 c->transport.send_read(c);
872 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
873 req->flags |= DCERPC_PULL_BIGENDIAN;
875 req->flags &= ~DCERPC_PULL_BIGENDIAN;
880 /* we've got the full payload */
881 req->state = RPC_REQUEST_DONE;
882 DLIST_REMOVE(c->pending, req);
884 if (c->request_queue != NULL) {
885 /* We have to look at shipping further requests before calling
886 * the async function, that one might close the pipe */
887 dcerpc_ship_next_request(c);
890 if (req->async.callback) {
891 req->async.callback(req);
896 make sure requests are cleaned up
898 static int dcerpc_req_destructor(struct rpc_request *req)
900 DLIST_REMOVE(req->p->conn->pending, req);
905 perform the send side of a async dcerpc request
907 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
908 const struct GUID *object,
911 DATA_BLOB *stub_data)
913 struct rpc_request *req;
915 p->conn->transport.recv_data = dcerpc_recv_data;
917 req = talloc(p, struct rpc_request);
923 req->call_id = next_call_id(p->conn);
924 req->status = NT_STATUS_OK;
925 req->state = RPC_REQUEST_PENDING;
926 req->payload = data_blob(NULL, 0);
929 req->async_call = async;
930 req->async.callback = NULL;
931 req->async.private = NULL;
932 req->recv_handler = NULL;
934 if (object != NULL) {
935 req->object = talloc_memdup(req, object, sizeof(*object));
936 if (req->object == NULL) {
945 req->request_data.length = stub_data->length;
946 req->request_data.data = talloc_reference(req, stub_data->data);
947 if (req->request_data.length && req->request_data.data == NULL) {
951 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
953 dcerpc_ship_next_request(p->conn);
955 if (p->request_timeout) {
956 event_add_timed(dcerpc_event_context(p), req,
957 timeval_current_ofs(p->request_timeout, 0),
958 dcerpc_timeout_handler, req);
961 talloc_set_destructor(req, dcerpc_req_destructor);
966 Send a request using the transport
969 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
971 struct rpc_request *req;
972 struct dcerpc_pipe *p;
973 DATA_BLOB *stub_data;
974 struct ncacn_packet pkt;
976 uint32_t remaining, chunk_size;
977 BOOL first_packet = True;
979 req = c->request_queue;
985 stub_data = &req->request_data;
987 if (!req->async_call && (c->pending != NULL)) {
991 DLIST_REMOVE(c->request_queue, req);
992 DLIST_ADD(c->pending, req);
994 init_ncacn_hdr(p->conn, &pkt);
996 remaining = stub_data->length;
998 /* we can write a full max_recv_frag size, minus the dcerpc
999 request header size */
1000 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1002 pkt.ptype = DCERPC_PKT_REQUEST;
1003 pkt.call_id = req->call_id;
1004 pkt.auth_length = 0;
1006 pkt.u.request.alloc_hint = remaining;
1007 pkt.u.request.context_id = p->context_id;
1008 pkt.u.request.opnum = req->opnum;
1011 pkt.u.request.object.object = *req->object;
1012 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1013 chunk_size -= ndr_size_GUID(req->object,0);
1016 /* we send a series of pdus without waiting for a reply */
1017 while (remaining > 0 || first_packet) {
1018 uint32_t chunk = MIN(chunk_size, remaining);
1019 BOOL last_frag = False;
1021 first_packet = False;
1022 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1024 if (remaining == stub_data->length) {
1025 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1027 if (chunk == remaining) {
1028 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1032 pkt.u.request.stub_and_verifier.data = stub_data->data +
1033 (stub_data->length - remaining);
1034 pkt.u.request.stub_and_verifier.length = chunk;
1036 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1037 if (!NT_STATUS_IS_OK(req->status)) {
1038 req->state = RPC_REQUEST_DONE;
1039 DLIST_REMOVE(p->conn->pending, req);
1043 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1044 if (!NT_STATUS_IS_OK(req->status)) {
1045 req->state = RPC_REQUEST_DONE;
1046 DLIST_REMOVE(p->conn->pending, req);
1055 return the event context for a dcerpc pipe
1056 used by callers who wish to operate asynchronously
1058 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1060 return p->conn->event_ctx;
1066 perform the receive side of a async dcerpc request
1068 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1069 TALLOC_CTX *mem_ctx,
1070 DATA_BLOB *stub_data)
1074 while (req->state == RPC_REQUEST_PENDING) {
1075 struct event_context *ctx = dcerpc_event_context(req->p);
1076 if (event_loop_once(ctx) != 0) {
1077 return NT_STATUS_CONNECTION_DISCONNECTED;
1080 *stub_data = req->payload;
1081 status = req->status;
1082 if (stub_data->data) {
1083 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1085 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1086 req->p->last_fault_code = req->fault_code;
1093 perform a full request/response pair on a dcerpc pipe
1095 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1096 struct GUID *object,
1099 TALLOC_CTX *mem_ctx,
1100 DATA_BLOB *stub_data_in,
1101 DATA_BLOB *stub_data_out)
1103 struct rpc_request *req;
1105 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1107 return NT_STATUS_NO_MEMORY;
1110 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1115 this is a paranoid NDR validator. For every packet we push onto the wire
1116 we pull it back again, then push it again. Then we compare the raw NDR data
1117 for that to the NDR we initially generated. If they don't match then we know
1118 we must have a bug in either the pull or push side of our code
1120 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1121 TALLOC_CTX *mem_ctx,
1124 ndr_push_flags_fn_t ndr_push,
1125 ndr_pull_flags_fn_t ndr_pull)
1128 struct ndr_pull *pull;
1129 struct ndr_push *push;
1133 st = talloc_size(mem_ctx, struct_size);
1135 return NT_STATUS_NO_MEMORY;
1138 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1140 return NT_STATUS_NO_MEMORY;
1142 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1144 status = ndr_pull(pull, NDR_IN, st);
1145 if (!NT_STATUS_IS_OK(status)) {
1146 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1147 "failed input validation pull - %s",
1151 push = ndr_push_init_ctx(mem_ctx);
1153 return NT_STATUS_NO_MEMORY;
1156 status = ndr_push(push, NDR_IN, st);
1157 if (!NT_STATUS_IS_OK(status)) {
1158 return ndr_push_error(push, NDR_ERR_VALIDATE,
1159 "failed input validation push - %s",
1163 blob2 = ndr_push_blob(push);
1165 if (!data_blob_equal(&blob, &blob2)) {
1166 DEBUG(3,("original:\n"));
1167 dump_data(3, blob.data, blob.length);
1168 DEBUG(3,("secondary:\n"));
1169 dump_data(3, blob2.data, blob2.length);
1170 return ndr_push_error(push, NDR_ERR_VALIDATE,
1171 "failed input validation data - %s",
1175 return NT_STATUS_OK;
1179 this is a paranoid NDR input validator. For every packet we pull
1180 from the wire we push it back again then pull and push it
1181 again. Then we compare the raw NDR data for that to the NDR we
1182 initially generated. If they don't match then we know we must have a
1183 bug in either the pull or push side of our code
1185 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1186 struct ndr_pull *pull_in,
1189 ndr_push_flags_fn_t ndr_push,
1190 ndr_pull_flags_fn_t ndr_pull,
1191 ndr_print_function_t ndr_print)
1194 struct ndr_pull *pull;
1195 struct ndr_push *push;
1197 DATA_BLOB blob, blob2;
1198 TALLOC_CTX *mem_ctx = pull_in;
1201 st = talloc_size(mem_ctx, struct_size);
1203 return NT_STATUS_NO_MEMORY;
1205 memcpy(st, struct_ptr, struct_size);
1207 push = ndr_push_init_ctx(mem_ctx);
1209 return NT_STATUS_NO_MEMORY;
1212 status = ndr_push(push, NDR_OUT, struct_ptr);
1213 if (!NT_STATUS_IS_OK(status)) {
1214 return ndr_push_error(push, NDR_ERR_VALIDATE,
1215 "failed output validation push - %s",
1219 blob = ndr_push_blob(push);
1221 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1223 return NT_STATUS_NO_MEMORY;
1226 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1227 status = ndr_pull(pull, NDR_OUT, st);
1228 if (!NT_STATUS_IS_OK(status)) {
1229 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1230 "failed output validation pull - %s",
1234 push = ndr_push_init_ctx(mem_ctx);
1236 return NT_STATUS_NO_MEMORY;
1239 status = ndr_push(push, NDR_OUT, st);
1240 if (!NT_STATUS_IS_OK(status)) {
1241 return ndr_push_error(push, NDR_ERR_VALIDATE,
1242 "failed output validation push2 - %s",
1246 blob2 = ndr_push_blob(push);
1248 if (!data_blob_equal(&blob, &blob2)) {
1249 DEBUG(3,("original:\n"));
1250 dump_data(3, blob.data, blob.length);
1251 DEBUG(3,("secondary:\n"));
1252 dump_data(3, blob2.data, blob2.length);
1253 return ndr_push_error(push, NDR_ERR_VALIDATE,
1254 "failed output validation data - %s",
1258 /* this checks the printed forms of the two structures, which effectively
1259 tests all of the value() attributes */
1260 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1261 NDR_OUT, struct_ptr);
1262 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1264 if (strcmp(s1, s2) != 0) {
1266 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1268 /* this is sometimes useful */
1269 printf("VALIDATE ERROR\n");
1270 file_save("wire.dat", s1, strlen(s1));
1271 file_save("gen.dat", s2, strlen(s2));
1272 system("diff -u wire.dat gen.dat");
1276 return NT_STATUS_OK;
1281 send a rpc request given a dcerpc_call structure
1283 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1284 const struct GUID *object,
1285 const struct dcerpc_interface_table *table,
1287 TALLOC_CTX *mem_ctx,
1290 const struct dcerpc_interface_call *call;
1291 struct ndr_push *push;
1294 struct rpc_request *req;
1296 call = &table->calls[opnum];
1298 /* setup for a ndr_push_* call */
1299 push = ndr_push_init_ctx(mem_ctx);
1304 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1305 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1308 /* push the structure into a blob */
1309 status = call->ndr_push(push, NDR_IN, r);
1310 if (!NT_STATUS_IS_OK(status)) {
1311 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1312 nt_errstr(status)));
1317 /* retrieve the blob */
1318 request = ndr_push_blob(push);
1320 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1321 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1322 call->ndr_push, call->ndr_pull);
1323 if (!NT_STATUS_IS_OK(status)) {
1324 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1325 nt_errstr(status)));
1331 DEBUG(10,("rpc request data:\n"));
1332 dump_data(10, request.data, request.length);
1334 /* make the actual dcerpc request */
1335 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1339 req->ndr.table = table;
1340 req->ndr.opnum = opnum;
1341 req->ndr.struct_ptr = r;
1342 req->ndr.mem_ctx = mem_ctx;
1351 receive the answer from a dcerpc_ndr_request_send()
1353 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1355 struct dcerpc_pipe *p = req->p;
1358 struct ndr_pull *pull;
1360 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1361 void *r = req->ndr.struct_ptr;
1362 uint32_t opnum = req->ndr.opnum;
1363 const struct dcerpc_interface_table *table = req->ndr.table;
1364 const struct dcerpc_interface_call *call = &table->calls[opnum];
1366 /* make sure the recv code doesn't free the request, as we
1367 need to grab the flags element before it is freed */
1368 talloc_increase_ref_count(req);
1370 status = dcerpc_request_recv(req, mem_ctx, &response);
1371 if (!NT_STATUS_IS_OK(status)) {
1377 /* prepare for ndr_pull_* */
1378 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1381 return NT_STATUS_NO_MEMORY;
1385 pull->data = talloc_steal(pull, pull->data);
1389 if (flags & DCERPC_PULL_BIGENDIAN) {
1390 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1393 DEBUG(10,("rpc reply data:\n"));
1394 dump_data(10, pull->data, pull->data_size);
1396 /* pull the structure from the blob */
1397 status = call->ndr_pull(pull, NDR_OUT, r);
1398 if (!NT_STATUS_IS_OK(status)) {
1399 dcerpc_log_packet(table, opnum, NDR_OUT,
1404 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1405 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1406 call->ndr_push, call->ndr_pull,
1408 if (!NT_STATUS_IS_OK(status)) {
1409 dcerpc_log_packet(table, opnum, NDR_OUT,
1415 if (pull->offset != pull->data_size) {
1416 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1417 pull->data_size - pull->offset));
1418 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1419 but it turns out that early versions of NT
1420 (specifically NT3.1) add junk onto the end of rpc
1421 packets, so if we want to interoperate at all with
1422 those versions then we need to ignore this error */
1425 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1427 return NT_STATUS_OK;
1432 a useful helper function for synchronous rpc requests
1434 this can be used when you have ndr push/pull functions in the
1437 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1438 const struct GUID *object,
1439 const struct dcerpc_interface_table *table,
1441 TALLOC_CTX *mem_ctx,
1444 struct rpc_request *req;
1446 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1448 return NT_STATUS_NO_MEMORY;
1451 return dcerpc_ndr_request_recv(req);
1456 a useful function for retrieving the server name we connected to
1458 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1460 if (!p->conn->transport.peer_name) {
1463 return p->conn->transport.peer_name(p->conn);
1468 get the dcerpc auth_level for a open connection
1470 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1474 if (c->flags & DCERPC_SEAL) {
1475 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1476 } else if (c->flags & DCERPC_SIGN) {
1477 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1478 } else if (c->flags & DCERPC_CONNECT) {
1479 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1481 auth_level = DCERPC_AUTH_LEVEL_NONE;
1487 Receive an alter reply from the transport
1489 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1490 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1492 struct composite_context *c;
1493 struct dcerpc_pipe *recv_pipe;
1495 c = talloc_get_type(req->async.private, struct composite_context);
1496 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1498 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1499 pkt->u.alter_resp.num_results == 1 &&
1500 pkt->u.alter_resp.ctx_list[0].result != 0) {
1501 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1502 pkt->u.alter_resp.ctx_list[0].reason));
1503 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1507 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1508 pkt->u.alter_resp.num_results == 0 ||
1509 pkt->u.alter_resp.ctx_list[0].result != 0) {
1510 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1514 /* the alter_resp might contain a reply set of credentials */
1515 if (recv_pipe->conn->security_state.auth_info &&
1516 pkt->u.alter_resp.auth_info.length) {
1517 c->status = ndr_pull_struct_blob(
1518 &pkt->u.alter_resp.auth_info, recv_pipe,
1519 recv_pipe->conn->security_state.auth_info,
1520 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1521 if (!composite_is_ok(c)) return;
1528 send a dcerpc alter_context request
1530 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1531 TALLOC_CTX *mem_ctx,
1532 const struct dcerpc_syntax_id *syntax,
1533 const struct dcerpc_syntax_id *transfer_syntax)
1535 struct composite_context *c;
1536 struct ncacn_packet pkt;
1538 struct rpc_request *req;
1540 c = composite_create(mem_ctx, p->conn->event_ctx);
1541 if (c == NULL) return NULL;
1543 c->private_data = p;
1545 p->syntax = *syntax;
1546 p->transfer_syntax = *transfer_syntax;
1548 init_ncacn_hdr(p->conn, &pkt);
1550 pkt.ptype = DCERPC_PKT_ALTER;
1551 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1552 pkt.call_id = p->conn->call_id;
1553 pkt.auth_length = 0;
1555 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1556 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1559 pkt.u.alter.max_xmit_frag = 5840;
1560 pkt.u.alter.max_recv_frag = 5840;
1561 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1562 pkt.u.alter.num_contexts = 1;
1563 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1564 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1565 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1566 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1567 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1568 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1569 pkt.u.alter.auth_info = data_blob(NULL, 0);
1571 /* construct the NDR form of the packet */
1572 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1573 p->conn->security_state.auth_info);
1574 if (!composite_is_ok(c)) return c;
1576 p->conn->transport.recv_data = dcerpc_recv_data;
1579 * we allocate a dcerpc_request so we can be in the same
1580 * request queue as normal requests
1582 req = talloc_zero(c, struct rpc_request);
1583 if (composite_nomem(req, c)) return c;
1585 req->state = RPC_REQUEST_PENDING;
1586 req->call_id = pkt.call_id;
1587 req->async.private = c;
1588 req->async.callback = dcerpc_composite_fail;
1590 req->recv_handler = dcerpc_alter_recv_handler;
1591 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1593 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1594 if (!composite_is_ok(c)) return c;
1596 event_add_timed(c->event_ctx, req,
1597 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1598 dcerpc_timeout_handler, req);
1603 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1605 NTSTATUS result = composite_wait(ctx);
1611 send a dcerpc alter_context request
1613 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1614 TALLOC_CTX *mem_ctx,
1615 const struct dcerpc_syntax_id *syntax,
1616 const struct dcerpc_syntax_id *transfer_syntax)
1618 struct composite_context *creq;
1619 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1620 return dcerpc_alter_context_recv(creq);