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 3 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, see <http://www.gnu.org/licenses/>.
24 #include "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.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"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
36 enum rpc_request_state {
43 handle for an async dcerpc request
46 struct rpc_request *next, *prev;
47 struct dcerpc_pipe *p;
50 enum rpc_request_state state;
55 /* this is used to distinguish bind and alter_context requests
56 from normal requests */
57 void (*recv_handler)(struct rpc_request *conn,
58 DATA_BLOB *blob, struct ncacn_packet *pkt);
60 const struct GUID *object;
62 DATA_BLOB request_data;
65 /* use by the ndr level async recv call */
67 const struct ndr_interface_table *table;
74 void (*callback)(struct rpc_request *);
79 _PUBLIC_ NTSTATUS dcerpc_init(void)
84 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
85 static void dcerpc_ship_next_request(struct dcecli_connection *c);
87 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
88 const struct GUID *object,
90 DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
93 DATA_BLOB *stub_data);
94 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
98 ndr_push_flags_fn_t ndr_push,
99 ndr_pull_flags_fn_t ndr_pull);
100 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
101 struct ndr_pull *pull_in,
104 ndr_push_flags_fn_t ndr_push,
105 ndr_pull_flags_fn_t ndr_pull,
106 ndr_print_function_t ndr_print);
108 /* destroy a dcerpc connection */
109 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
112 conn->free_skipped = true;
115 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
120 /* initialise a dcerpc connection.
121 the event context is optional
123 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
124 struct tevent_context *ev)
126 struct dcecli_connection *c;
128 c = talloc_zero(mem_ctx, struct dcecli_connection);
135 if (c->event_ctx == NULL) {
141 c->security_state.auth_info = NULL;
142 c->security_state.session_key = dcerpc_generic_session_key;
143 c->security_state.generic_state = NULL;
144 c->binding_string = NULL;
146 c->srv_max_xmit_frag = 0;
147 c->srv_max_recv_frag = 0;
150 talloc_set_destructor(c, dcerpc_connection_destructor);
155 struct dcerpc_bh_state {
156 struct dcerpc_pipe *p;
159 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
161 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
162 struct dcerpc_bh_state);
172 if (hs->p->conn->dead) {
179 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
182 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
183 struct dcerpc_bh_state);
187 return DCERPC_REQUEST_TIMEOUT;
190 old = hs->p->request_timeout;
191 hs->p->request_timeout = timeout;
196 struct dcerpc_bh_raw_call_state {
197 struct dcerpc_binding_handle *h;
203 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
205 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
206 struct tevent_context *ev,
207 struct dcerpc_binding_handle *h,
208 const struct GUID *object,
211 const uint8_t *in_data,
214 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
215 struct dcerpc_bh_state);
216 struct tevent_req *req;
217 struct dcerpc_bh_raw_call_state *state;
219 struct rpc_request *subreq;
221 req = tevent_req_create(mem_ctx, &state,
222 struct dcerpc_bh_raw_call_state);
227 state->in_data.data = discard_const_p(uint8_t, in_data);
228 state->in_data.length = in_length;
230 ok = dcerpc_bh_is_connected(h);
232 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
233 return tevent_req_post(req, ev);
236 subreq = dcerpc_request_send(hs->p,
240 if (tevent_req_nomem(subreq, req)) {
241 return tevent_req_post(req, ev);
243 subreq->async.callback = dcerpc_bh_raw_call_done;
244 subreq->async.private_data = req;
249 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
251 struct tevent_req *req =
252 talloc_get_type_abort(subreq->async.private_data,
254 struct dcerpc_bh_raw_call_state *state =
256 struct dcerpc_bh_raw_call_state);
260 state->out_flags = 0;
261 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
262 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
265 fault_code = subreq->fault_code;
267 status = dcerpc_request_recv(subreq, state, &state->out_data);
268 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
269 status = dcerpc_fault_to_nt_status(fault_code);
271 if (!NT_STATUS_IS_OK(status)) {
272 tevent_req_nterror(req, status);
276 tevent_req_done(req);
279 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
285 struct dcerpc_bh_raw_call_state *state =
287 struct dcerpc_bh_raw_call_state);
290 if (tevent_req_is_nterror(req, &status)) {
291 tevent_req_received(req);
295 *out_data = talloc_move(mem_ctx, &state->out_data.data);
296 *out_length = state->out_data.length;
297 *out_flags = state->out_flags;
298 tevent_req_received(req);
302 struct dcerpc_bh_disconnect_state {
306 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
307 struct tevent_context *ev,
308 struct dcerpc_binding_handle *h)
310 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
311 struct dcerpc_bh_state);
312 struct tevent_req *req;
313 struct dcerpc_bh_disconnect_state *state;
316 req = tevent_req_create(mem_ctx, &state,
317 struct dcerpc_bh_disconnect_state);
322 ok = dcerpc_bh_is_connected(h);
324 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
325 return tevent_req_post(req, ev);
328 /* TODO: do a real disconnect ... */
331 tevent_req_done(req);
332 return tevent_req_post(req, ev);
335 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
339 if (tevent_req_is_nterror(req, &status)) {
340 tevent_req_received(req);
344 tevent_req_received(req);
348 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
350 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
351 struct dcerpc_bh_state);
353 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
360 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
362 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
363 struct dcerpc_bh_state);
365 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
372 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
374 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
375 struct dcerpc_bh_state);
377 if (hs->p->conn->flags & DCERPC_NDR64) {
384 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
386 const void *_struct_ptr,
387 const struct ndr_interface_call *call)
389 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
390 struct dcerpc_bh_state);
391 void *struct_ptr = discard_const(_struct_ptr);
393 if (ndr_flags & NDR_IN) {
394 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
395 ndr_print_function_debug(call->ndr_print,
401 if (ndr_flags & NDR_OUT) {
402 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
403 ndr_print_function_debug(call->ndr_print,
411 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
413 const void *struct_ptr,
414 const struct ndr_interface_call *call)
416 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
417 call->name, nt_errstr(error)));
420 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
422 const DATA_BLOB *blob,
423 const struct ndr_interface_call *call)
425 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
426 struct dcerpc_bh_state);
427 const uint32_t num_examples = 20;
430 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
431 call->name, nt_errstr(error)));
433 if (hs->p->conn->packet_log_dir == NULL) return;
435 for (i=0;i<num_examples;i++) {
437 asprintf(&name, "%s/rpclog/%s-out.%d",
438 hs->p->conn->packet_log_dir,
443 if (!file_exist(name)) {
444 if (file_save(name, blob->data, blob->length)) {
445 DEBUG(10,("Logged rpc packet to %s\n", name));
454 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
456 const DATA_BLOB *blob,
457 const struct ndr_interface_call *call)
459 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
460 struct dcerpc_bh_state);
462 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
465 status = dcerpc_ndr_validate_in(hs->p->conn,
471 if (!NT_STATUS_IS_OK(status)) {
472 DEBUG(0,("Validation [in] failed for %s - %s\n",
473 call->name, nt_errstr(status)));
478 DEBUG(10,("rpc request data:\n"));
479 dump_data(10, blob->data, blob->length);
484 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
485 struct ndr_pull *pull_in,
486 const void *_struct_ptr,
487 const struct ndr_interface_call *call)
489 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
490 struct dcerpc_bh_state);
491 void *struct_ptr = discard_const(_struct_ptr);
493 DEBUG(10,("rpc reply data:\n"));
494 dump_data(10, pull_in->data, pull_in->data_size);
496 if (pull_in->offset != pull_in->data_size) {
497 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
498 pull_in->data_size - pull_in->offset,
499 pull_in->offset, pull_in->offset,
501 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
502 but it turns out that early versions of NT
503 (specifically NT3.1) add junk onto the end of rpc
504 packets, so if we want to interoperate at all with
505 those versions then we need to ignore this error */
508 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
511 status = dcerpc_ndr_validate_out(hs->p->conn,
518 if (!NT_STATUS_IS_OK(status)) {
519 DEBUG(2,("Validation [out] failed for %s - %s\n",
520 call->name, nt_errstr(status)));
528 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
530 .is_connected = dcerpc_bh_is_connected,
531 .set_timeout = dcerpc_bh_set_timeout,
532 .raw_call_send = dcerpc_bh_raw_call_send,
533 .raw_call_recv = dcerpc_bh_raw_call_recv,
534 .disconnect_send = dcerpc_bh_disconnect_send,
535 .disconnect_recv = dcerpc_bh_disconnect_recv,
537 .push_bigendian = dcerpc_bh_push_bigendian,
538 .ref_alloc = dcerpc_bh_ref_alloc,
539 .use_ndr64 = dcerpc_bh_use_ndr64,
540 .do_ndr_print = dcerpc_bh_do_ndr_print,
541 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
542 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
543 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
544 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
547 /* initialise a dcerpc pipe. */
548 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
550 struct dcerpc_binding_handle *h;
551 struct dcerpc_bh_state *hs;
553 h = dcerpc_binding_handle_create(p,
558 struct dcerpc_bh_state,
565 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
570 /* initialise a dcerpc pipe. */
571 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
573 struct dcerpc_pipe *p;
575 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
580 p->conn = dcerpc_connection_init(p, ev);
581 if (p->conn == NULL) {
586 p->last_fault_code = 0;
588 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
591 ZERO_STRUCT(p->syntax);
592 ZERO_STRUCT(p->transfer_syntax);
595 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
598 p->binding_handle = dcerpc_pipe_binding_handle(p);
599 if (p->binding_handle == NULL) {
609 choose the next call id to use
611 static uint32_t next_call_id(struct dcecli_connection *c)
614 if (c->call_id == 0) {
621 setup for a ndr pull, also setting up any flags from the binding string
623 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
624 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
626 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
628 if (ndr == NULL) return ndr;
630 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
631 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
634 if (c->flags & DCERPC_NDR_REF_ALLOC) {
635 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
638 if (c->flags & DCERPC_NDR64) {
639 ndr->flags |= LIBNDR_FLAG_NDR64;
646 parse a data blob into a ncacn_packet structure. This handles both
647 input and output packets
649 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
650 struct ncacn_packet *pkt)
652 struct ndr_pull *ndr;
653 enum ndr_err_code ndr_err;
655 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
657 return NT_STATUS_NO_MEMORY;
660 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
661 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
664 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
665 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
666 return ndr_map_error2ntstatus(ndr_err);
673 parse the authentication information on a dcerpc response packet
675 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
676 DATA_BLOB *raw_packet,
677 struct ncacn_packet *pkt)
680 struct dcerpc_auth auth;
681 uint32_t auth_length;
683 if (!c->security_state.auth_info ||
684 !c->security_state.generic_state) {
688 switch (c->security_state.auth_info->auth_level) {
689 case DCERPC_AUTH_LEVEL_PRIVACY:
690 case DCERPC_AUTH_LEVEL_INTEGRITY:
693 case DCERPC_AUTH_LEVEL_CONNECT:
694 if (pkt->auth_length != 0) {
698 case DCERPC_AUTH_LEVEL_NONE:
699 if (pkt->auth_length != 0) {
700 return NT_STATUS_INVALID_NETWORK_RESPONSE;
705 return NT_STATUS_INVALID_LEVEL;
708 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
709 &pkt->u.response.stub_and_verifier,
710 &auth, &auth_length, false);
711 NT_STATUS_NOT_OK_RETURN(status);
713 pkt->u.response.stub_and_verifier.length -= auth_length;
715 /* check signature or unseal the packet */
716 switch (c->security_state.auth_info->auth_level) {
717 case DCERPC_AUTH_LEVEL_PRIVACY:
718 status = gensec_unseal_packet(c->security_state.generic_state,
719 raw_packet->data + DCERPC_REQUEST_LENGTH,
720 pkt->u.response.stub_and_verifier.length,
722 raw_packet->length - auth.credentials.length,
724 memcpy(pkt->u.response.stub_and_verifier.data,
725 raw_packet->data + DCERPC_REQUEST_LENGTH,
726 pkt->u.response.stub_and_verifier.length);
729 case DCERPC_AUTH_LEVEL_INTEGRITY:
730 status = gensec_check_packet(c->security_state.generic_state,
731 pkt->u.response.stub_and_verifier.data,
732 pkt->u.response.stub_and_verifier.length,
734 raw_packet->length - auth.credentials.length,
738 case DCERPC_AUTH_LEVEL_CONNECT:
739 /* for now we ignore possible signatures here */
740 status = NT_STATUS_OK;
744 status = NT_STATUS_INVALID_LEVEL;
748 /* remove the indicated amount of padding */
749 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
750 return NT_STATUS_INFO_LENGTH_MISMATCH;
752 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
759 push a dcerpc request packet into a blob, possibly signing it.
761 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
762 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
764 struct ncacn_packet *pkt)
767 struct ndr_push *ndr;
769 size_t payload_length;
770 enum ndr_err_code ndr_err;
771 size_t hdr_size = DCERPC_REQUEST_LENGTH;
773 /* non-signed packets are simpler */
775 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
778 switch (c->security_state.auth_info->auth_level) {
779 case DCERPC_AUTH_LEVEL_PRIVACY:
780 case DCERPC_AUTH_LEVEL_INTEGRITY:
783 case DCERPC_AUTH_LEVEL_CONNECT:
784 /* TODO: let the gensec mech decide if it wants to generate a signature */
785 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
787 case DCERPC_AUTH_LEVEL_NONE:
788 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
791 return NT_STATUS_INVALID_LEVEL;
794 ndr = ndr_push_init_ctx(mem_ctx);
796 return NT_STATUS_NO_MEMORY;
799 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
800 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
803 if (c->flags & DCERPC_NDR64) {
804 ndr->flags |= LIBNDR_FLAG_NDR64;
807 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
808 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
812 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
813 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
814 return ndr_map_error2ntstatus(ndr_err);
817 /* pad to 16 byte multiple in the payload portion of the
818 packet. This matches what w2k3 does. Note that we can't use
819 ndr_push_align() as that is relative to the start of the
820 whole packet, whereas w2k8 wants it relative to the start
822 c->security_state.auth_info->auth_pad_length =
823 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
824 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
825 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
826 return ndr_map_error2ntstatus(ndr_err);
829 payload_length = pkt->u.request.stub_and_verifier.length +
830 c->security_state.auth_info->auth_pad_length;
832 /* we start without signature, it will appended later */
833 c->security_state.auth_info->credentials = data_blob(NULL,0);
835 /* add the auth verifier */
836 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
837 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
838 return ndr_map_error2ntstatus(ndr_err);
841 /* extract the whole packet as a blob */
842 *blob = ndr_push_blob(ndr);
845 * Setup the frag and auth length in the packet buffer.
846 * This is needed if the GENSEC mech does AEAD signing
847 * of the packet headers. The signature itself will be
850 dcerpc_set_frag_length(blob, blob->length + sig_size);
851 dcerpc_set_auth_length(blob, sig_size);
853 /* sign or seal the packet */
854 switch (c->security_state.auth_info->auth_level) {
855 case DCERPC_AUTH_LEVEL_PRIVACY:
856 status = gensec_seal_packet(c->security_state.generic_state,
858 blob->data + hdr_size,
863 if (!NT_STATUS_IS_OK(status)) {
868 case DCERPC_AUTH_LEVEL_INTEGRITY:
869 status = gensec_sign_packet(c->security_state.generic_state,
871 blob->data + hdr_size,
876 if (!NT_STATUS_IS_OK(status)) {
882 status = NT_STATUS_INVALID_LEVEL;
886 if (creds2.length != sig_size) {
887 /* this means the sig_size estimate for the signature
888 was incorrect. We have to correct the packet
889 sizes. That means we could go over the max fragment
891 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
892 (unsigned) creds2.length,
894 (unsigned) c->security_state.auth_info->auth_pad_length,
895 (unsigned) pkt->u.request.stub_and_verifier.length));
896 dcerpc_set_frag_length(blob, blob->length + creds2.length);
897 dcerpc_set_auth_length(blob, creds2.length);
900 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
901 return NT_STATUS_NO_MEMORY;
909 fill in the fixed values in a dcerpc header
911 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
914 pkt->rpc_vers_minor = 0;
915 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
918 pkt->drep[0] = DCERPC_DREP_LE;
926 map a bind nak reason to a NTSTATUS
928 static NTSTATUS dcerpc_map_reason(uint16_t reason)
931 case DCERPC_BIND_REASON_ASYNTAX:
932 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
933 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
934 return NT_STATUS_INVALID_PARAMETER;
936 return NT_STATUS_UNSUCCESSFUL;
940 a bind or alter context has failed
942 static void dcerpc_composite_fail(struct rpc_request *req)
944 struct composite_context *c = talloc_get_type(req->async.private_data,
945 struct composite_context);
946 composite_error(c, req->status);
950 remove requests from the pending or queued queues
952 static int dcerpc_req_dequeue(struct rpc_request *req)
954 switch (req->state) {
955 case RPC_REQUEST_QUEUED:
956 DLIST_REMOVE(req->p->conn->request_queue, req);
958 case RPC_REQUEST_PENDING:
959 DLIST_REMOVE(req->p->conn->pending, req);
961 case RPC_REQUEST_DONE:
969 mark the dcerpc connection dead. All outstanding requests get an error
971 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
973 if (conn->dead) return;
977 if (conn->transport.shutdown_pipe) {
978 conn->transport.shutdown_pipe(conn, status);
981 /* all pending requests get the error */
982 while (conn->pending) {
983 struct rpc_request *req = conn->pending;
984 dcerpc_req_dequeue(req);
985 req->state = RPC_REQUEST_DONE;
986 req->status = status;
987 if (req->async.callback) {
988 req->async.callback(req);
992 talloc_set_destructor(conn, NULL);
993 if (conn->free_skipped) {
999 forward declarations of the recv_data handlers for the types of
1000 packets we need to handle
1002 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1003 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1006 receive a dcerpc reply from the transport. Here we work out what
1007 type of reply it is (normal request, bind or alter context) and
1008 dispatch to the appropriate handler
1010 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1012 struct ncacn_packet pkt;
1014 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1015 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1018 /* the transport may be telling us of a severe error, such as
1020 if (!NT_STATUS_IS_OK(status)) {
1021 data_blob_free(blob);
1022 dcerpc_connection_dead(conn, status);
1026 /* parse the basic packet to work out what type of response this is */
1027 status = ncacn_pull(conn, blob, blob->data, &pkt);
1028 if (!NT_STATUS_IS_OK(status)) {
1029 data_blob_free(blob);
1030 dcerpc_connection_dead(conn, status);
1033 dcerpc_request_recv_data(conn, blob, &pkt);
1037 Receive a bind reply from the transport
1039 static void dcerpc_bind_recv_handler(struct rpc_request *req,
1040 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1042 struct composite_context *c;
1043 struct dcecli_connection *conn;
1045 c = talloc_get_type(req->async.private_data, struct composite_context);
1047 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1048 DEBUG(2,("dcerpc: bind_nak reason %d\n",
1049 pkt->u.bind_nak.reject_reason));
1050 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
1055 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1056 (pkt->u.bind_ack.num_results == 0) ||
1057 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1058 req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1059 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1063 conn = req->p->conn;
1065 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1066 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1068 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1069 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1070 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1073 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1074 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1075 conn->flags |= DCERPC_HEADER_SIGNING;
1078 /* the bind_ack might contain a reply set of credentials */
1079 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1081 uint32_t auth_length;
1082 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1083 conn->security_state.auth_info, &auth_length, true);
1084 if (!NT_STATUS_IS_OK(status)) {
1085 composite_error(c, status);
1090 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1096 handle timeouts of individual dcerpc requests
1098 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1099 struct timeval t, void *private_data)
1101 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1103 if (req->ignore_timeout) {
1104 dcerpc_req_dequeue(req);
1105 req->state = RPC_REQUEST_DONE;
1106 req->status = NT_STATUS_IO_TIMEOUT;
1107 if (req->async.callback) {
1108 req->async.callback(req);
1113 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1117 send a async dcerpc bind request
1119 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
1120 TALLOC_CTX *mem_ctx,
1121 const struct ndr_syntax_id *syntax,
1122 const struct ndr_syntax_id *transfer_syntax)
1124 struct composite_context *c;
1125 struct ncacn_packet pkt;
1127 struct rpc_request *req;
1129 c = composite_create(mem_ctx,p->conn->event_ctx);
1130 if (c == NULL) return NULL;
1132 c->private_data = p;
1134 p->syntax = *syntax;
1135 p->transfer_syntax = *transfer_syntax;
1137 init_ncacn_hdr(p->conn, &pkt);
1139 pkt.ptype = DCERPC_PKT_BIND;
1140 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1141 pkt.call_id = p->conn->call_id;
1142 pkt.auth_length = 0;
1144 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1145 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1148 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1149 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1152 pkt.u.bind.max_xmit_frag = 5840;
1153 pkt.u.bind.max_recv_frag = 5840;
1154 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1155 pkt.u.bind.num_contexts = 1;
1156 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1157 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
1158 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1159 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1160 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1161 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1162 pkt.u.bind.auth_info = data_blob(NULL, 0);
1164 /* construct the NDR form of the packet */
1165 c->status = ncacn_push_auth(&blob, c, &pkt,
1166 p->conn->security_state.auth_info);
1167 if (!composite_is_ok(c)) return c;
1169 p->conn->transport.recv_data = dcerpc_recv_data;
1172 * we allocate a dcerpc_request so we can be in the same
1173 * request queue as normal requests
1175 req = talloc_zero(c, struct rpc_request);
1176 if (composite_nomem(req, c)) return c;
1178 req->state = RPC_REQUEST_PENDING;
1179 req->call_id = pkt.call_id;
1180 req->async.private_data = c;
1181 req->async.callback = dcerpc_composite_fail;
1183 req->recv_handler = dcerpc_bind_recv_handler;
1184 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1185 talloc_set_destructor(req, dcerpc_req_dequeue);
1187 c->status = p->conn->transport.send_request(p->conn, &blob,
1189 if (!composite_is_ok(c)) return c;
1191 tevent_add_timer(c->event_ctx, req,
1192 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1193 dcerpc_timeout_handler, req);
1199 recv side of async dcerpc bind request
1201 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
1203 NTSTATUS result = composite_wait(ctx);
1209 perform a continued bind (and auth3)
1211 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1212 TALLOC_CTX *mem_ctx)
1214 struct ncacn_packet pkt;
1218 init_ncacn_hdr(p->conn, &pkt);
1220 pkt.ptype = DCERPC_PKT_AUTH3;
1221 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1222 pkt.call_id = next_call_id(p->conn);
1223 pkt.auth_length = 0;
1224 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1226 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1227 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1230 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1231 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1234 /* construct the NDR form of the packet */
1235 status = ncacn_push_auth(&blob, mem_ctx,
1237 p->conn->security_state.auth_info);
1238 if (!NT_STATUS_IS_OK(status)) {
1242 /* send it on its way */
1243 status = p->conn->transport.send_request(p->conn, &blob, false);
1244 if (!NT_STATUS_IS_OK(status)) {
1248 return NT_STATUS_OK;
1253 process a fragment received from the transport layer during a
1256 This function frees the data
1258 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1259 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1261 struct rpc_request *req;
1262 unsigned int length;
1263 NTSTATUS status = NT_STATUS_OK;
1266 if this is an authenticated connection then parse and check
1267 the auth info. We have to do this before finding the
1268 matching packet, as the request structure might have been
1269 removed due to a timeout, but if it has been we still need
1270 to run the auth routines so that we don't get the sign/seal
1271 info out of step with the server
1273 if (c->security_state.auth_info && c->security_state.generic_state &&
1274 pkt->ptype == DCERPC_PKT_RESPONSE) {
1275 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1278 /* find the matching request */
1279 for (req=c->pending;req;req=req->next) {
1280 if (pkt->call_id == req->call_id) break;
1284 /* useful for testing certain vendors RPC servers */
1285 if (req == NULL && c->pending && pkt->call_id == 0) {
1286 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1292 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1293 data_blob_free(raw_packet);
1297 talloc_steal(req, raw_packet->data);
1299 if (req->recv_handler != NULL) {
1300 dcerpc_req_dequeue(req);
1301 req->state = RPC_REQUEST_DONE;
1302 req->recv_handler(req, raw_packet, pkt);
1306 if (pkt->ptype == DCERPC_PKT_FAULT) {
1307 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1308 req->fault_code = pkt->u.fault.status;
1309 req->status = NT_STATUS_NET_WRITE_FAULT;
1313 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1314 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1316 req->fault_code = DCERPC_FAULT_OTHER;
1317 req->status = NT_STATUS_NET_WRITE_FAULT;
1321 /* now check the status from the auth routines, and if it failed then fail
1322 this request accordingly */
1323 if (!NT_STATUS_IS_OK(status)) {
1324 req->status = status;
1328 length = pkt->u.response.stub_and_verifier.length;
1331 req->payload.data = talloc_realloc(req,
1334 req->payload.length + length);
1335 if (!req->payload.data) {
1336 req->status = NT_STATUS_NO_MEMORY;
1339 memcpy(req->payload.data+req->payload.length,
1340 pkt->u.response.stub_and_verifier.data, length);
1341 req->payload.length += length;
1344 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1345 c->transport.send_read(c);
1349 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1350 req->flags |= DCERPC_PULL_BIGENDIAN;
1352 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1357 /* we've got the full payload */
1358 req->state = RPC_REQUEST_DONE;
1359 DLIST_REMOVE(c->pending, req);
1361 if (c->request_queue != NULL) {
1362 /* We have to look at shipping further requests before calling
1363 * the async function, that one might close the pipe */
1364 dcerpc_ship_next_request(c);
1367 if (req->async.callback) {
1368 req->async.callback(req);
1373 perform the send side of a async dcerpc request
1375 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
1376 const struct GUID *object,
1378 DATA_BLOB *stub_data)
1380 struct rpc_request *req;
1382 p->conn->transport.recv_data = dcerpc_recv_data;
1384 req = talloc(p, struct rpc_request);
1390 req->call_id = next_call_id(p->conn);
1391 req->status = NT_STATUS_OK;
1392 req->state = RPC_REQUEST_QUEUED;
1393 req->payload = data_blob(NULL, 0);
1395 req->fault_code = 0;
1396 req->ignore_timeout = false;
1397 req->async.callback = NULL;
1398 req->async.private_data = NULL;
1399 req->recv_handler = NULL;
1401 if (object != NULL) {
1402 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1403 if (req->object == NULL) {
1412 req->request_data.length = stub_data->length;
1413 req->request_data.data = talloc_reference(req, stub_data->data);
1414 if (req->request_data.length && req->request_data.data == NULL) {
1418 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1419 talloc_set_destructor(req, dcerpc_req_dequeue);
1421 dcerpc_ship_next_request(p->conn);
1423 if (p->request_timeout) {
1424 tevent_add_timer(dcerpc_event_context(p), req,
1425 timeval_current_ofs(p->request_timeout, 0),
1426 dcerpc_timeout_handler, req);
1433 Send a request using the transport
1436 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1438 struct rpc_request *req;
1439 struct dcerpc_pipe *p;
1440 DATA_BLOB *stub_data;
1441 struct ncacn_packet pkt;
1443 uint32_t remaining, chunk_size;
1444 bool first_packet = true;
1445 size_t sig_size = 0;
1446 bool need_async = false;
1448 req = c->request_queue;
1454 stub_data = &req->request_data;
1460 DLIST_REMOVE(c->request_queue, req);
1461 DLIST_ADD(c->pending, req);
1462 req->state = RPC_REQUEST_PENDING;
1464 init_ncacn_hdr(p->conn, &pkt);
1466 remaining = stub_data->length;
1468 /* we can write a full max_recv_frag size, minus the dcerpc
1469 request header size */
1470 chunk_size = p->conn->srv_max_recv_frag;
1471 chunk_size -= DCERPC_REQUEST_LENGTH;
1472 if (c->security_state.auth_info &&
1473 c->security_state.generic_state) {
1474 sig_size = gensec_sig_size(c->security_state.generic_state,
1475 p->conn->srv_max_recv_frag);
1477 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1478 chunk_size -= sig_size;
1481 chunk_size -= (chunk_size % 16);
1483 pkt.ptype = DCERPC_PKT_REQUEST;
1484 pkt.call_id = req->call_id;
1485 pkt.auth_length = 0;
1487 pkt.u.request.alloc_hint = remaining;
1488 pkt.u.request.context_id = p->context_id;
1489 pkt.u.request.opnum = req->opnum;
1492 pkt.u.request.object.object = *req->object;
1493 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1494 chunk_size -= ndr_size_GUID(req->object,0);
1497 /* we send a series of pdus without waiting for a reply */
1498 while (remaining > 0 || first_packet) {
1499 uint32_t chunk = MIN(chunk_size, remaining);
1500 bool last_frag = false;
1501 bool do_trans = false;
1503 first_packet = false;
1504 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1506 if (remaining == stub_data->length) {
1507 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1509 if (chunk == remaining) {
1510 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1514 pkt.u.request.stub_and_verifier.data = stub_data->data +
1515 (stub_data->length - remaining);
1516 pkt.u.request.stub_and_verifier.length = chunk;
1518 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1519 if (!NT_STATUS_IS_OK(req->status)) {
1520 req->state = RPC_REQUEST_DONE;
1521 DLIST_REMOVE(p->conn->pending, req);
1525 if (last_frag && !need_async) {
1529 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1530 if (!NT_STATUS_IS_OK(req->status)) {
1531 req->state = RPC_REQUEST_DONE;
1532 DLIST_REMOVE(p->conn->pending, req);
1536 if (last_frag && !do_trans) {
1537 req->status = p->conn->transport.send_read(p->conn);
1538 if (!NT_STATUS_IS_OK(req->status)) {
1539 req->state = RPC_REQUEST_DONE;
1540 DLIST_REMOVE(p->conn->pending, req);
1550 return the event context for a dcerpc pipe
1551 used by callers who wish to operate asynchronously
1553 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1555 return p->conn->event_ctx;
1561 perform the receive side of a async dcerpc request
1563 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1564 TALLOC_CTX *mem_ctx,
1565 DATA_BLOB *stub_data)
1569 while (req->state != RPC_REQUEST_DONE) {
1570 struct tevent_context *ctx = dcerpc_event_context(req->p);
1571 if (tevent_loop_once(ctx) != 0) {
1572 return NT_STATUS_CONNECTION_DISCONNECTED;
1575 *stub_data = req->payload;
1576 status = req->status;
1577 if (stub_data->data) {
1578 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1580 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1581 req->p->last_fault_code = req->fault_code;
1583 talloc_unlink(talloc_parent(req), req);
1588 this is a paranoid NDR validator. For every packet we push onto the wire
1589 we pull it back again, then push it again. Then we compare the raw NDR data
1590 for that to the NDR we initially generated. If they don't match then we know
1591 we must have a bug in either the pull or push side of our code
1593 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1594 TALLOC_CTX *mem_ctx,
1597 ndr_push_flags_fn_t ndr_push,
1598 ndr_pull_flags_fn_t ndr_pull)
1601 struct ndr_pull *pull;
1602 struct ndr_push *push;
1604 enum ndr_err_code ndr_err;
1606 st = talloc_size(mem_ctx, struct_size);
1608 return NT_STATUS_NO_MEMORY;
1611 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1613 return NT_STATUS_NO_MEMORY;
1615 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1617 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1618 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1621 if (c->flags & DCERPC_NDR64) {
1622 pull->flags |= LIBNDR_FLAG_NDR64;
1625 ndr_err = ndr_pull(pull, NDR_IN, st);
1626 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1627 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1628 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1629 "failed input validation pull - %s",
1631 return ndr_map_error2ntstatus(ndr_err);
1634 push = ndr_push_init_ctx(mem_ctx);
1636 return NT_STATUS_NO_MEMORY;
1639 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1640 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1643 if (c->flags & DCERPC_NDR64) {
1644 push->flags |= LIBNDR_FLAG_NDR64;
1647 ndr_err = ndr_push(push, NDR_IN, st);
1648 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1649 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1650 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1651 "failed input validation push - %s",
1653 return ndr_map_error2ntstatus(ndr_err);
1656 blob2 = ndr_push_blob(push);
1658 if (data_blob_cmp(&blob, &blob2) != 0) {
1659 DEBUG(3,("original:\n"));
1660 dump_data(3, blob.data, blob.length);
1661 DEBUG(3,("secondary:\n"));
1662 dump_data(3, blob2.data, blob2.length);
1663 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1664 "failed input validation blobs doesn't match");
1665 return ndr_map_error2ntstatus(ndr_err);
1668 return NT_STATUS_OK;
1672 this is a paranoid NDR input validator. For every packet we pull
1673 from the wire we push it back again then pull and push it
1674 again. Then we compare the raw NDR data for that to the NDR we
1675 initially generated. If they don't match then we know we must have a
1676 bug in either the pull or push side of our code
1678 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1679 struct ndr_pull *pull_in,
1682 ndr_push_flags_fn_t ndr_push,
1683 ndr_pull_flags_fn_t ndr_pull,
1684 ndr_print_function_t ndr_print)
1687 struct ndr_pull *pull;
1688 struct ndr_push *push;
1689 DATA_BLOB blob, blob2;
1690 TALLOC_CTX *mem_ctx = pull_in;
1692 enum ndr_err_code ndr_err;
1694 st = talloc_size(mem_ctx, struct_size);
1696 return NT_STATUS_NO_MEMORY;
1698 memcpy(st, struct_ptr, struct_size);
1700 push = ndr_push_init_ctx(mem_ctx);
1702 return NT_STATUS_NO_MEMORY;
1705 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1706 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1707 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1708 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1709 "failed output validation push - %s",
1711 return ndr_map_error2ntstatus(ndr_err);
1714 blob = ndr_push_blob(push);
1716 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1718 return NT_STATUS_NO_MEMORY;
1721 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1722 ndr_err = ndr_pull(pull, NDR_OUT, st);
1723 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1724 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1725 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1726 "failed output validation pull - %s",
1728 return ndr_map_error2ntstatus(ndr_err);
1731 push = ndr_push_init_ctx(mem_ctx);
1733 return NT_STATUS_NO_MEMORY;
1736 ndr_err = ndr_push(push, NDR_OUT, st);
1737 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1738 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1739 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1740 "failed output validation push2 - %s",
1742 return ndr_map_error2ntstatus(ndr_err);
1745 blob2 = ndr_push_blob(push);
1747 if (data_blob_cmp(&blob, &blob2) != 0) {
1748 DEBUG(3,("original:\n"));
1749 dump_data(3, blob.data, blob.length);
1750 DEBUG(3,("secondary:\n"));
1751 dump_data(3, blob2.data, blob2.length);
1752 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1753 "failed output validation blobs doesn't match");
1754 return ndr_map_error2ntstatus(ndr_err);
1757 /* this checks the printed forms of the two structures, which effectively
1758 tests all of the value() attributes */
1759 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1760 NDR_OUT, struct_ptr);
1761 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1763 if (strcmp(s1, s2) != 0) {
1765 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1767 /* this is sometimes useful */
1768 printf("VALIDATE ERROR\n");
1769 file_save("wire.dat", s1, strlen(s1));
1770 file_save("gen.dat", s2, strlen(s2));
1771 system("diff -u wire.dat gen.dat");
1773 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1774 "failed output validation strings doesn't match");
1775 return ndr_map_error2ntstatus(ndr_err);
1778 return NT_STATUS_OK;
1782 a useful function for retrieving the server name we connected to
1784 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1786 if (!p->conn->transport.target_hostname) {
1787 if (!p->conn->transport.peer_name) {
1790 return p->conn->transport.peer_name(p->conn);
1792 return p->conn->transport.target_hostname(p->conn);
1797 get the dcerpc auth_level for a open connection
1799 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1803 if (c->flags & DCERPC_SEAL) {
1804 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1805 } else if (c->flags & DCERPC_SIGN) {
1806 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1807 } else if (c->flags & DCERPC_CONNECT) {
1808 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1810 auth_level = DCERPC_AUTH_LEVEL_NONE;
1816 Receive an alter reply from the transport
1818 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1819 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1821 struct composite_context *c;
1822 struct dcerpc_pipe *recv_pipe;
1824 c = talloc_get_type(req->async.private_data, struct composite_context);
1825 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1827 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1828 pkt->u.alter_resp.num_results == 1 &&
1829 pkt->u.alter_resp.ctx_list[0].result != 0) {
1830 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1831 pkt->u.alter_resp.ctx_list[0].reason));
1832 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1836 if (pkt->ptype == DCERPC_PKT_FAULT) {
1837 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1838 recv_pipe->last_fault_code = pkt->u.fault.status;
1839 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1843 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1844 pkt->u.alter_resp.num_results == 0 ||
1845 pkt->u.alter_resp.ctx_list[0].result != 0) {
1846 recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1847 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1851 /* the alter_resp might contain a reply set of credentials */
1852 if (recv_pipe->conn->security_state.auth_info &&
1853 pkt->u.alter_resp.auth_info.length) {
1854 struct dcecli_connection *conn = recv_pipe->conn;
1856 uint32_t auth_length;
1857 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1858 conn->security_state.auth_info, &auth_length, true);
1859 if (!NT_STATUS_IS_OK(status)) {
1860 composite_error(c, status);
1869 send a dcerpc alter_context request
1871 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1872 TALLOC_CTX *mem_ctx,
1873 const struct ndr_syntax_id *syntax,
1874 const struct ndr_syntax_id *transfer_syntax)
1876 struct composite_context *c;
1877 struct ncacn_packet pkt;
1879 struct rpc_request *req;
1881 c = composite_create(mem_ctx, p->conn->event_ctx);
1882 if (c == NULL) return NULL;
1884 c->private_data = p;
1886 p->syntax = *syntax;
1887 p->transfer_syntax = *transfer_syntax;
1889 init_ncacn_hdr(p->conn, &pkt);
1891 pkt.ptype = DCERPC_PKT_ALTER;
1892 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1893 pkt.call_id = p->conn->call_id;
1894 pkt.auth_length = 0;
1896 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1897 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1900 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1901 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1904 pkt.u.alter.max_xmit_frag = 5840;
1905 pkt.u.alter.max_recv_frag = 5840;
1906 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1907 pkt.u.alter.num_contexts = 1;
1908 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1909 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1910 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1911 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1912 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1913 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1914 pkt.u.alter.auth_info = data_blob(NULL, 0);
1916 /* construct the NDR form of the packet */
1917 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1918 p->conn->security_state.auth_info);
1919 if (!composite_is_ok(c)) return c;
1921 p->conn->transport.recv_data = dcerpc_recv_data;
1924 * we allocate a dcerpc_request so we can be in the same
1925 * request queue as normal requests
1927 req = talloc_zero(c, struct rpc_request);
1928 if (composite_nomem(req, c)) return c;
1930 req->state = RPC_REQUEST_PENDING;
1931 req->call_id = pkt.call_id;
1932 req->async.private_data = c;
1933 req->async.callback = dcerpc_composite_fail;
1935 req->recv_handler = dcerpc_alter_recv_handler;
1936 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1937 talloc_set_destructor(req, dcerpc_req_dequeue);
1939 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1940 if (!composite_is_ok(c)) return c;
1942 tevent_add_timer(c->event_ctx, req,
1943 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1944 dcerpc_timeout_handler, req);
1949 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1951 NTSTATUS result = composite_wait(ctx);
1957 send a dcerpc alter_context request
1959 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1960 TALLOC_CTX *mem_ctx,
1961 const struct ndr_syntax_id *syntax,
1962 const struct ndr_syntax_id *transfer_syntax)
1964 struct composite_context *creq;
1965 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1966 return dcerpc_alter_context_recv(creq);