2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/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 /* we allocate a dcerpc_request so we can be in the same
636 request queue as normal requests, but most of the request
637 fields are not used as there is no call id */
638 req = talloc_zero(mem_ctx, struct rpc_request);
639 if (req == NULL) return NULL;
641 c = talloc_zero(mem_ctx, struct composite_context);
642 if (c == NULL) return NULL;
644 c->state = COMPOSITE_STATE_IN_PROGRESS;
646 c->event_ctx = p->conn->event_ctx;
649 p->transfer_syntax = *transfer_syntax;
651 init_ncacn_hdr(p->conn, &pkt);
653 pkt.ptype = DCERPC_PKT_BIND;
654 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
655 pkt.call_id = p->conn->call_id;
658 pkt.u.bind.max_xmit_frag = 5840;
659 pkt.u.bind.max_recv_frag = 5840;
660 pkt.u.bind.assoc_group_id = 0;
661 pkt.u.bind.num_contexts = 1;
662 pkt.u.bind.ctx_list =
663 talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
664 if (pkt.u.bind.ctx_list == NULL) {
665 c->status = NT_STATUS_NO_MEMORY;
668 pkt.u.bind.ctx_list[0].context_id = p->context_id;
669 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
670 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
671 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
672 pkt.u.bind.auth_info = data_blob(NULL, 0);
674 /* construct the NDR form of the packet */
675 c->status = ncacn_push_auth(&blob, c, &pkt,
676 p->conn->security_state.auth_info);
677 if (!NT_STATUS_IS_OK(c->status)) {
681 p->conn->transport.recv_data = dcerpc_recv_data;
683 req->state = RPC_REQUEST_PENDING;
684 req->call_id = pkt.call_id;
685 req->async.private = c;
686 req->async.callback = dcerpc_composite_fail;
688 req->recv_handler = dcerpc_bind_recv_handler;
690 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
692 c->status = p->conn->transport.send_request(p->conn, &blob,
694 if (!NT_STATUS_IS_OK(c->status)) {
698 event_add_timed(c->event_ctx, req,
699 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
700 dcerpc_timeout_handler, req);
705 composite_error(c, c->status);
710 recv side of async dcerpc bind request
712 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
714 NTSTATUS result = composite_wait(ctx);
720 perform a bind using the given syntax
722 the auth_info structure is updated with the reply authentication info
725 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
727 const struct dcerpc_syntax_id *syntax,
728 const struct dcerpc_syntax_id *transfer_syntax)
730 struct composite_context *creq;
731 creq = dcerpc_bind_send(p, mem_ctx, syntax, transfer_syntax);
732 return dcerpc_bind_recv(creq);
736 perform a continued bind (and auth3)
738 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
741 struct ncacn_packet pkt;
745 init_ncacn_hdr(c, &pkt);
747 pkt.ptype = DCERPC_PKT_AUTH3;
748 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
749 pkt.call_id = next_call_id(c);
751 pkt.u.auth3._pad = 0;
752 pkt.u.auth3.auth_info = data_blob(NULL, 0);
754 /* construct the NDR form of the packet */
755 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
756 if (!NT_STATUS_IS_OK(status)) {
760 /* send it on its way */
761 status = c->transport.send_request(c, &blob, False);
762 if (!NT_STATUS_IS_OK(status)) {
771 return the rpc syntax and transfer syntax given the pipe uuid and version
773 NTSTATUS dcerpc_init_syntaxes(const struct dcerpc_interface_table *table,
774 struct dcerpc_syntax_id *syntax,
775 struct dcerpc_syntax_id *transfer_syntax)
777 syntax->uuid = table->syntax_id.uuid;
778 syntax->if_version = table->syntax_id.if_version;
780 *transfer_syntax = ndr_transfer_syntax;
785 /* perform a dcerpc bind, using the uuid as the key */
786 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
788 const struct dcerpc_interface_table *table)
790 struct dcerpc_syntax_id syntax;
791 struct dcerpc_syntax_id transfer_syntax;
794 status = dcerpc_init_syntaxes(table,
795 &syntax, &transfer_syntax);
796 if (!NT_STATUS_IS_OK(status)) {
797 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
801 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
806 process a fragment received from the transport layer during a
809 This function frees the data
811 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
812 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
814 struct rpc_request *req;
816 NTSTATUS status = NT_STATUS_OK;
819 if this is an authenticated connection then parse and check
820 the auth info. We have to do this before finding the
821 matching packet, as the request structure might have been
822 removed due to a timeout, but if it has been we still need
823 to run the auth routines so that we don't get the sign/seal
824 info out of step with the server
826 if (c->security_state.auth_info && c->security_state.generic_state &&
827 pkt->ptype == DCERPC_PKT_RESPONSE) {
828 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
831 /* find the matching request */
832 for (req=c->pending;req;req=req->next) {
833 if (pkt->call_id == req->call_id) break;
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 req->state = RPC_REQUEST_DONE;
846 DLIST_REMOVE(c->pending, req);
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 make sure requests are cleaned up
920 static int dcerpc_req_destructor(struct rpc_request *req)
922 DLIST_REMOVE(req->p->conn->pending, req);
927 perform the send side of a async dcerpc request
929 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
930 const struct GUID *object,
933 DATA_BLOB *stub_data)
935 struct rpc_request *req;
937 p->conn->transport.recv_data = dcerpc_recv_data;
939 req = talloc(p, struct rpc_request);
945 req->call_id = next_call_id(p->conn);
946 req->status = NT_STATUS_OK;
947 req->state = RPC_REQUEST_PENDING;
948 req->payload = data_blob(NULL, 0);
951 req->async_call = async;
952 req->async.callback = NULL;
953 req->async.private = NULL;
954 req->recv_handler = NULL;
956 if (object != NULL) {
957 req->object = talloc_memdup(req, object, sizeof(*object));
958 if (req->object == NULL) {
967 req->request_data.length = stub_data->length;
968 req->request_data.data = talloc_reference(req, stub_data->data);
969 if (req->request_data.data == NULL) {
973 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
975 dcerpc_ship_next_request(p->conn);
977 if (p->request_timeout) {
978 event_add_timed(dcerpc_event_context(p), req,
979 timeval_current_ofs(p->request_timeout, 0),
980 dcerpc_timeout_handler, req);
983 talloc_set_destructor(req, dcerpc_req_destructor);
988 Send a request using the transport
991 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
993 struct rpc_request *req;
994 struct dcerpc_pipe *p;
995 DATA_BLOB *stub_data;
996 struct ncacn_packet pkt;
998 uint32_t remaining, chunk_size;
999 BOOL first_packet = True;
1001 req = c->request_queue;
1007 stub_data = &req->request_data;
1009 if (!req->async_call && (c->pending != NULL)) {
1013 DLIST_REMOVE(c->request_queue, req);
1014 DLIST_ADD(c->pending, req);
1016 init_ncacn_hdr(p->conn, &pkt);
1018 remaining = stub_data->length;
1020 /* we can write a full max_recv_frag size, minus the dcerpc
1021 request header size */
1022 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1024 pkt.ptype = DCERPC_PKT_REQUEST;
1025 pkt.call_id = req->call_id;
1026 pkt.auth_length = 0;
1028 pkt.u.request.alloc_hint = remaining;
1029 pkt.u.request.context_id = p->context_id;
1030 pkt.u.request.opnum = req->opnum;
1033 pkt.u.request.object.object = *req->object;
1034 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
1035 chunk_size -= ndr_size_GUID(req->object,0);
1038 /* we send a series of pdus without waiting for a reply */
1039 while (remaining > 0 || first_packet) {
1040 uint32_t chunk = MIN(chunk_size, remaining);
1041 BOOL last_frag = False;
1043 first_packet = False;
1044 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1046 if (remaining == stub_data->length) {
1047 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1049 if (chunk == remaining) {
1050 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1054 pkt.u.request.stub_and_verifier.data = stub_data->data +
1055 (stub_data->length - remaining);
1056 pkt.u.request.stub_and_verifier.length = chunk;
1058 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1059 if (!NT_STATUS_IS_OK(req->status)) {
1060 req->state = RPC_REQUEST_DONE;
1061 DLIST_REMOVE(p->conn->pending, req);
1065 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1066 if (!NT_STATUS_IS_OK(req->status)) {
1067 req->state = RPC_REQUEST_DONE;
1068 DLIST_REMOVE(p->conn->pending, req);
1077 return the event context for a dcerpc pipe
1078 used by callers who wish to operate asynchronously
1080 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1082 return p->conn->event_ctx;
1088 perform the receive side of a async dcerpc request
1090 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1091 TALLOC_CTX *mem_ctx,
1092 DATA_BLOB *stub_data)
1096 while (req->state == RPC_REQUEST_PENDING) {
1097 struct event_context *ctx = dcerpc_event_context(req->p);
1098 if (event_loop_once(ctx) != 0) {
1099 return NT_STATUS_CONNECTION_DISCONNECTED;
1102 *stub_data = req->payload;
1103 status = req->status;
1104 if (stub_data->data) {
1105 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1107 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1108 req->p->last_fault_code = req->fault_code;
1115 perform a full request/response pair on a dcerpc pipe
1117 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1118 struct GUID *object,
1121 TALLOC_CTX *mem_ctx,
1122 DATA_BLOB *stub_data_in,
1123 DATA_BLOB *stub_data_out)
1125 struct rpc_request *req;
1127 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1129 return NT_STATUS_NO_MEMORY;
1132 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1137 this is a paranoid NDR validator. For every packet we push onto the wire
1138 we pull it back again, then push it again. Then we compare the raw NDR data
1139 for that to the NDR we initially generated. If they don't match then we know
1140 we must have a bug in either the pull or push side of our code
1142 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1143 TALLOC_CTX *mem_ctx,
1146 ndr_push_flags_fn_t ndr_push,
1147 ndr_pull_flags_fn_t ndr_pull)
1150 struct ndr_pull *pull;
1151 struct ndr_push *push;
1155 st = talloc_size(mem_ctx, struct_size);
1157 return NT_STATUS_NO_MEMORY;
1160 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1162 return NT_STATUS_NO_MEMORY;
1164 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1166 status = ndr_pull(pull, NDR_IN, st);
1167 if (!NT_STATUS_IS_OK(status)) {
1168 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1169 "failed input validation pull - %s",
1173 push = ndr_push_init_ctx(mem_ctx);
1175 return NT_STATUS_NO_MEMORY;
1178 status = ndr_push(push, NDR_IN, st);
1179 if (!NT_STATUS_IS_OK(status)) {
1180 return ndr_push_error(push, NDR_ERR_VALIDATE,
1181 "failed input validation push - %s",
1185 blob2 = ndr_push_blob(push);
1187 if (!data_blob_equal(&blob, &blob2)) {
1188 DEBUG(3,("original:\n"));
1189 dump_data(3, blob.data, blob.length);
1190 DEBUG(3,("secondary:\n"));
1191 dump_data(3, blob2.data, blob2.length);
1192 return ndr_push_error(push, NDR_ERR_VALIDATE,
1193 "failed input validation data - %s",
1197 return NT_STATUS_OK;
1201 this is a paranoid NDR input validator. For every packet we pull
1202 from the wire we push it back again then pull and push it
1203 again. Then we compare the raw NDR data for that to the NDR we
1204 initially generated. If they don't match then we know we must have a
1205 bug in either the pull or push side of our code
1207 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1208 struct ndr_pull *pull_in,
1211 ndr_push_flags_fn_t ndr_push,
1212 ndr_pull_flags_fn_t ndr_pull,
1213 ndr_print_function_t ndr_print)
1216 struct ndr_pull *pull;
1217 struct ndr_push *push;
1219 DATA_BLOB blob, blob2;
1220 TALLOC_CTX *mem_ctx = pull_in;
1223 st = talloc_size(mem_ctx, struct_size);
1225 return NT_STATUS_NO_MEMORY;
1227 memcpy(st, struct_ptr, struct_size);
1229 push = ndr_push_init_ctx(mem_ctx);
1231 return NT_STATUS_NO_MEMORY;
1234 status = ndr_push(push, NDR_OUT, struct_ptr);
1235 if (!NT_STATUS_IS_OK(status)) {
1236 return ndr_push_error(push, NDR_ERR_VALIDATE,
1237 "failed output validation push - %s",
1241 blob = ndr_push_blob(push);
1243 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1245 return NT_STATUS_NO_MEMORY;
1248 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1249 status = ndr_pull(pull, NDR_OUT, st);
1250 if (!NT_STATUS_IS_OK(status)) {
1251 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1252 "failed output validation pull - %s",
1256 push = ndr_push_init_ctx(mem_ctx);
1258 return NT_STATUS_NO_MEMORY;
1261 status = ndr_push(push, NDR_OUT, st);
1262 if (!NT_STATUS_IS_OK(status)) {
1263 return ndr_push_error(push, NDR_ERR_VALIDATE,
1264 "failed output validation push2 - %s",
1268 blob2 = ndr_push_blob(push);
1270 if (!data_blob_equal(&blob, &blob2)) {
1271 DEBUG(3,("original:\n"));
1272 dump_data(3, blob.data, blob.length);
1273 DEBUG(3,("secondary:\n"));
1274 dump_data(3, blob2.data, blob2.length);
1275 return ndr_push_error(push, NDR_ERR_VALIDATE,
1276 "failed output validation data - %s",
1280 /* this checks the printed forms of the two structures, which effectively
1281 tests all of the value() attributes */
1282 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1283 NDR_OUT, struct_ptr);
1284 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1286 if (strcmp(s1, s2) != 0) {
1288 printf("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2);
1290 /* this is sometimes useful */
1291 printf("VALIDATE ERROR\n");
1292 file_save("wire.dat", s1, strlen(s1));
1293 file_save("gen.dat", s2, strlen(s2));
1294 system("diff -u wire.dat gen.dat");
1298 return NT_STATUS_OK;
1303 send a rpc request given a dcerpc_call structure
1305 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1306 const struct GUID *object,
1307 const struct dcerpc_interface_table *table,
1309 TALLOC_CTX *mem_ctx,
1312 const struct dcerpc_interface_call *call;
1313 struct ndr_push *push;
1316 struct rpc_request *req;
1318 call = &table->calls[opnum];
1320 /* setup for a ndr_push_* call */
1321 push = ndr_push_init_ctx(mem_ctx);
1326 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1327 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1330 /* push the structure into a blob */
1331 status = call->ndr_push(push, NDR_IN, r);
1332 if (!NT_STATUS_IS_OK(status)) {
1333 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1334 nt_errstr(status)));
1339 /* retrieve the blob */
1340 request = ndr_push_blob(push);
1342 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1343 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1344 call->ndr_push, call->ndr_pull);
1345 if (!NT_STATUS_IS_OK(status)) {
1346 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1347 nt_errstr(status)));
1353 DEBUG(10,("rpc request data:\n"));
1354 dump_data(10, request.data, request.length);
1356 /* make the actual dcerpc request */
1357 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1361 req->ndr.table = table;
1362 req->ndr.opnum = opnum;
1363 req->ndr.struct_ptr = r;
1364 req->ndr.mem_ctx = mem_ctx;
1373 receive the answer from a dcerpc_ndr_request_send()
1375 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1377 struct dcerpc_pipe *p = req->p;
1380 struct ndr_pull *pull;
1382 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1383 void *r = req->ndr.struct_ptr;
1384 uint32_t opnum = req->ndr.opnum;
1385 const struct dcerpc_interface_table *table = req->ndr.table;
1386 const struct dcerpc_interface_call *call = &table->calls[opnum];
1388 /* make sure the recv code doesn't free the request, as we
1389 need to grab the flags element before it is freed */
1390 talloc_increase_ref_count(req);
1392 status = dcerpc_request_recv(req, mem_ctx, &response);
1393 if (!NT_STATUS_IS_OK(status)) {
1399 /* prepare for ndr_pull_* */
1400 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1403 return NT_STATUS_NO_MEMORY;
1407 pull->data = talloc_steal(pull, pull->data);
1411 if (flags & DCERPC_PULL_BIGENDIAN) {
1412 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1415 DEBUG(10,("rpc reply data:\n"));
1416 dump_data(10, pull->data, pull->data_size);
1418 /* pull the structure from the blob */
1419 status = call->ndr_pull(pull, NDR_OUT, r);
1420 if (!NT_STATUS_IS_OK(status)) {
1421 dcerpc_log_packet(table, opnum, NDR_OUT,
1426 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1427 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1428 call->ndr_push, call->ndr_pull,
1430 if (!NT_STATUS_IS_OK(status)) {
1431 dcerpc_log_packet(table, opnum, NDR_OUT,
1437 if (pull->offset != pull->data_size) {
1438 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1439 pull->data_size - pull->offset));
1440 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1441 but it turns out that early versions of NT
1442 (specifically NT3.1) add junk onto the end of rpc
1443 packets, so if we want to interoperate at all with
1444 those versions then we need to ignore this error */
1447 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1449 return NT_STATUS_OK;
1454 a useful helper function for synchronous rpc requests
1456 this can be used when you have ndr push/pull functions in the
1459 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1460 const struct GUID *object,
1461 const struct dcerpc_interface_table *table,
1463 TALLOC_CTX *mem_ctx,
1466 struct rpc_request *req;
1468 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1470 return NT_STATUS_NO_MEMORY;
1473 return dcerpc_ndr_request_recv(req);
1478 a useful function for retrieving the server name we connected to
1480 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1482 if (!p->conn->transport.peer_name) {
1485 return p->conn->transport.peer_name(p->conn);
1490 get the dcerpc auth_level for a open connection
1492 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1496 if (c->flags & DCERPC_SEAL) {
1497 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1498 } else if (c->flags & DCERPC_SIGN) {
1499 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1500 } else if (c->flags & DCERPC_CONNECT) {
1501 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1503 auth_level = DCERPC_AUTH_LEVEL_NONE;
1509 Receive an alter reply from the transport
1511 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1512 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1514 struct composite_context *c;
1515 struct dcerpc_pipe *recv_pipe;
1517 c = talloc_get_type(req->async.private, struct composite_context);
1518 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1520 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1521 pkt->u.alter_resp.num_results == 1 &&
1522 pkt->u.alter_resp.ctx_list[0].result != 0) {
1523 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1524 pkt->u.alter_resp.ctx_list[0].reason));
1525 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1529 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1530 pkt->u.alter_resp.num_results == 0 ||
1531 pkt->u.alter_resp.ctx_list[0].result != 0) {
1532 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1536 /* the alter_resp might contain a reply set of credentials */
1537 if (recv_pipe->conn->security_state.auth_info &&
1538 pkt->u.alter_resp.auth_info.length) {
1539 c->status = ndr_pull_struct_blob(
1540 &pkt->u.alter_resp.auth_info, recv_pipe,
1541 recv_pipe->conn->security_state.auth_info,
1542 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1543 if (!composite_is_ok(c)) return;
1550 send a dcerpc alter_context request
1552 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1553 TALLOC_CTX *mem_ctx,
1554 const struct dcerpc_syntax_id *syntax,
1555 const struct dcerpc_syntax_id *transfer_syntax)
1557 struct composite_context *c;
1558 struct ncacn_packet pkt;
1560 struct rpc_request *req;
1562 /* we allocate a dcerpc_request so we can be in the same
1563 request queue as normal requests, but most of the request
1564 fields are not used as there is no call id */
1565 req = talloc_zero(mem_ctx, struct rpc_request);
1566 if (req == NULL) return NULL;
1568 c = talloc_zero(req, struct composite_context);
1569 if (c == NULL) return NULL;
1571 c->state = COMPOSITE_STATE_IN_PROGRESS;
1572 c->private_data = p;
1573 c->event_ctx = p->conn->event_ctx;
1575 p->syntax = *syntax;
1576 p->transfer_syntax = *transfer_syntax;
1578 init_ncacn_hdr(p->conn, &pkt);
1580 pkt.ptype = DCERPC_PKT_ALTER;
1581 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1582 pkt.call_id = p->conn->call_id;
1583 pkt.auth_length = 0;
1585 pkt.u.alter.max_xmit_frag = 5840;
1586 pkt.u.alter.max_recv_frag = 5840;
1587 pkt.u.alter.assoc_group_id = 0;
1588 pkt.u.alter.num_contexts = 1;
1589 pkt.u.alter.ctx_list = talloc_array(mem_ctx,
1590 struct dcerpc_ctx_list, 1);
1591 if (pkt.u.alter.ctx_list == NULL) {
1592 c->status = NT_STATUS_NO_MEMORY;
1595 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1596 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1597 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1598 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1599 pkt.u.alter.auth_info = data_blob(NULL, 0);
1601 /* construct the NDR form of the packet */
1602 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1603 p->conn->security_state.auth_info);
1604 if (!NT_STATUS_IS_OK(c->status)) {
1608 p->conn->transport.recv_data = dcerpc_recv_data;
1610 req->state = RPC_REQUEST_PENDING;
1611 req->call_id = pkt.call_id;
1612 req->async.private = c;
1613 req->async.callback = dcerpc_composite_fail;
1615 req->recv_handler = dcerpc_alter_recv_handler;
1617 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1619 c->status = p->conn->transport.send_request(p->conn, &blob, True);
1620 if (!NT_STATUS_IS_OK(c->status)) {
1624 event_add_timed(c->event_ctx, req,
1625 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1626 dcerpc_timeout_handler, req);
1631 composite_error(c, c->status);
1635 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1637 NTSTATUS result = composite_wait(ctx);
1643 send a dcerpc alter_context request
1645 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1646 TALLOC_CTX *mem_ctx,
1647 const struct dcerpc_syntax_id *syntax,
1648 const struct dcerpc_syntax_id *transfer_syntax)
1650 struct composite_context *creq;
1651 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1652 return dcerpc_alter_context_recv(creq);