2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/gen_ndr/ndr_epmapper.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 static struct dcerpc_interface_list *dcerpc_pipes = NULL;
33 register a dcerpc client interface
35 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
37 struct dcerpc_interface_list *l = talloc(talloc_autofree_context(),
38 struct dcerpc_interface_list);
40 if (idl_iface_by_name (interface->name) != NULL) {
41 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
42 return NT_STATUS_OBJECT_NAME_COLLISION;
46 DLIST_ADD(dcerpc_pipes, l);
52 return the list of registered dcerpc_pipes
54 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
59 /* destroy a dcerpc connection */
60 static int dcerpc_connection_destructor(void *ptr)
62 struct dcerpc_connection *c = ptr;
63 if (c->transport.shutdown_pipe) {
64 c->transport.shutdown_pipe(c);
70 /* initialise a dcerpc connection.
71 the event context is optional
73 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
74 struct event_context *ev)
76 struct dcerpc_connection *c;
78 c = talloc_zero(mem_ctx, struct dcerpc_connection);
84 ev = event_context_init(c);
93 c->security_state.auth_info = NULL;
94 c->security_state.session_key = dcerpc_generic_session_key;
95 c->security_state.generic_state = NULL;
96 c->binding_string = NULL;
98 c->srv_max_xmit_frag = 0;
99 c->srv_max_recv_frag = 0;
102 talloc_set_destructor(c, dcerpc_connection_destructor);
107 /* initialise a dcerpc pipe. */
108 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
110 struct dcerpc_pipe *p;
112 p = talloc(mem_ctx, struct dcerpc_pipe);
117 p->conn = dcerpc_connection_init(p, ev);
118 if (p->conn == NULL) {
123 p->last_fault_code = 0;
125 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
127 ZERO_STRUCT(p->syntax);
128 ZERO_STRUCT(p->transfer_syntax);
135 choose the next call id to use
137 static uint32_t next_call_id(struct dcerpc_connection *c)
140 if (c->call_id == 0) {
146 /* we need to be able to get/set the fragment length without doing a full
148 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
150 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
151 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
153 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
157 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
159 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
160 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
162 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
166 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
168 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
169 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
171 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
177 setup for a ndr pull, also setting up any flags from the binding string
179 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
180 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
182 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
184 if (ndr == NULL) return ndr;
186 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
187 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
190 if (c->flags & DCERPC_NDR_REF_ALLOC) {
191 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
198 parse a data blob into a ncacn_packet structure. This handles both
199 input and output packets
201 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
202 struct ncacn_packet *pkt)
204 struct ndr_pull *ndr;
206 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
208 return NT_STATUS_NO_MEMORY;
211 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
212 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
215 return ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
219 generate a CONNECT level verifier
221 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
223 *blob = data_blob_talloc(mem_ctx, NULL, 16);
224 if (blob->data == NULL) {
225 return NT_STATUS_NO_MEMORY;
227 SIVAL(blob->data, 0, 1);
228 memset(blob->data+4, 0, 12);
233 check a CONNECT level verifier
235 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
237 if (blob->length != 16 ||
238 IVAL(blob->data, 0) != 1) {
239 return NT_STATUS_ACCESS_DENIED;
245 parse a possibly signed blob into a dcerpc request packet structure
247 static NTSTATUS ncacn_pull_request_sign(struct dcerpc_connection *c,
248 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
249 struct ncacn_packet *pkt)
251 struct ndr_pull *ndr;
253 struct dcerpc_auth auth;
256 /* non-signed packets are simpler */
257 if (!c->security_state.auth_info ||
258 !c->security_state.generic_state) {
259 return ncacn_pull(c, blob, mem_ctx, pkt);
262 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
264 return NT_STATUS_NO_MEMORY;
267 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
268 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
271 /* pull the basic packet */
272 status = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
273 if (!NT_STATUS_IS_OK(status)) {
277 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
281 if (pkt->auth_length == 0 &&
282 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
286 auth_blob.length = 8 + pkt->auth_length;
288 /* check for a valid length */
289 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
290 return NT_STATUS_INFO_LENGTH_MISMATCH;
294 pkt->u.response.stub_and_verifier.data +
295 pkt->u.response.stub_and_verifier.length - auth_blob.length;
296 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
298 /* pull the auth structure */
299 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
301 return NT_STATUS_NO_MEMORY;
304 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
305 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
308 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
309 if (!NT_STATUS_IS_OK(status)) {
314 /* check signature or unseal the packet */
315 switch (c->security_state.auth_info->auth_level) {
316 case DCERPC_AUTH_LEVEL_PRIVACY:
317 status = gensec_unseal_packet(c->security_state.generic_state,
319 blob->data + DCERPC_REQUEST_LENGTH,
320 pkt->u.response.stub_and_verifier.length,
322 blob->length - auth.credentials.length,
324 memcpy(pkt->u.response.stub_and_verifier.data,
325 blob->data + DCERPC_REQUEST_LENGTH,
326 pkt->u.response.stub_and_verifier.length);
329 case DCERPC_AUTH_LEVEL_INTEGRITY:
330 status = gensec_check_packet(c->security_state.generic_state,
332 pkt->u.response.stub_and_verifier.data,
333 pkt->u.response.stub_and_verifier.length,
335 blob->length - auth.credentials.length,
339 case DCERPC_AUTH_LEVEL_CONNECT:
340 status = dcerpc_check_connect_verifier(&auth.credentials);
343 case DCERPC_AUTH_LEVEL_NONE:
347 status = NT_STATUS_INVALID_LEVEL;
351 /* remove the indicated amount of paddiing */
352 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
353 return NT_STATUS_INFO_LENGTH_MISMATCH;
355 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
362 push a dcerpc request packet into a blob, possibly signing it.
364 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
365 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
366 struct ncacn_packet *pkt)
369 struct ndr_push *ndr;
372 /* non-signed packets are simpler */
373 if (!c->security_state.auth_info ||
374 !c->security_state.generic_state) {
375 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
378 ndr = ndr_push_init_ctx(mem_ctx);
380 return NT_STATUS_NO_MEMORY;
383 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
384 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
387 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
388 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
391 status = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
392 if (!NT_STATUS_IS_OK(status)) {
396 /* pad to 16 byte multiple in the payload portion of the
397 packet. This matches what w2k3 does */
398 c->security_state.auth_info->auth_pad_length =
399 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
400 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
402 /* sign or seal the packet */
403 switch (c->security_state.auth_info->auth_level) {
404 case DCERPC_AUTH_LEVEL_PRIVACY:
405 case DCERPC_AUTH_LEVEL_INTEGRITY:
406 c->security_state.auth_info->credentials
407 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state));
408 data_blob_clear(&c->security_state.auth_info->credentials);
411 case DCERPC_AUTH_LEVEL_CONNECT:
412 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
415 case DCERPC_AUTH_LEVEL_NONE:
416 c->security_state.auth_info->credentials = data_blob(NULL, 0);
420 status = NT_STATUS_INVALID_LEVEL;
424 if (!NT_STATUS_IS_OK(status)) {
428 /* add the auth verifier */
429 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
430 if (!NT_STATUS_IS_OK(status)) {
434 /* extract the whole packet as a blob */
435 *blob = ndr_push_blob(ndr);
437 /* fill in the fragment length and auth_length, we can't fill
438 in these earlier as we don't know the signature length (it
439 could be variable length) */
440 dcerpc_set_frag_length(blob, blob->length);
441 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
443 /* sign or seal the packet */
444 switch (c->security_state.auth_info->auth_level) {
445 case DCERPC_AUTH_LEVEL_PRIVACY:
446 status = gensec_seal_packet(c->security_state.generic_state,
448 blob->data + DCERPC_REQUEST_LENGTH,
449 pkt->u.request.stub_and_verifier.length +
450 c->security_state.auth_info->auth_pad_length,
453 c->security_state.auth_info->credentials.length,
455 if (!NT_STATUS_IS_OK(status)) {
458 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
461 case DCERPC_AUTH_LEVEL_INTEGRITY:
462 status = gensec_sign_packet(c->security_state.generic_state,
464 blob->data + DCERPC_REQUEST_LENGTH,
465 pkt->u.request.stub_and_verifier.length +
466 c->security_state.auth_info->auth_pad_length,
469 c->security_state.auth_info->credentials.length,
471 if (!NT_STATUS_IS_OK(status)) {
474 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
477 case DCERPC_AUTH_LEVEL_CONNECT:
480 case DCERPC_AUTH_LEVEL_NONE:
481 c->security_state.auth_info->credentials = data_blob(NULL, 0);
485 status = NT_STATUS_INVALID_LEVEL;
489 data_blob_free(&c->security_state.auth_info->credentials);
496 fill in the fixed values in a dcerpc header
498 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
501 pkt->rpc_vers_minor = 0;
502 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
505 pkt->drep[0] = DCERPC_DREP_LE;
513 hold the state of pending full requests
515 struct full_request_state {
516 struct dcerpc_connection *c;
517 DATA_BLOB *reply_blob;
522 receive a reply to a full request
524 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob,
527 struct full_request_state *state = talloc_get_type(c->full_request_private,
528 struct full_request_state);
530 /* it timed out earlier */
534 if (!NT_STATUS_IS_OK(status)) {
535 state->status = status;
538 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
539 state->reply_blob = NULL;
543 handle timeouts of full dcerpc requests
545 static void dcerpc_full_timeout_handler(struct event_context *ev, struct timed_event *te,
546 struct timeval t, void *private)
548 struct full_request_state *state = talloc_get_type(private,
549 struct full_request_state);
550 state->status = NT_STATUS_IO_TIMEOUT;
551 state->c->full_request_private = NULL;
555 perform a single pdu synchronous request - used for the bind code
556 this cannot be mixed with normal async requests
558 static NTSTATUS full_request(struct dcerpc_connection *c,
560 DATA_BLOB *request_blob,
561 DATA_BLOB *reply_blob)
563 struct full_request_state *state = talloc(mem_ctx, struct full_request_state);
567 return NT_STATUS_NO_MEMORY;
570 state->reply_blob = reply_blob;
571 state->status = NT_STATUS_OK;
574 c->transport.recv_data = full_request_recv;
575 c->full_request_private = state;
577 status = c->transport.send_request(c, request_blob, True);
578 if (!NT_STATUS_IS_OK(status)) {
582 event_add_timed(c->event_ctx, state,
583 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
584 dcerpc_full_timeout_handler, state);
586 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
587 if (event_loop_once(c->event_ctx) != 0) {
588 return NT_STATUS_CONNECTION_DISCONNECTED;
592 c->full_request_private = NULL;
594 return state->status;
598 map a bind nak reason to a NTSTATUS
600 static NTSTATUS dcerpc_map_reason(uint16_t reason)
603 case DCERPC_BIND_REASON_ASYNTAX:
604 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
606 return NT_STATUS_UNSUCCESSFUL;
611 perform a bind using the given syntax
613 the auth_info structure is updated with the reply authentication info
616 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
618 const struct dcerpc_syntax_id *syntax,
619 const struct dcerpc_syntax_id *transfer_syntax)
621 struct ncacn_packet pkt;
626 p->transfer_syntax = *transfer_syntax;
628 init_ncacn_hdr(p->conn, &pkt);
630 pkt.ptype = DCERPC_PKT_BIND;
631 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
632 pkt.call_id = p->conn->call_id;
635 pkt.u.bind.max_xmit_frag = 5840;
636 pkt.u.bind.max_recv_frag = 5840;
637 pkt.u.bind.assoc_group_id = 0;
638 pkt.u.bind.num_contexts = 1;
639 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
640 if (!pkt.u.bind.ctx_list) {
641 return NT_STATUS_NO_MEMORY;
643 pkt.u.bind.ctx_list[0].context_id = p->context_id;
644 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
645 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
646 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
647 pkt.u.bind.auth_info = data_blob(NULL, 0);
649 /* construct the NDR form of the packet */
650 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
651 if (!NT_STATUS_IS_OK(status)) {
655 /* send it on its way */
656 status = full_request(p->conn, mem_ctx, &blob, &blob);
657 if (!NT_STATUS_IS_OK(status)) {
661 /* unmarshall the NDR */
662 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
663 if (!NT_STATUS_IS_OK(status)) {
667 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
668 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
669 return dcerpc_map_reason(pkt.u.bind_nak.reject_reason);
672 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
673 pkt.u.bind_ack.num_results == 0 ||
674 pkt.u.bind_ack.ctx_list[0].result != 0) {
675 return NT_STATUS_UNSUCCESSFUL;
678 p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
679 p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
681 /* the bind_ack might contain a reply set of credentials */
682 if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
683 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
685 p->conn->security_state.auth_info,
686 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
693 perform a continued bind (and auth3)
695 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
698 struct ncacn_packet pkt;
702 init_ncacn_hdr(c, &pkt);
704 pkt.ptype = DCERPC_PKT_AUTH3;
705 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
706 pkt.call_id = next_call_id(c);
708 pkt.u.auth3._pad = 0;
709 pkt.u.auth3.auth_info = data_blob(NULL, 0);
711 /* construct the NDR form of the packet */
712 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
713 if (!NT_STATUS_IS_OK(status)) {
717 /* send it on its way */
718 status = c->transport.send_request(c, &blob, False);
719 if (!NT_STATUS_IS_OK(status)) {
727 /* perform a dcerpc bind, using the uuid as the key */
728 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
730 const char *uuid, uint_t version)
732 struct dcerpc_syntax_id syntax;
733 struct dcerpc_syntax_id transfer_syntax;
736 status = GUID_from_string(uuid, &syntax.uuid);
737 if (!NT_STATUS_IS_OK(status)) {
738 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
741 syntax.if_version = version;
743 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
744 if (!NT_STATUS_IS_OK(status)) {
747 transfer_syntax.if_version = NDR_GUID_VERSION;
749 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
753 process a fragment received from the transport layer during a
756 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
760 struct ncacn_packet pkt;
761 struct rpc_request *req;
764 if (!NT_STATUS_IS_OK(status)) {
765 /* all pending requests get the error */
768 req->state = RPC_REQUEST_DONE;
769 req->status = status;
770 DLIST_REMOVE(c->pending, req);
771 if (req->async.callback) {
772 req->async.callback(req);
780 status = ncacn_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
782 /* find the matching request. Notice we match before we check
783 the status. this is ok as a pending call_id can never be
785 for (req=c->pending;req;req=req->next) {
786 if (pkt.call_id == req->call_id) break;
790 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
794 if (!NT_STATUS_IS_OK(status)) {
795 req->status = status;
796 req->state = RPC_REQUEST_DONE;
797 DLIST_REMOVE(c->pending, req);
798 if (req->async.callback) {
799 req->async.callback(req);
804 if (pkt.ptype == DCERPC_PKT_FAULT) {
805 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
806 req->fault_code = pkt.u.fault.status;
807 req->status = NT_STATUS_NET_WRITE_FAULT;
808 req->state = RPC_REQUEST_DONE;
809 DLIST_REMOVE(c->pending, req);
810 if (req->async.callback) {
811 req->async.callback(req);
816 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
817 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
819 req->fault_code = DCERPC_FAULT_OTHER;
820 req->status = NT_STATUS_NET_WRITE_FAULT;
821 req->state = RPC_REQUEST_DONE;
822 DLIST_REMOVE(c->pending, req);
823 if (req->async.callback) {
824 req->async.callback(req);
829 length = pkt.u.response.stub_and_verifier.length;
832 req->payload.data = talloc_realloc(req,
835 req->payload.length + length);
836 if (!req->payload.data) {
837 req->status = NT_STATUS_NO_MEMORY;
838 req->state = RPC_REQUEST_DONE;
839 DLIST_REMOVE(c->pending, req);
840 if (req->async.callback) {
841 req->async.callback(req);
845 memcpy(req->payload.data+req->payload.length,
846 pkt.u.response.stub_and_verifier.data, length);
847 req->payload.length += length;
850 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
851 c->transport.send_read(c);
855 /* we've got the full payload */
856 req->state = RPC_REQUEST_DONE;
857 DLIST_REMOVE(c->pending, req);
859 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
860 req->flags |= DCERPC_PULL_BIGENDIAN;
862 req->flags &= ~DCERPC_PULL_BIGENDIAN;
865 if (req->async.callback) {
866 req->async.callback(req);
871 handle timeouts of individual dcerpc requests
873 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
874 struct timeval t, void *private)
876 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
878 if (req->state != RPC_REQUEST_PENDING) {
882 req->status = NT_STATUS_IO_TIMEOUT;
883 req->state = RPC_REQUEST_DONE;
884 DLIST_REMOVE(req->p->conn->pending, req);
885 if (req->async.callback) {
886 req->async.callback(req);
892 make sure requests are cleaned up
894 static int dcerpc_req_destructor(void *ptr)
896 struct rpc_request *req = ptr;
897 DLIST_REMOVE(req->p->conn->pending, req);
902 perform the send side of a async dcerpc request
904 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
905 const struct GUID *object,
907 DATA_BLOB *stub_data)
909 struct rpc_request *req;
910 struct ncacn_packet pkt;
912 uint32_t remaining, chunk_size;
913 BOOL first_packet = True;
915 p->conn->transport.recv_data = dcerpc_request_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.callback = NULL;
931 init_ncacn_hdr(p->conn, &pkt);
933 remaining = stub_data->length;
935 /* we can write a full max_recv_frag size, minus the dcerpc
936 request header size */
937 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
939 pkt.ptype = DCERPC_PKT_REQUEST;
940 pkt.call_id = req->call_id;
943 pkt.u.request.alloc_hint = remaining;
944 pkt.u.request.context_id = p->context_id;
945 pkt.u.request.opnum = opnum;
948 pkt.u.request.object.object = *object;
949 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
950 chunk_size -= ndr_size_GUID(object,0);
953 DLIST_ADD(p->conn->pending, req);
955 /* we send a series of pdus without waiting for a reply */
956 while (remaining > 0 || first_packet) {
957 uint32_t chunk = MIN(chunk_size, remaining);
958 BOOL last_frag = False;
960 first_packet = False;
961 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
963 if (remaining == stub_data->length) {
964 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
966 if (chunk == remaining) {
967 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
971 pkt.u.request.stub_and_verifier.data = stub_data->data +
972 (stub_data->length - remaining);
973 pkt.u.request.stub_and_verifier.length = chunk;
975 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
976 if (!NT_STATUS_IS_OK(req->status)) {
977 req->state = RPC_REQUEST_DONE;
978 DLIST_REMOVE(p->conn->pending, req);
982 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
983 if (!NT_STATUS_IS_OK(req->status)) {
984 req->state = RPC_REQUEST_DONE;
985 DLIST_REMOVE(p->conn->pending, req);
992 if (p->request_timeout) {
993 event_add_timed(dcerpc_event_context(p), req,
994 timeval_current_ofs(p->request_timeout, 0),
995 dcerpc_timeout_handler, req);
998 talloc_set_destructor(req, dcerpc_req_destructor);
1004 return the event context for a dcerpc pipe
1005 used by callers who wish to operate asynchronously
1007 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1009 return p->conn->event_ctx;
1015 perform the receive side of a async dcerpc request
1017 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1018 TALLOC_CTX *mem_ctx,
1019 DATA_BLOB *stub_data)
1023 while (req->state == RPC_REQUEST_PENDING) {
1024 struct event_context *ctx = dcerpc_event_context(req->p);
1025 if (event_loop_once(ctx) != 0) {
1026 return NT_STATUS_CONNECTION_DISCONNECTED;
1029 *stub_data = req->payload;
1030 status = req->status;
1031 if (stub_data->data) {
1032 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1034 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1035 req->p->last_fault_code = req->fault_code;
1042 perform a full request/response pair on a dcerpc pipe
1044 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1045 struct GUID *object,
1047 TALLOC_CTX *mem_ctx,
1048 DATA_BLOB *stub_data_in,
1049 DATA_BLOB *stub_data_out)
1051 struct rpc_request *req;
1053 req = dcerpc_request_send(p, object, opnum, stub_data_in);
1055 return NT_STATUS_NO_MEMORY;
1058 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1063 this is a paranoid NDR validator. For every packet we push onto the wire
1064 we pull it back again, then push it again. Then we compare the raw NDR data
1065 for that to the NDR we initially generated. If they don't match then we know
1066 we must have a bug in either the pull or push side of our code
1068 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1069 TALLOC_CTX *mem_ctx,
1072 ndr_push_flags_fn_t ndr_push,
1073 ndr_pull_flags_fn_t ndr_pull)
1076 struct ndr_pull *pull;
1077 struct ndr_push *push;
1081 st = talloc_size(mem_ctx, struct_size);
1083 return NT_STATUS_NO_MEMORY;
1086 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1088 return NT_STATUS_NO_MEMORY;
1090 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1092 status = ndr_pull(pull, NDR_IN, st);
1093 if (!NT_STATUS_IS_OK(status)) {
1094 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1095 "failed input validation pull - %s",
1099 push = ndr_push_init_ctx(mem_ctx);
1101 return NT_STATUS_NO_MEMORY;
1104 status = ndr_push(push, NDR_IN, st);
1105 if (!NT_STATUS_IS_OK(status)) {
1106 return ndr_push_error(push, NDR_ERR_VALIDATE,
1107 "failed input validation push - %s",
1111 blob2 = ndr_push_blob(push);
1113 if (!data_blob_equal(&blob, &blob2)) {
1114 DEBUG(3,("original:\n"));
1115 dump_data(3, blob.data, blob.length);
1116 DEBUG(3,("secondary:\n"));
1117 dump_data(3, blob2.data, blob2.length);
1118 return ndr_push_error(push, NDR_ERR_VALIDATE,
1119 "failed input validation data - %s",
1123 return NT_STATUS_OK;
1127 this is a paranoid NDR input validator. For every packet we pull
1128 from the wire we push it back again then pull and push it
1129 again. Then we compare the raw NDR data for that to the NDR we
1130 initially generated. If they don't match then we know we must have a
1131 bug in either the pull or push side of our code
1133 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1134 TALLOC_CTX *mem_ctx,
1137 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1138 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1141 struct ndr_pull *pull;
1142 struct ndr_push *push;
1144 DATA_BLOB blob, blob2;
1146 st = talloc_size(mem_ctx, struct_size);
1148 return NT_STATUS_NO_MEMORY;
1150 memcpy(st, struct_ptr, struct_size);
1152 push = ndr_push_init_ctx(mem_ctx);
1154 return NT_STATUS_NO_MEMORY;
1157 status = ndr_push(push, NDR_OUT, struct_ptr);
1158 if (!NT_STATUS_IS_OK(status)) {
1159 return ndr_push_error(push, NDR_ERR_VALIDATE,
1160 "failed output validation push - %s",
1164 blob = ndr_push_blob(push);
1166 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1168 return NT_STATUS_NO_MEMORY;
1171 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1172 status = ndr_pull(pull, NDR_OUT, st);
1173 if (!NT_STATUS_IS_OK(status)) {
1174 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1175 "failed output validation pull - %s",
1179 push = ndr_push_init_ctx(mem_ctx);
1181 return NT_STATUS_NO_MEMORY;
1184 status = ndr_push(push, NDR_OUT, st);
1185 if (!NT_STATUS_IS_OK(status)) {
1186 return ndr_push_error(push, NDR_ERR_VALIDATE,
1187 "failed output validation push2 - %s",
1191 blob2 = ndr_push_blob(push);
1193 if (!data_blob_equal(&blob, &blob2)) {
1194 DEBUG(3,("original:\n"));
1195 dump_data(3, blob.data, blob.length);
1196 DEBUG(3,("secondary:\n"));
1197 dump_data(3, blob2.data, blob2.length);
1198 return ndr_push_error(push, NDR_ERR_VALIDATE,
1199 "failed output validation data - %s",
1203 return NT_STATUS_OK;
1208 send a rpc request given a dcerpc_call structure
1210 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1211 const struct GUID *object,
1212 const struct dcerpc_interface_table *table,
1214 TALLOC_CTX *mem_ctx,
1217 const struct dcerpc_interface_call *call;
1218 struct ndr_push *push;
1221 struct rpc_request *req;
1223 call = &table->calls[opnum];
1225 /* setup for a ndr_push_* call */
1226 push = ndr_push_init_ctx(mem_ctx);
1231 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1232 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1235 /* push the structure into a blob */
1236 status = call->ndr_push(push, NDR_IN, r);
1237 if (!NT_STATUS_IS_OK(status)) {
1238 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1239 nt_errstr(status)));
1244 /* retrieve the blob */
1245 request = ndr_push_blob(push);
1247 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1248 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1249 call->ndr_push, call->ndr_pull);
1250 if (!NT_STATUS_IS_OK(status)) {
1251 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1252 nt_errstr(status)));
1258 DEBUG(10,("rpc request data:\n"));
1259 dump_data(10, request.data, request.length);
1261 /* make the actual dcerpc request */
1262 req = dcerpc_request_send(p, object, opnum, &request);
1265 req->ndr.table = table;
1266 req->ndr.opnum = opnum;
1267 req->ndr.struct_ptr = r;
1268 req->ndr.mem_ctx = mem_ctx;
1277 receive the answer from a dcerpc_ndr_request_send()
1279 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1281 struct dcerpc_pipe *p = req->p;
1284 struct ndr_pull *pull;
1286 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1287 void *r = req->ndr.struct_ptr;
1288 uint32_t opnum = req->ndr.opnum;
1289 const struct dcerpc_interface_table *table = req->ndr.table;
1290 const struct dcerpc_interface_call *call = &table->calls[opnum];
1292 /* make sure the recv code doesn't free the request, as we
1293 need to grab the flags element before it is freed */
1294 talloc_increase_ref_count(req);
1296 status = dcerpc_request_recv(req, mem_ctx, &response);
1297 if (!NT_STATUS_IS_OK(status)) {
1303 /* prepare for ndr_pull_* */
1304 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1307 return NT_STATUS_NO_MEMORY;
1311 pull->data = talloc_steal(pull, pull->data);
1315 if (flags & DCERPC_PULL_BIGENDIAN) {
1316 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1319 DEBUG(10,("rpc reply data:\n"));
1320 dump_data(10, pull->data, pull->data_size);
1322 /* pull the structure from the blob */
1323 status = call->ndr_pull(pull, NDR_OUT, r);
1324 if (!NT_STATUS_IS_OK(status)) {
1325 dcerpc_log_packet(table, opnum, NDR_OUT,
1330 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1331 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1332 call->ndr_push, call->ndr_pull);
1333 if (!NT_STATUS_IS_OK(status)) {
1334 dcerpc_log_packet(table, opnum, NDR_OUT,
1340 if (pull->offset != pull->data_size) {
1341 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1342 pull->data_size - pull->offset));
1343 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1344 but it turns out that early versions of NT
1345 (specifically NT3.1) add junk onto the end of rpc
1346 packets, so if we want to interoperate at all with
1347 those versions then we need to ignore this error */
1350 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1352 return NT_STATUS_OK;
1357 a useful helper function for synchronous rpc requests
1359 this can be used when you have ndr push/pull functions in the
1362 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1363 const struct GUID *object,
1364 const struct dcerpc_interface_table *table,
1366 TALLOC_CTX *mem_ctx,
1369 struct rpc_request *req;
1371 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1373 return NT_STATUS_NO_MEMORY;
1376 return dcerpc_ndr_request_recv(req);
1381 a useful function for retrieving the server name we connected to
1383 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1385 if (!p->conn->transport.peer_name) {
1388 return p->conn->transport.peer_name(p->conn);
1393 get the dcerpc auth_level for a open connection
1395 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1399 if (c->flags & DCERPC_SEAL) {
1400 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1401 } else if (c->flags & DCERPC_SIGN) {
1402 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1403 } else if (c->flags & DCERPC_CONNECT) {
1404 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1406 auth_level = DCERPC_AUTH_LEVEL_NONE;
1413 send a dcerpc alter_context request
1415 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1416 TALLOC_CTX *mem_ctx,
1417 const struct dcerpc_syntax_id *syntax,
1418 const struct dcerpc_syntax_id *transfer_syntax)
1420 struct ncacn_packet pkt;
1424 p->syntax = *syntax;
1425 p->transfer_syntax = *transfer_syntax;
1427 init_ncacn_hdr(p->conn, &pkt);
1429 pkt.ptype = DCERPC_PKT_ALTER;
1430 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1431 pkt.call_id = p->conn->call_id;
1432 pkt.auth_length = 0;
1434 pkt.u.alter.max_xmit_frag = 5840;
1435 pkt.u.alter.max_recv_frag = 5840;
1436 pkt.u.alter.assoc_group_id = 0;
1437 pkt.u.alter.num_contexts = 1;
1438 pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1439 if (!pkt.u.alter.ctx_list) {
1440 return NT_STATUS_NO_MEMORY;
1442 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1443 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1444 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1445 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1446 pkt.u.alter.auth_info = data_blob(NULL, 0);
1448 /* construct the NDR form of the packet */
1449 status = ncacn_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1450 if (!NT_STATUS_IS_OK(status)) {
1454 /* send it on its way */
1455 status = full_request(p->conn, mem_ctx, &blob, &blob);
1456 if (!NT_STATUS_IS_OK(status)) {
1460 /* unmarshall the NDR */
1461 status = ncacn_pull(p->conn, &blob, mem_ctx, &pkt);
1462 if (!NT_STATUS_IS_OK(status)) {
1466 if (pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1467 pkt.u.alter_resp.num_results == 1 &&
1468 pkt.u.alter_resp.ctx_list[0].result != 0) {
1469 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1470 pkt.u.alter_resp.ctx_list[0].reason));
1471 return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason);
1474 if (pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1475 pkt.u.alter_resp.num_results == 0 ||
1476 pkt.u.alter_resp.ctx_list[0].result != 0) {
1477 return NT_STATUS_UNSUCCESSFUL;
1480 /* the alter_resp might contain a reply set of credentials */
1481 if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) {
1482 status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info,
1484 p->conn->security_state.auth_info,
1485 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);