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 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)) {
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_ORPC) {
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 c->security_state.auth_info->credentials
373 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
375 data_blob_clear(&c->security_state.auth_info->credentials);
378 case DCERPC_AUTH_LEVEL_CONNECT:
379 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
382 case DCERPC_AUTH_LEVEL_NONE:
383 c->security_state.auth_info->credentials = data_blob(NULL, 0);
387 status = NT_STATUS_INVALID_LEVEL;
391 if (!NT_STATUS_IS_OK(status)) {
395 /* add the auth verifier */
396 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
397 if (!NT_STATUS_IS_OK(status)) {
401 /* extract the whole packet as a blob */
402 *blob = ndr_push_blob(ndr);
404 /* fill in the fragment length and auth_length, we can't fill
405 in these earlier as we don't know the signature length (it
406 could be variable length) */
407 dcerpc_set_frag_length(blob, blob->length);
408 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
410 /* sign or seal the packet */
411 switch (c->security_state.auth_info->auth_level) {
412 case DCERPC_AUTH_LEVEL_PRIVACY:
413 status = gensec_seal_packet(c->security_state.generic_state,
415 blob->data + DCERPC_REQUEST_LENGTH,
419 c->security_state.auth_info->credentials.length,
421 if (!NT_STATUS_IS_OK(status)) {
424 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
427 case DCERPC_AUTH_LEVEL_INTEGRITY:
428 status = gensec_sign_packet(c->security_state.generic_state,
430 blob->data + DCERPC_REQUEST_LENGTH,
434 c->security_state.auth_info->credentials.length,
436 if (!NT_STATUS_IS_OK(status)) {
439 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
442 case DCERPC_AUTH_LEVEL_CONNECT:
445 case DCERPC_AUTH_LEVEL_NONE:
446 c->security_state.auth_info->credentials = data_blob(NULL, 0);
450 status = NT_STATUS_INVALID_LEVEL;
454 data_blob_free(&c->security_state.auth_info->credentials);
461 fill in the fixed values in a dcerpc header
463 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
466 pkt->rpc_vers_minor = 0;
467 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
470 pkt->drep[0] = DCERPC_DREP_LE;
478 map a bind nak reason to a NTSTATUS
480 static NTSTATUS dcerpc_map_reason(uint16_t reason)
483 case DCERPC_BIND_REASON_ASYNTAX:
484 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
485 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
486 return NT_STATUS_INVALID_PARAMETER;
488 return NT_STATUS_UNSUCCESSFUL;
492 a bind or alter context has failed
494 static void dcerpc_composite_fail(struct rpc_request *req)
496 struct composite_context *c = talloc_get_type(req->async.private,
497 struct composite_context);
498 composite_error(c, req->status);
502 mark the dcerpc connection dead. All outstanding requests get an error
504 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
506 /* all pending requests get the error */
507 while (conn->pending) {
508 struct rpc_request *req = conn->pending;
509 req->state = RPC_REQUEST_DONE;
510 req->status = status;
511 DLIST_REMOVE(conn->pending, req);
512 if (req->async.callback) {
513 req->async.callback(req);
519 forward declarations of the recv_data handlers for the types of
520 packets we need to handle
522 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
523 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
526 receive a dcerpc reply from the transport. Here we work out what
527 type of reply it is (normal request, bind or alter context) and
528 dispatch to the appropriate handler
530 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
532 struct ncacn_packet pkt;
534 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
535 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
538 /* the transport may be telling us of a severe error, such as
540 if (!NT_STATUS_IS_OK(status)) {
541 data_blob_free(blob);
542 dcerpc_connection_dead(conn, status);
546 /* parse the basic packet to work out what type of response this is */
547 status = ncacn_pull(conn, blob, blob->data, &pkt);
548 if (!NT_STATUS_IS_OK(status)) {
549 data_blob_free(blob);
550 dcerpc_connection_dead(conn, status);
553 dcerpc_request_recv_data(conn, blob, &pkt);
558 Receive a bind reply from the transport
560 static void dcerpc_bind_recv_handler(struct rpc_request *req,
561 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
563 struct composite_context *c;
564 struct dcerpc_connection *conn;
566 c = talloc_get_type(req->async.private, struct composite_context);
568 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
569 DEBUG(2,("dcerpc: bind_nak reason %d\n",
570 pkt->u.bind_nak.reject_reason));
571 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
576 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
577 (pkt->u.bind_ack.num_results == 0) ||
578 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
579 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
585 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
586 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
588 /* the bind_ack might contain a reply set of credentials */
589 if (conn->security_state.auth_info &&
590 pkt->u.bind_ack.auth_info.length) {
591 c->status = ndr_pull_struct_blob(
592 &pkt->u.bind_ack.auth_info, conn,
593 conn->security_state.auth_info,
594 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
595 if (!composite_is_ok(c)) return;
602 handle timeouts of individual dcerpc requests
604 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
605 struct timeval t, void *private)
607 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
609 if (req->state != RPC_REQUEST_PENDING) {
613 req->status = NT_STATUS_IO_TIMEOUT;
614 req->state = RPC_REQUEST_DONE;
615 DLIST_REMOVE(req->p->conn->pending, req);
616 if (req->async.callback) {
617 req->async.callback(req);
623 send a async dcerpc bind request
625 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
627 const struct dcerpc_syntax_id *syntax,
628 const struct dcerpc_syntax_id *transfer_syntax)
630 struct composite_context *c;
631 struct ncacn_packet pkt;
633 struct rpc_request *req;
635 c = composite_create(mem_ctx,p->conn->event_ctx);
636 if (c == NULL) return NULL;
641 p->transfer_syntax = *transfer_syntax;
643 init_ncacn_hdr(p->conn, &pkt);
645 pkt.ptype = DCERPC_PKT_BIND;
646 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
647 pkt.call_id = p->conn->call_id;
650 pkt.u.bind.max_xmit_frag = 5840;
651 pkt.u.bind.max_recv_frag = 5840;
652 pkt.u.bind.assoc_group_id = 0;
653 pkt.u.bind.num_contexts = 1;
654 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
655 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
656 pkt.u.bind.ctx_list[0].context_id = p->context_id;
657 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
658 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
659 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
660 pkt.u.bind.auth_info = data_blob(NULL, 0);
662 /* construct the NDR form of the packet */
663 c->status = ncacn_push_auth(&blob, c, &pkt,
664 p->conn->security_state.auth_info);
665 if (!composite_is_ok(c)) return c;
667 p->conn->transport.recv_data = dcerpc_recv_data;
670 * we allocate a dcerpc_request so we can be in the same
671 * request queue as normal requests
673 req = talloc_zero(c, struct rpc_request);
674 if (composite_nomem(req, c)) return c;
676 req->state = RPC_REQUEST_PENDING;
677 req->call_id = pkt.call_id;
678 req->async.private = c;
679 req->async.callback = dcerpc_composite_fail;
681 req->recv_handler = dcerpc_bind_recv_handler;
682 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
684 c->status = p->conn->transport.send_request(p->conn, &blob,
686 if (!composite_is_ok(c)) return c;
688 event_add_timed(c->event_ctx, req,
689 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
690 dcerpc_timeout_handler, req);
696 recv side of async dcerpc bind request
698 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
700 NTSTATUS result = composite_wait(ctx);
706 perform a bind using the given syntax
708 the auth_info structure is updated with the reply authentication info
711 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
713 const struct dcerpc_syntax_id *syntax,
714 const struct dcerpc_syntax_id *transfer_syntax)
716 struct composite_context *creq;
717 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
718 return dcerpc_bind_recv(creq);
722 perform a continued bind (and auth3)
724 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
727 struct ncacn_packet pkt;
731 init_ncacn_hdr(c, &pkt);
733 pkt.ptype = DCERPC_PKT_AUTH3;
734 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
735 pkt.call_id = next_call_id(c);
737 pkt.u.auth3._pad = 0;
738 pkt.u.auth3.auth_info = data_blob(NULL, 0);
740 /* construct the NDR form of the packet */
741 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
742 if (!NT_STATUS_IS_OK(status)) {
746 /* send it on its way */
747 status = c->transport.send_request(c, &blob, False);
748 if (!NT_STATUS_IS_OK(status)) {
757 return the rpc syntax and transfer syntax given the pipe uuid and version
759 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
760 struct dcerpc_syntax_id *syntax,
761 struct dcerpc_syntax_id *transfer_syntax)
763 syntax->uuid = table->syntax_id.uuid;
764 syntax->if_version = table->syntax_id.if_version;
766 *transfer_syntax = ndr_transfer_syntax;
771 /* perform a dcerpc bind, using the uuid as the key */
772 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
774 const struct dcerpc_interface_table *table)
776 struct dcerpc_syntax_id syntax;
777 struct dcerpc_syntax_id transfer_syntax;
780 status = dcerpc_init_syntaxes(table,
781 &syntax, &transfer_syntax);
782 if (!NT_STATUS_IS_OK(status)) {
783 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
787 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
792 process a fragment received from the transport layer during a
795 This function frees the data
797 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
798 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
800 struct rpc_request *req;
802 NTSTATUS status = NT_STATUS_OK;
805 if this is an authenticated connection then parse and check
806 the auth info. We have to do this before finding the
807 matching packet, as the request structure might have been
808 removed due to a timeout, but if it has been we still need
809 to run the auth routines so that we don't get the sign/seal
810 info out of step with the server
812 if (c->security_state.auth_info && c->security_state.generic_state &&
813 pkt->ptype == DCERPC_PKT_RESPONSE) {
814 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
817 /* find the matching request */
818 for (req=c->pending;req;req=req->next) {
819 if (pkt->call_id == req->call_id) break;
823 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
824 data_blob_free(raw_packet);
828 talloc_steal(req, raw_packet->data);
830 if (req->recv_handler != NULL) {
831 req->state = RPC_REQUEST_DONE;
832 DLIST_REMOVE(c->pending, req);
833 req->recv_handler(req, raw_packet, pkt);
837 if (pkt->ptype == DCERPC_PKT_FAULT) {
838 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
839 req->fault_code = pkt->u.fault.status;
840 req->status = NT_STATUS_NET_WRITE_FAULT;
844 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
845 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
847 req->fault_code = DCERPC_FAULT_OTHER;
848 req->status = NT_STATUS_NET_WRITE_FAULT;
852 /* now check the status from the auth routines, and if it failed then fail
853 this request accordingly */
854 if (!NT_STATUS_IS_OK(status)) {
855 req->status = status;
859 length = pkt->u.response.stub_and_verifier.length;
862 req->payload.data = talloc_realloc(req,
865 req->payload.length + length);
866 if (!req->payload.data) {
867 req->status = NT_STATUS_NO_MEMORY;
870 memcpy(req->payload.data+req->payload.length,
871 pkt->u.response.stub_and_verifier.data, length);
872 req->payload.length += length;
875 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
876 c->transport.send_read(c);
880 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
881 req->flags |= DCERPC_PULL_BIGENDIAN;
883 req->flags &= ~DCERPC_PULL_BIGENDIAN;
888 /* we've got the full payload */
889 req->state = RPC_REQUEST_DONE;
890 DLIST_REMOVE(c->pending, req);
892 if (c->request_queue != NULL) {
893 /* We have to look at shipping further requests before calling
894 * the async function, that one might close the pipe */
895 dcerpc_ship_next_request(c);
898 if (req->async.callback) {
899 req->async.callback(req);
904 make sure requests are cleaned up
906 static int dcerpc_req_destructor(struct rpc_request *req)
908 DLIST_REMOVE(req->p->conn->pending, req);
913 perform the send side of a async dcerpc request
915 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
916 const struct GUID *object,
919 DATA_BLOB *stub_data)
921 struct rpc_request *req;
923 p->conn->transport.recv_data = dcerpc_recv_data;
925 req = talloc(p, struct rpc_request);
931 req->call_id = next_call_id(p->conn);
932 req->status = NT_STATUS_OK;
933 req->state = RPC_REQUEST_PENDING;
934 req->payload = data_blob(NULL, 0);
937 req->async_call = async;
938 req->async.callback = NULL;
939 req->async.private = NULL;
940 req->recv_handler = NULL;
942 if (object != NULL) {
943 req->object = talloc_memdup(req, object, sizeof(*object));
944 if (req->object == NULL) {
953 req->request_data.length = stub_data->length;
954 req->request_data.data = talloc_reference(req, stub_data->data);
955 if (req->request_data.data == NULL) {
959 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
961 dcerpc_ship_next_request(p->conn);
963 if (p->request_timeout) {
964 event_add_timed(dcerpc_event_context(p), req,
965 timeval_current_ofs(p->request_timeout, 0),
966 dcerpc_timeout_handler, req);
969 talloc_set_destructor(req, dcerpc_req_destructor);
974 Send a request using the transport
977 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
979 struct rpc_request *req;
980 struct dcerpc_pipe *p;
981 DATA_BLOB *stub_data;
982 struct ncacn_packet pkt;
984 uint32_t remaining, chunk_size;
985 BOOL first_packet = True;
987 req = c->request_queue;
993 stub_data = &req->request_data;
995 if (!req->async_call && (c->pending != NULL)) {
999 DLIST_REMOVE(c->request_queue, req);
1000 DLIST_ADD(c->pending, req);
1002 init_ncacn_hdr(p->conn, &pkt);
1004 remaining = stub_data->length;
1006 /* we can write a full max_recv_frag size, minus the dcerpc
1007 request header size */
1008 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1010 pkt.ptype = DCERPC_PKT_REQUEST;
1011 pkt.call_id = req->call_id;
1012 pkt.auth_length = 0;
1014 pkt.u.request.alloc_hint = remaining;
1015 pkt.u.request.context_id = p->context_id;
1016 pkt.u.request.opnum = req->opnum;
1019 pkt.u.request.object.object = *req->object;
1020 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1021 chunk_size -= ndr_size_GUID(req->object,0);
1024 /* we send a series of pdus without waiting for a reply */
1025 while (remaining > 0 || first_packet) {
1026 uint32_t chunk = MIN(chunk_size, remaining);
1027 BOOL last_frag = False;
1029 first_packet = False;
1030 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1032 if (remaining == stub_data->length) {
1033 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1035 if (chunk == remaining) {
1036 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1040 pkt.u.request.stub_and_verifier.data = stub_data->data +
1041 (stub_data->length - remaining);
1042 pkt.u.request.stub_and_verifier.length = chunk;
1044 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1045 if (!NT_STATUS_IS_OK(req->status)) {
1046 req->state = RPC_REQUEST_DONE;
1047 DLIST_REMOVE(p->conn->pending, req);
1051 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1052 if (!NT_STATUS_IS_OK(req->status)) {
1053 req->state = RPC_REQUEST_DONE;
1054 DLIST_REMOVE(p->conn->pending, req);
1063 return the event context for a dcerpc pipe
1064 used by callers who wish to operate asynchronously
1066 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1068 return p->conn->event_ctx;
1074 perform the receive side of a async dcerpc request
1076 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1077 TALLOC_CTX *mem_ctx,
1078 DATA_BLOB *stub_data)
1082 while (req->state == RPC_REQUEST_PENDING) {
1083 struct event_context *ctx = dcerpc_event_context(req->p);
1084 if (event_loop_once(ctx) != 0) {
1085 return NT_STATUS_CONNECTION_DISCONNECTED;
1088 *stub_data = req->payload;
1089 status = req->status;
1090 if (stub_data->data) {
1091 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1093 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1094 req->p->last_fault_code = req->fault_code;
1101 perform a full request/response pair on a dcerpc pipe
1103 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1104 struct GUID *object,
1107 TALLOC_CTX *mem_ctx,
1108 DATA_BLOB *stub_data_in,
1109 DATA_BLOB *stub_data_out)
1111 struct rpc_request *req;
1113 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1115 return NT_STATUS_NO_MEMORY;
1118 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1123 this is a paranoid NDR validator. For every packet we push onto the wire
1124 we pull it back again, then push it again. Then we compare the raw NDR data
1125 for that to the NDR we initially generated. If they don't match then we know
1126 we must have a bug in either the pull or push side of our code
1128 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1129 TALLOC_CTX *mem_ctx,
1132 ndr_push_flags_fn_t ndr_push,
1133 ndr_pull_flags_fn_t ndr_pull)
1136 struct ndr_pull *pull;
1137 struct ndr_push *push;
1141 st = talloc_size(mem_ctx, struct_size);
1143 return NT_STATUS_NO_MEMORY;
1146 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1148 return NT_STATUS_NO_MEMORY;
1150 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1152 status = ndr_pull(pull, NDR_IN, st);
1153 if (!NT_STATUS_IS_OK(status)) {
1154 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1155 "failed input validation pull - %s",
1159 push = ndr_push_init_ctx(mem_ctx);
1161 return NT_STATUS_NO_MEMORY;
1164 status = ndr_push(push, NDR_IN, st);
1165 if (!NT_STATUS_IS_OK(status)) {
1166 return ndr_push_error(push, NDR_ERR_VALIDATE,
1167 "failed input validation push - %s",
1171 blob2 = ndr_push_blob(push);
1173 if (!data_blob_equal(&blob, &blob2)) {
1174 DEBUG(3,("original:\n"));
1175 dump_data(3, blob.data, blob.length);
1176 DEBUG(3,("secondary:\n"));
1177 dump_data(3, blob2.data, blob2.length);
1178 return ndr_push_error(push, NDR_ERR_VALIDATE,
1179 "failed input validation data - %s",
1183 return NT_STATUS_OK;
1187 this is a paranoid NDR input validator. For every packet we pull
1188 from the wire we push it back again then pull and push it
1189 again. Then we compare the raw NDR data for that to the NDR we
1190 initially generated. If they don't match then we know we must have a
1191 bug in either the pull or push side of our code
1193 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1194 struct ndr_pull *pull_in,
1197 ndr_push_flags_fn_t ndr_push,
1198 ndr_pull_flags_fn_t ndr_pull,
1199 ndr_print_function_t ndr_print)
1202 struct ndr_pull *pull;
1203 struct ndr_push *push;
1205 DATA_BLOB blob, blob2;
1206 TALLOC_CTX *mem_ctx = pull_in;
1209 st = talloc_size(mem_ctx, struct_size);
1211 return NT_STATUS_NO_MEMORY;
1213 memcpy(st, struct_ptr, struct_size);
1215 push = ndr_push_init_ctx(mem_ctx);
1217 return NT_STATUS_NO_MEMORY;
1220 status = ndr_push(push, NDR_OUT, struct_ptr);
1221 if (!NT_STATUS_IS_OK(status)) {
1222 return ndr_push_error(push, NDR_ERR_VALIDATE,
1223 "failed output validation push - %s",
1227 blob = ndr_push_blob(push);
1229 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1231 return NT_STATUS_NO_MEMORY;
1234 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1235 status = ndr_pull(pull, NDR_OUT, st);
1236 if (!NT_STATUS_IS_OK(status)) {
1237 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1238 "failed output validation pull - %s",
1242 push = ndr_push_init_ctx(mem_ctx);
1244 return NT_STATUS_NO_MEMORY;
1247 status = ndr_push(push, NDR_OUT, st);
1248 if (!NT_STATUS_IS_OK(status)) {
1249 return ndr_push_error(push, NDR_ERR_VALIDATE,
1250 "failed output validation push2 - %s",
1254 blob2 = ndr_push_blob(push);
1256 if (!data_blob_equal(&blob, &blob2)) {
1257 DEBUG(3,("original:\n"));
1258 dump_data(3, blob.data, blob.length);
1259 DEBUG(3,("secondary:\n"));
1260 dump_data(3, blob2.data, blob2.length);
1261 return ndr_push_error(push, NDR_ERR_VALIDATE,
1262 "failed output validation data - %s",
1266 /* this checks the printed forms of the two structures, which effectively
1267 tests all of the value() attributes */
1268 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1269 NDR_OUT, struct_ptr);
1270 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1272 if (strcmp(s1, s2) != 0) {
1274 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1276 /* this is sometimes useful */
1277 printf("VALIDATE ERROR\n");
1278 file_save("wire.dat", s1, strlen(s1));
1279 file_save("gen.dat", s2, strlen(s2));
1280 system("diff -u wire.dat gen.dat");
1284 return NT_STATUS_OK;
1289 send a rpc request given a dcerpc_call structure
1291 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1292 const struct GUID *object,
1293 const struct dcerpc_interface_table *table,
1295 TALLOC_CTX *mem_ctx,
1298 const struct dcerpc_interface_call *call;
1299 struct ndr_push *push;
1302 struct rpc_request *req;
1304 call = &table->calls[opnum];
1306 /* setup for a ndr_push_* call */
1307 push = ndr_push_init_ctx(mem_ctx);
1312 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1313 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1316 /* push the structure into a blob */
1317 status = call->ndr_push(push, NDR_IN, r);
1318 if (!NT_STATUS_IS_OK(status)) {
1319 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1320 nt_errstr(status)));
1325 /* retrieve the blob */
1326 request = ndr_push_blob(push);
1328 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1329 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1330 call->ndr_push, call->ndr_pull);
1331 if (!NT_STATUS_IS_OK(status)) {
1332 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1333 nt_errstr(status)));
1339 DEBUG(10,("rpc request data:\n"));
1340 dump_data(10, request.data, request.length);
1342 /* make the actual dcerpc request */
1343 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1347 req->ndr.table = table;
1348 req->ndr.opnum = opnum;
1349 req->ndr.struct_ptr = r;
1350 req->ndr.mem_ctx = mem_ctx;
1359 receive the answer from a dcerpc_ndr_request_send()
1361 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1363 struct dcerpc_pipe *p = req->p;
1366 struct ndr_pull *pull;
1368 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1369 void *r = req->ndr.struct_ptr;
1370 uint32_t opnum = req->ndr.opnum;
1371 const struct dcerpc_interface_table *table = req->ndr.table;
1372 const struct dcerpc_interface_call *call = &table->calls[opnum];
1374 /* make sure the recv code doesn't free the request, as we
1375 need to grab the flags element before it is freed */
1376 talloc_increase_ref_count(req);
1378 status = dcerpc_request_recv(req, mem_ctx, &response);
1379 if (!NT_STATUS_IS_OK(status)) {
1385 /* prepare for ndr_pull_* */
1386 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1389 return NT_STATUS_NO_MEMORY;
1393 pull->data = talloc_steal(pull, pull->data);
1397 if (flags & DCERPC_PULL_BIGENDIAN) {
1398 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1401 DEBUG(10,("rpc reply data:\n"));
1402 dump_data(10, pull->data, pull->data_size);
1404 /* pull the structure from the blob */
1405 status = call->ndr_pull(pull, NDR_OUT, r);
1406 if (!NT_STATUS_IS_OK(status)) {
1407 dcerpc_log_packet(table, opnum, NDR_OUT,
1412 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1413 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1414 call->ndr_push, call->ndr_pull,
1416 if (!NT_STATUS_IS_OK(status)) {
1417 dcerpc_log_packet(table, opnum, NDR_OUT,
1423 if (pull->offset != pull->data_size) {
1424 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1425 pull->data_size - pull->offset));
1426 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1427 but it turns out that early versions of NT
1428 (specifically NT3.1) add junk onto the end of rpc
1429 packets, so if we want to interoperate at all with
1430 those versions then we need to ignore this error */
1433 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1435 return NT_STATUS_OK;
1440 a useful helper function for synchronous rpc requests
1442 this can be used when you have ndr push/pull functions in the
1445 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1446 const struct GUID *object,
1447 const struct dcerpc_interface_table *table,
1449 TALLOC_CTX *mem_ctx,
1452 struct rpc_request *req;
1454 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1456 return NT_STATUS_NO_MEMORY;
1459 return dcerpc_ndr_request_recv(req);
1464 a useful function for retrieving the server name we connected to
1466 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1468 if (!p->conn->transport.peer_name) {
1471 return p->conn->transport.peer_name(p->conn);
1476 get the dcerpc auth_level for a open connection
1478 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1482 if (c->flags & DCERPC_SEAL) {
1483 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1484 } else if (c->flags & DCERPC_SIGN) {
1485 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1486 } else if (c->flags & DCERPC_CONNECT) {
1487 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1489 auth_level = DCERPC_AUTH_LEVEL_NONE;
1495 Receive an alter reply from the transport
1497 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1498 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1500 struct composite_context *c;
1501 struct dcerpc_pipe *recv_pipe;
1503 c = talloc_get_type(req->async.private, struct composite_context);
1504 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1506 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1507 pkt->u.alter_resp.num_results == 1 &&
1508 pkt->u.alter_resp.ctx_list[0].result != 0) {
1509 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1510 pkt->u.alter_resp.ctx_list[0].reason));
1511 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1515 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1516 pkt->u.alter_resp.num_results == 0 ||
1517 pkt->u.alter_resp.ctx_list[0].result != 0) {
1518 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1522 /* the alter_resp might contain a reply set of credentials */
1523 if (recv_pipe->conn->security_state.auth_info &&
1524 pkt->u.alter_resp.auth_info.length) {
1525 c->status = ndr_pull_struct_blob(
1526 &pkt->u.alter_resp.auth_info, recv_pipe,
1527 recv_pipe->conn->security_state.auth_info,
1528 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1529 if (!composite_is_ok(c)) return;
1536 send a dcerpc alter_context request
1538 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1539 TALLOC_CTX *mem_ctx,
1540 const struct dcerpc_syntax_id *syntax,
1541 const struct dcerpc_syntax_id *transfer_syntax)
1543 struct composite_context *c;
1544 struct ncacn_packet pkt;
1546 struct rpc_request *req;
1548 c = composite_create(mem_ctx, p->conn->event_ctx);
1549 if (c == NULL) return NULL;
1551 c->private_data = p;
1553 p->syntax = *syntax;
1554 p->transfer_syntax = *transfer_syntax;
1556 init_ncacn_hdr(p->conn, &pkt);
1558 pkt.ptype = DCERPC_PKT_ALTER;
1559 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1560 pkt.call_id = p->conn->call_id;
1561 pkt.auth_length = 0;
1563 pkt.u.alter.max_xmit_frag = 5840;
1564 pkt.u.alter.max_recv_frag = 5840;
1565 pkt.u.alter.assoc_group_id = 0;
1566 pkt.u.alter.num_contexts = 1;
1567 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1568 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1569 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1570 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1571 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1572 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1573 pkt.u.alter.auth_info = data_blob(NULL, 0);
1575 /* construct the NDR form of the packet */
1576 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1577 p->conn->security_state.auth_info);
1578 if (!composite_is_ok(c)) return c;
1580 p->conn->transport.recv_data = dcerpc_recv_data;
1583 * we allocate a dcerpc_request so we can be in the same
1584 * request queue as normal requests
1586 req = talloc_zero(c, struct rpc_request);
1587 if (composite_nomem(req, c)) return c;
1589 req->state = RPC_REQUEST_PENDING;
1590 req->call_id = pkt.call_id;
1591 req->async.private = c;
1592 req->async.callback = dcerpc_composite_fail;
1594 req->recv_handler = dcerpc_alter_recv_handler;
1595 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1597 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1598 if (!composite_is_ok(c)) return c;
1600 event_add_timed(c->event_ctx, req,
1601 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1602 dcerpc_timeout_handler, req);
1607 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1609 NTSTATUS result = composite_wait(ctx);
1615 send a dcerpc alter_context request
1617 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1618 TALLOC_CTX *mem_ctx,
1619 const struct dcerpc_syntax_id *syntax,
1620 const struct dcerpc_syntax_id *transfer_syntax)
1622 struct composite_context *creq;
1623 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1624 return dcerpc_alter_context_recv(creq);