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 "auth/gensec/gensec.h"
31 #include "param/param.h"
32 #include "lib/util/tevent_ntstatus.h"
33 #include "librpc/rpc/rpc_common.h"
35 enum rpc_request_state {
42 handle for an async dcerpc request
45 struct rpc_request *next, *prev;
46 struct dcerpc_pipe *p;
49 enum rpc_request_state state;
54 /* this is used to distinguish bind and alter_context requests
55 from normal requests */
56 void (*recv_handler)(struct rpc_request *conn,
57 DATA_BLOB *blob, struct ncacn_packet *pkt);
59 const struct GUID *object;
61 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_schedule_io_trigger(struct dcecli_connection *c);
87 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
88 struct dcerpc_pipe *p,
89 const struct GUID *object,
91 DATA_BLOB *stub_data);
92 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
94 DATA_BLOB *stub_data);
95 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
99 ndr_push_flags_fn_t ndr_push,
100 ndr_pull_flags_fn_t ndr_pull);
101 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
102 struct ndr_pull *pull_in,
105 ndr_push_flags_fn_t ndr_push,
106 ndr_pull_flags_fn_t ndr_pull,
107 ndr_print_function_t ndr_print);
109 /* destroy a dcerpc connection */
110 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
113 conn->free_skipped = true;
116 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
121 /* initialise a dcerpc connection.
122 the event context is optional
124 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
125 struct tevent_context *ev)
127 struct dcecli_connection *c;
129 c = talloc_zero(mem_ctx, struct dcecli_connection);
136 if (c->event_ctx == NULL) {
142 c->security_state.auth_info = NULL;
143 c->security_state.session_key = dcerpc_generic_session_key;
144 c->security_state.generic_state = NULL;
145 c->binding_string = NULL;
147 c->srv_max_xmit_frag = 0;
148 c->srv_max_recv_frag = 0;
151 c->io_trigger = tevent_create_immediate(c);
152 if (c->io_trigger == NULL) {
157 talloc_set_destructor(c, dcerpc_connection_destructor);
162 struct dcerpc_bh_state {
163 struct dcerpc_pipe *p;
166 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
168 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
169 struct dcerpc_bh_state);
179 if (hs->p->conn->dead) {
186 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
189 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
190 struct dcerpc_bh_state);
194 return DCERPC_REQUEST_TIMEOUT;
197 old = hs->p->request_timeout;
198 hs->p->request_timeout = timeout;
203 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
204 enum dcerpc_AuthType *auth_type,
205 enum dcerpc_AuthLevel *auth_level)
207 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
208 struct dcerpc_bh_state);
214 if (hs->p->conn == NULL) {
218 if (hs->p->conn->security_state.auth_info == NULL) {
222 *auth_type = hs->p->conn->security_state.auth_info->auth_type;
223 *auth_level = hs->p->conn->security_state.auth_info->auth_level;
226 struct dcerpc_bh_raw_call_state {
227 struct tevent_context *ev;
228 struct dcerpc_binding_handle *h;
234 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
236 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
237 struct tevent_context *ev,
238 struct dcerpc_binding_handle *h,
239 const struct GUID *object,
242 const uint8_t *in_data,
245 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
246 struct dcerpc_bh_state);
247 struct tevent_req *req;
248 struct dcerpc_bh_raw_call_state *state;
250 struct rpc_request *subreq;
252 req = tevent_req_create(mem_ctx, &state,
253 struct dcerpc_bh_raw_call_state);
259 state->in_data.data = discard_const_p(uint8_t, in_data);
260 state->in_data.length = in_length;
262 ok = dcerpc_bh_is_connected(h);
264 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
265 return tevent_req_post(req, ev);
268 subreq = dcerpc_request_send(state,
273 if (tevent_req_nomem(subreq, req)) {
274 return tevent_req_post(req, ev);
276 subreq->async.callback = dcerpc_bh_raw_call_done;
277 subreq->async.private_data = req;
282 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
284 struct tevent_req *req =
285 talloc_get_type_abort(subreq->async.private_data,
287 struct dcerpc_bh_raw_call_state *state =
289 struct dcerpc_bh_raw_call_state);
293 state->out_flags = 0;
294 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
295 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
298 fault_code = subreq->fault_code;
300 status = dcerpc_request_recv(subreq, state, &state->out_data);
301 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
302 status = dcerpc_fault_to_nt_status(fault_code);
306 * We trigger the callback in the next event run
307 * because the code in this file might trigger
308 * multiple request callbacks from within a single
311 * In order to avoid segfaults from within
312 * dcerpc_connection_dead() we call
313 * tevent_req_defer_callback().
315 tevent_req_defer_callback(req, state->ev);
317 if (!NT_STATUS_IS_OK(status)) {
318 tevent_req_nterror(req, status);
322 tevent_req_done(req);
325 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
331 struct dcerpc_bh_raw_call_state *state =
333 struct dcerpc_bh_raw_call_state);
336 if (tevent_req_is_nterror(req, &status)) {
337 tevent_req_received(req);
341 *out_data = talloc_move(mem_ctx, &state->out_data.data);
342 *out_length = state->out_data.length;
343 *out_flags = state->out_flags;
344 tevent_req_received(req);
348 struct dcerpc_bh_disconnect_state {
352 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
353 struct tevent_context *ev,
354 struct dcerpc_binding_handle *h)
356 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
357 struct dcerpc_bh_state);
358 struct tevent_req *req;
359 struct dcerpc_bh_disconnect_state *state;
362 req = tevent_req_create(mem_ctx, &state,
363 struct dcerpc_bh_disconnect_state);
368 ok = dcerpc_bh_is_connected(h);
370 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
371 return tevent_req_post(req, ev);
374 /* TODO: do a real disconnect ... */
377 tevent_req_done(req);
378 return tevent_req_post(req, ev);
381 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
385 if (tevent_req_is_nterror(req, &status)) {
386 tevent_req_received(req);
390 tevent_req_received(req);
394 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
396 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
397 struct dcerpc_bh_state);
399 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
406 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
408 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
409 struct dcerpc_bh_state);
411 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
418 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
420 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
421 struct dcerpc_bh_state);
423 if (hs->p->conn->flags & DCERPC_NDR64) {
430 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
432 const void *_struct_ptr,
433 const struct ndr_interface_call *call)
435 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
436 struct dcerpc_bh_state);
437 void *struct_ptr = discard_const(_struct_ptr);
439 if (ndr_flags & NDR_IN) {
440 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
441 ndr_print_function_debug(call->ndr_print,
447 if (ndr_flags & NDR_OUT) {
448 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
449 ndr_print_function_debug(call->ndr_print,
457 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
459 const void *struct_ptr,
460 const struct ndr_interface_call *call)
462 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
463 call->name, nt_errstr(error)));
466 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
468 const DATA_BLOB *blob,
469 const struct ndr_interface_call *call)
471 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
472 struct dcerpc_bh_state);
473 const uint32_t num_examples = 20;
476 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
477 call->name, nt_errstr(error)));
479 if (hs->p->conn->packet_log_dir == NULL) return;
481 for (i=0;i<num_examples;i++) {
483 asprintf(&name, "%s/rpclog/%s-out.%d",
484 hs->p->conn->packet_log_dir,
489 if (!file_exist(name)) {
490 if (file_save(name, blob->data, blob->length)) {
491 DEBUG(10,("Logged rpc packet to %s\n", name));
500 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
502 const DATA_BLOB *blob,
503 const struct ndr_interface_call *call)
505 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
506 struct dcerpc_bh_state);
508 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
511 status = dcerpc_ndr_validate_in(hs->p->conn,
517 if (!NT_STATUS_IS_OK(status)) {
518 DEBUG(0,("Validation [in] failed for %s - %s\n",
519 call->name, nt_errstr(status)));
524 DEBUG(10,("rpc request data:\n"));
525 dump_data(10, blob->data, blob->length);
530 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
531 struct ndr_pull *pull_in,
532 const void *_struct_ptr,
533 const struct ndr_interface_call *call)
535 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
536 struct dcerpc_bh_state);
537 void *struct_ptr = discard_const(_struct_ptr);
539 DEBUG(10,("rpc reply data:\n"));
540 dump_data(10, pull_in->data, pull_in->data_size);
542 if (pull_in->offset != pull_in->data_size) {
543 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
544 pull_in->data_size - pull_in->offset,
545 pull_in->offset, pull_in->offset,
547 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
548 but it turns out that early versions of NT
549 (specifically NT3.1) add junk onto the end of rpc
550 packets, so if we want to interoperate at all with
551 those versions then we need to ignore this error */
554 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
557 status = dcerpc_ndr_validate_out(hs->p->conn,
564 if (!NT_STATUS_IS_OK(status)) {
565 DEBUG(2,("Validation [out] failed for %s - %s\n",
566 call->name, nt_errstr(status)));
574 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
576 .is_connected = dcerpc_bh_is_connected,
577 .set_timeout = dcerpc_bh_set_timeout,
578 .auth_info = dcerpc_bh_auth_info,
579 .raw_call_send = dcerpc_bh_raw_call_send,
580 .raw_call_recv = dcerpc_bh_raw_call_recv,
581 .disconnect_send = dcerpc_bh_disconnect_send,
582 .disconnect_recv = dcerpc_bh_disconnect_recv,
584 .push_bigendian = dcerpc_bh_push_bigendian,
585 .ref_alloc = dcerpc_bh_ref_alloc,
586 .use_ndr64 = dcerpc_bh_use_ndr64,
587 .do_ndr_print = dcerpc_bh_do_ndr_print,
588 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
589 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
590 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
591 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
594 /* initialise a dcerpc pipe. */
595 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
597 struct dcerpc_binding_handle *h;
598 struct dcerpc_bh_state *hs;
600 h = dcerpc_binding_handle_create(p,
605 struct dcerpc_bh_state,
612 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
617 /* initialise a dcerpc pipe. */
618 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
620 struct dcerpc_pipe *p;
622 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
627 p->conn = dcerpc_connection_init(p, ev);
628 if (p->conn == NULL) {
633 p->last_fault_code = 0;
635 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
638 ZERO_STRUCT(p->syntax);
639 ZERO_STRUCT(p->transfer_syntax);
642 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
645 p->binding_handle = dcerpc_pipe_binding_handle(p);
646 if (p->binding_handle == NULL) {
656 choose the next call id to use
658 static uint32_t next_call_id(struct dcecli_connection *c)
661 if (c->call_id == 0) {
668 setup for a ndr pull, also setting up any flags from the binding string
670 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
671 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
673 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
675 if (ndr == NULL) return ndr;
677 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
678 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
681 if (c->flags & DCERPC_NDR_REF_ALLOC) {
682 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
685 if (c->flags & DCERPC_NDR64) {
686 ndr->flags |= LIBNDR_FLAG_NDR64;
693 parse a data blob into a ncacn_packet structure. This handles both
694 input and output packets
696 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
697 struct ncacn_packet *pkt)
699 struct ndr_pull *ndr;
700 enum ndr_err_code ndr_err;
702 ndr = ndr_pull_init_blob(blob, mem_ctx);
704 return NT_STATUS_NO_MEMORY;
707 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
708 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
711 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
712 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
715 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
716 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
717 return ndr_map_error2ntstatus(ndr_err);
724 parse the authentication information on a dcerpc response packet
726 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
727 DATA_BLOB *raw_packet,
728 struct ncacn_packet *pkt)
731 struct dcerpc_auth auth;
732 uint32_t auth_length;
734 if (!c->security_state.auth_info ||
735 !c->security_state.generic_state) {
739 switch (c->security_state.auth_info->auth_level) {
740 case DCERPC_AUTH_LEVEL_PRIVACY:
741 case DCERPC_AUTH_LEVEL_INTEGRITY:
744 case DCERPC_AUTH_LEVEL_CONNECT:
745 if (pkt->auth_length != 0) {
749 case DCERPC_AUTH_LEVEL_NONE:
750 if (pkt->auth_length != 0) {
751 return NT_STATUS_INVALID_NETWORK_RESPONSE;
756 return NT_STATUS_INVALID_LEVEL;
759 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
760 &pkt->u.response.stub_and_verifier,
761 &auth, &auth_length, false);
762 NT_STATUS_NOT_OK_RETURN(status);
764 pkt->u.response.stub_and_verifier.length -= auth_length;
766 /* check signature or unseal the packet */
767 switch (c->security_state.auth_info->auth_level) {
768 case DCERPC_AUTH_LEVEL_PRIVACY:
769 status = gensec_unseal_packet(c->security_state.generic_state,
770 raw_packet->data + DCERPC_REQUEST_LENGTH,
771 pkt->u.response.stub_and_verifier.length,
773 raw_packet->length - auth.credentials.length,
775 memcpy(pkt->u.response.stub_and_verifier.data,
776 raw_packet->data + DCERPC_REQUEST_LENGTH,
777 pkt->u.response.stub_and_verifier.length);
780 case DCERPC_AUTH_LEVEL_INTEGRITY:
781 status = gensec_check_packet(c->security_state.generic_state,
782 pkt->u.response.stub_and_verifier.data,
783 pkt->u.response.stub_and_verifier.length,
785 raw_packet->length - auth.credentials.length,
789 case DCERPC_AUTH_LEVEL_CONNECT:
790 /* for now we ignore possible signatures here */
791 status = NT_STATUS_OK;
795 status = NT_STATUS_INVALID_LEVEL;
799 /* remove the indicated amount of padding */
800 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
801 return NT_STATUS_INFO_LENGTH_MISMATCH;
803 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
810 push a dcerpc request packet into a blob, possibly signing it.
812 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
813 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
815 struct ncacn_packet *pkt)
818 struct ndr_push *ndr;
820 size_t payload_length;
821 enum ndr_err_code ndr_err;
822 size_t hdr_size = DCERPC_REQUEST_LENGTH;
824 /* non-signed packets are simpler */
826 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
829 switch (c->security_state.auth_info->auth_level) {
830 case DCERPC_AUTH_LEVEL_PRIVACY:
831 case DCERPC_AUTH_LEVEL_INTEGRITY:
834 case DCERPC_AUTH_LEVEL_CONNECT:
835 /* TODO: let the gensec mech decide if it wants to generate a signature */
836 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
838 case DCERPC_AUTH_LEVEL_NONE:
839 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
842 return NT_STATUS_INVALID_LEVEL;
845 ndr = ndr_push_init_ctx(mem_ctx);
847 return NT_STATUS_NO_MEMORY;
850 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
851 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
854 if (c->flags & DCERPC_NDR64) {
855 ndr->flags |= LIBNDR_FLAG_NDR64;
858 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
859 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
863 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
864 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
865 return ndr_map_error2ntstatus(ndr_err);
868 /* pad to 16 byte multiple in the payload portion of the
869 packet. This matches what w2k3 does. Note that we can't use
870 ndr_push_align() as that is relative to the start of the
871 whole packet, whereas w2k8 wants it relative to the start
873 c->security_state.auth_info->auth_pad_length =
874 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
875 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
876 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
877 return ndr_map_error2ntstatus(ndr_err);
880 payload_length = pkt->u.request.stub_and_verifier.length +
881 c->security_state.auth_info->auth_pad_length;
883 /* we start without signature, it will appended later */
884 c->security_state.auth_info->credentials = data_blob(NULL,0);
886 /* add the auth verifier */
887 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
888 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
889 return ndr_map_error2ntstatus(ndr_err);
892 /* extract the whole packet as a blob */
893 *blob = ndr_push_blob(ndr);
896 * Setup the frag and auth length in the packet buffer.
897 * This is needed if the GENSEC mech does AEAD signing
898 * of the packet headers. The signature itself will be
901 dcerpc_set_frag_length(blob, blob->length + sig_size);
902 dcerpc_set_auth_length(blob, sig_size);
904 /* sign or seal the packet */
905 switch (c->security_state.auth_info->auth_level) {
906 case DCERPC_AUTH_LEVEL_PRIVACY:
907 status = gensec_seal_packet(c->security_state.generic_state,
909 blob->data + hdr_size,
914 if (!NT_STATUS_IS_OK(status)) {
919 case DCERPC_AUTH_LEVEL_INTEGRITY:
920 status = gensec_sign_packet(c->security_state.generic_state,
922 blob->data + hdr_size,
927 if (!NT_STATUS_IS_OK(status)) {
933 status = NT_STATUS_INVALID_LEVEL;
937 if (creds2.length != sig_size) {
938 /* this means the sig_size estimate for the signature
939 was incorrect. We have to correct the packet
940 sizes. That means we could go over the max fragment
942 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
943 (unsigned) creds2.length,
945 (unsigned) c->security_state.auth_info->auth_pad_length,
946 (unsigned) pkt->u.request.stub_and_verifier.length));
947 dcerpc_set_frag_length(blob, blob->length + creds2.length);
948 dcerpc_set_auth_length(blob, creds2.length);
951 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
952 return NT_STATUS_NO_MEMORY;
960 fill in the fixed values in a dcerpc header
962 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
965 pkt->rpc_vers_minor = 0;
966 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
969 pkt->drep[0] = DCERPC_DREP_LE;
977 map a bind nak reason to a NTSTATUS
979 static NTSTATUS dcerpc_map_reason(uint16_t reason)
982 case DCERPC_BIND_REASON_ASYNTAX:
983 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
984 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
985 return NT_STATUS_INVALID_PARAMETER;
987 return NT_STATUS_UNSUCCESSFUL;
991 remove requests from the pending or queued queues
993 static int dcerpc_req_dequeue(struct rpc_request *req)
995 switch (req->state) {
996 case RPC_REQUEST_QUEUED:
997 DLIST_REMOVE(req->p->conn->request_queue, req);
999 case RPC_REQUEST_PENDING:
1000 DLIST_REMOVE(req->p->conn->pending, req);
1002 case RPC_REQUEST_DONE:
1010 mark the dcerpc connection dead. All outstanding requests get an error
1012 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1014 if (conn->dead) return;
1018 TALLOC_FREE(conn->io_trigger);
1019 conn->io_trigger_pending = false;
1021 conn->transport.recv_data = NULL;
1023 if (conn->transport.shutdown_pipe) {
1024 conn->transport.shutdown_pipe(conn, status);
1027 /* all pending requests get the error */
1028 while (conn->pending) {
1029 struct rpc_request *req = conn->pending;
1030 dcerpc_req_dequeue(req);
1031 req->state = RPC_REQUEST_DONE;
1032 req->status = status;
1033 if (req->async.callback) {
1034 req->async.callback(req);
1038 /* all requests, which are not shipped */
1039 while (conn->request_queue) {
1040 struct rpc_request *req = conn->request_queue;
1041 dcerpc_req_dequeue(req);
1042 req->state = RPC_REQUEST_DONE;
1043 req->status = status;
1044 if (req->async.callback) {
1045 req->async.callback(req);
1049 talloc_set_destructor(conn, NULL);
1050 if (conn->free_skipped) {
1056 forward declarations of the recv_data handlers for the types of
1057 packets we need to handle
1059 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1060 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1063 receive a dcerpc reply from the transport. Here we work out what
1064 type of reply it is (normal request, bind or alter context) and
1065 dispatch to the appropriate handler
1067 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1069 struct ncacn_packet pkt;
1071 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1072 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1075 /* the transport may be telling us of a severe error, such as
1077 if (!NT_STATUS_IS_OK(status)) {
1078 data_blob_free(blob);
1079 dcerpc_connection_dead(conn, status);
1083 /* parse the basic packet to work out what type of response this is */
1084 status = ncacn_pull(conn, blob, blob->data, &pkt);
1085 if (!NT_STATUS_IS_OK(status)) {
1086 data_blob_free(blob);
1087 dcerpc_connection_dead(conn, status);
1091 dcerpc_request_recv_data(conn, blob, &pkt);
1095 handle timeouts of individual dcerpc requests
1097 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1098 struct timeval t, void *private_data)
1100 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1102 if (req->ignore_timeout) {
1103 dcerpc_req_dequeue(req);
1104 req->state = RPC_REQUEST_DONE;
1105 req->status = NT_STATUS_IO_TIMEOUT;
1106 if (req->async.callback) {
1107 req->async.callback(req);
1112 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1115 struct dcerpc_bind_state {
1116 struct tevent_context *ev;
1117 struct dcerpc_pipe *p;
1120 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1121 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1122 DATA_BLOB *raw_packet,
1123 struct ncacn_packet *pkt);
1125 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1126 struct tevent_context *ev,
1127 struct dcerpc_pipe *p,
1128 const struct ndr_syntax_id *syntax,
1129 const struct ndr_syntax_id *transfer_syntax)
1131 struct tevent_req *req;
1132 struct dcerpc_bind_state *state;
1133 struct ncacn_packet pkt;
1136 struct rpc_request *subreq;
1138 req = tevent_req_create(mem_ctx, &state,
1139 struct dcerpc_bind_state);
1147 p->syntax = *syntax;
1148 p->transfer_syntax = *transfer_syntax;
1150 init_ncacn_hdr(p->conn, &pkt);
1152 pkt.ptype = DCERPC_PKT_BIND;
1153 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1154 pkt.call_id = p->conn->call_id;
1155 pkt.auth_length = 0;
1157 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1158 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1161 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1162 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1165 pkt.u.bind.max_xmit_frag = 5840;
1166 pkt.u.bind.max_recv_frag = 5840;
1167 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1168 pkt.u.bind.num_contexts = 1;
1169 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1170 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1171 return tevent_req_post(req, ev);
1173 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1174 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1175 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1176 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1177 pkt.u.bind.auth_info = data_blob(NULL, 0);
1179 /* construct the NDR form of the packet */
1180 status = ncacn_push_auth(&blob, state, &pkt,
1181 p->conn->security_state.auth_info);
1182 if (tevent_req_nterror(req, status)) {
1183 return tevent_req_post(req, ev);
1186 p->conn->transport.recv_data = dcerpc_recv_data;
1189 * we allocate a dcerpc_request so we can be in the same
1190 * request queue as normal requests
1192 subreq = talloc_zero(state, struct rpc_request);
1193 if (tevent_req_nomem(subreq, req)) {
1194 return tevent_req_post(req, ev);
1197 subreq->state = RPC_REQUEST_PENDING;
1198 subreq->call_id = pkt.call_id;
1199 subreq->async.private_data = req;
1200 subreq->async.callback = dcerpc_bind_fail_handler;
1202 subreq->recv_handler = dcerpc_bind_recv_handler;
1203 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1204 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1206 status = p->conn->transport.send_request(p->conn, &blob, true);
1207 if (tevent_req_nterror(req, status)) {
1208 return tevent_req_post(req, ev);
1211 tevent_add_timer(ev, subreq,
1212 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1213 dcerpc_timeout_handler, subreq);
1218 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1220 struct tevent_req *req =
1221 talloc_get_type_abort(subreq->async.private_data,
1223 struct dcerpc_bind_state *state =
1224 tevent_req_data(req,
1225 struct dcerpc_bind_state);
1226 NTSTATUS status = subreq->status;
1228 TALLOC_FREE(subreq);
1231 * We trigger the callback in the next event run
1232 * because the code in this file might trigger
1233 * multiple request callbacks from within a single
1236 * In order to avoid segfaults from within
1237 * dcerpc_connection_dead() we call
1238 * tevent_req_defer_callback().
1240 tevent_req_defer_callback(req, state->ev);
1242 tevent_req_nterror(req, status);
1245 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1246 DATA_BLOB *raw_packet,
1247 struct ncacn_packet *pkt)
1249 struct tevent_req *req =
1250 talloc_get_type_abort(subreq->async.private_data,
1252 struct dcerpc_bind_state *state =
1253 tevent_req_data(req,
1254 struct dcerpc_bind_state);
1255 struct dcecli_connection *conn = state->p->conn;
1259 * Note that pkt is allocated under raw_packet->data,
1260 * while raw_packet->data is a child of subreq.
1262 talloc_steal(state, raw_packet->data);
1263 TALLOC_FREE(subreq);
1266 * We trigger the callback in the next event run
1267 * because the code in this file might trigger
1268 * multiple request callbacks from within a single
1271 * In order to avoid segfaults from within
1272 * dcerpc_connection_dead() we call
1273 * tevent_req_defer_callback().
1275 tevent_req_defer_callback(req, state->ev);
1277 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1278 status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason);
1280 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1281 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1283 tevent_req_nterror(req, status);
1287 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1288 (pkt->u.bind_ack.num_results == 0) ||
1289 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1290 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1291 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1295 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1296 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1298 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1299 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1300 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1303 if ((state->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1304 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1305 conn->flags |= DCERPC_HEADER_SIGNING;
1308 /* the bind_ack might contain a reply set of credentials */
1309 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1310 uint32_t auth_length;
1312 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1313 conn->security_state.auth_info, &auth_length, true);
1314 if (tevent_req_nterror(req, status)) {
1319 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1321 tevent_req_done(req);
1324 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1326 return tevent_req_simple_recv_ntstatus(req);
1330 perform a continued bind (and auth3)
1332 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1333 TALLOC_CTX *mem_ctx)
1335 struct ncacn_packet pkt;
1339 init_ncacn_hdr(p->conn, &pkt);
1341 pkt.ptype = DCERPC_PKT_AUTH3;
1342 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1343 pkt.call_id = next_call_id(p->conn);
1344 pkt.auth_length = 0;
1345 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1347 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1348 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1351 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1352 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1355 /* construct the NDR form of the packet */
1356 status = ncacn_push_auth(&blob, mem_ctx,
1358 p->conn->security_state.auth_info);
1359 if (!NT_STATUS_IS_OK(status)) {
1363 /* send it on its way */
1364 status = p->conn->transport.send_request(p->conn, &blob, false);
1365 if (!NT_STATUS_IS_OK(status)) {
1369 return NT_STATUS_OK;
1374 process a fragment received from the transport layer during a
1377 This function frees the data
1379 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1380 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1382 struct rpc_request *req;
1383 unsigned int length;
1384 NTSTATUS status = NT_STATUS_OK;
1387 if this is an authenticated connection then parse and check
1388 the auth info. We have to do this before finding the
1389 matching packet, as the request structure might have been
1390 removed due to a timeout, but if it has been we still need
1391 to run the auth routines so that we don't get the sign/seal
1392 info out of step with the server
1394 if (c->security_state.auth_info && c->security_state.generic_state &&
1395 pkt->ptype == DCERPC_PKT_RESPONSE) {
1396 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1399 /* find the matching request */
1400 for (req=c->pending;req;req=req->next) {
1401 if (pkt->call_id == req->call_id) break;
1405 /* useful for testing certain vendors RPC servers */
1406 if (req == NULL && c->pending && pkt->call_id == 0) {
1407 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1413 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1414 data_blob_free(raw_packet);
1418 talloc_steal(req, raw_packet->data);
1420 if (req->recv_handler != NULL) {
1421 dcerpc_req_dequeue(req);
1422 req->state = RPC_REQUEST_DONE;
1425 * We have to look at shipping further requests before calling
1426 * the async function, that one might close the pipe
1428 dcerpc_schedule_io_trigger(c);
1430 req->recv_handler(req, raw_packet, pkt);
1434 if (pkt->ptype == DCERPC_PKT_FAULT) {
1435 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1436 req->fault_code = pkt->u.fault.status;
1437 req->status = NT_STATUS_NET_WRITE_FAULT;
1441 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1442 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1444 req->fault_code = DCERPC_FAULT_OTHER;
1445 req->status = NT_STATUS_NET_WRITE_FAULT;
1449 /* now check the status from the auth routines, and if it failed then fail
1450 this request accordingly */
1451 if (!NT_STATUS_IS_OK(status)) {
1452 req->status = status;
1456 length = pkt->u.response.stub_and_verifier.length;
1459 req->payload.data = talloc_realloc(req,
1462 req->payload.length + length);
1463 if (!req->payload.data) {
1464 req->status = NT_STATUS_NO_MEMORY;
1467 memcpy(req->payload.data+req->payload.length,
1468 pkt->u.response.stub_and_verifier.data, length);
1469 req->payload.length += length;
1472 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1473 c->transport.send_read(c);
1477 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1478 req->flags |= DCERPC_PULL_BIGENDIAN;
1480 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1485 /* we've got the full payload */
1486 dcerpc_req_dequeue(req);
1487 req->state = RPC_REQUEST_DONE;
1490 * We have to look at shipping further requests before calling
1491 * the async function, that one might close the pipe
1493 dcerpc_schedule_io_trigger(c);
1495 if (req->async.callback) {
1496 req->async.callback(req);
1501 perform the send side of a async dcerpc request
1503 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1504 struct dcerpc_pipe *p,
1505 const struct GUID *object,
1507 DATA_BLOB *stub_data)
1509 struct rpc_request *req;
1511 p->conn->transport.recv_data = dcerpc_recv_data;
1513 req = talloc_zero(mem_ctx, struct rpc_request);
1519 req->call_id = next_call_id(p->conn);
1520 req->state = RPC_REQUEST_QUEUED;
1522 if (object != NULL) {
1523 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1524 if (req->object == NULL) {
1531 req->request_data.length = stub_data->length;
1532 req->request_data.data = stub_data->data;
1534 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1535 talloc_set_destructor(req, dcerpc_req_dequeue);
1537 dcerpc_schedule_io_trigger(p->conn);
1539 if (p->request_timeout) {
1540 tevent_add_timer(dcerpc_event_context(p), req,
1541 timeval_current_ofs(p->request_timeout, 0),
1542 dcerpc_timeout_handler, req);
1549 Send a request using the transport
1552 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1554 struct rpc_request *req;
1555 struct dcerpc_pipe *p;
1556 DATA_BLOB *stub_data;
1557 struct ncacn_packet pkt;
1559 uint32_t remaining, chunk_size;
1560 bool first_packet = true;
1561 size_t sig_size = 0;
1562 bool need_async = false;
1563 bool can_async = true;
1565 req = c->request_queue;
1571 stub_data = &req->request_data;
1577 if (c->security_state.auth_info &&
1578 c->security_state.generic_state)
1580 struct gensec_security *gensec = c->security_state.generic_state;
1582 switch (c->security_state.auth_info->auth_level) {
1583 case DCERPC_AUTH_LEVEL_PRIVACY:
1584 case DCERPC_AUTH_LEVEL_INTEGRITY:
1585 can_async = gensec_have_feature(gensec,
1586 GENSEC_FEATURE_ASYNC_REPLIES);
1588 case DCERPC_AUTH_LEVEL_CONNECT:
1589 case DCERPC_AUTH_LEVEL_NONE:
1598 if (need_async && !can_async) {
1599 req->wait_for_sync = true;
1603 DLIST_REMOVE(c->request_queue, req);
1604 DLIST_ADD(c->pending, req);
1605 req->state = RPC_REQUEST_PENDING;
1607 init_ncacn_hdr(p->conn, &pkt);
1609 remaining = stub_data->length;
1611 /* we can write a full max_recv_frag size, minus the dcerpc
1612 request header size */
1613 chunk_size = p->conn->srv_max_recv_frag;
1614 chunk_size -= DCERPC_REQUEST_LENGTH;
1615 if (c->security_state.auth_info &&
1616 c->security_state.generic_state) {
1617 sig_size = gensec_sig_size(c->security_state.generic_state,
1618 p->conn->srv_max_recv_frag);
1620 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1621 chunk_size -= sig_size;
1624 chunk_size -= (chunk_size % 16);
1626 pkt.ptype = DCERPC_PKT_REQUEST;
1627 pkt.call_id = req->call_id;
1628 pkt.auth_length = 0;
1630 pkt.u.request.alloc_hint = remaining;
1631 pkt.u.request.context_id = p->context_id;
1632 pkt.u.request.opnum = req->opnum;
1635 pkt.u.request.object.object = *req->object;
1636 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1637 chunk_size -= ndr_size_GUID(req->object,0);
1640 /* we send a series of pdus without waiting for a reply */
1641 while (remaining > 0 || first_packet) {
1642 uint32_t chunk = MIN(chunk_size, remaining);
1643 bool last_frag = false;
1644 bool do_trans = false;
1646 first_packet = false;
1647 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1649 if (remaining == stub_data->length) {
1650 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1652 if (chunk == remaining) {
1653 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1657 pkt.u.request.stub_and_verifier.data = stub_data->data +
1658 (stub_data->length - remaining);
1659 pkt.u.request.stub_and_verifier.length = chunk;
1661 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1662 if (!NT_STATUS_IS_OK(req->status)) {
1663 req->state = RPC_REQUEST_DONE;
1664 DLIST_REMOVE(p->conn->pending, req);
1668 if (last_frag && !need_async) {
1672 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1673 if (!NT_STATUS_IS_OK(req->status)) {
1674 req->state = RPC_REQUEST_DONE;
1675 DLIST_REMOVE(p->conn->pending, req);
1679 if (last_frag && !do_trans) {
1680 req->status = p->conn->transport.send_read(p->conn);
1681 if (!NT_STATUS_IS_OK(req->status)) {
1682 req->state = RPC_REQUEST_DONE;
1683 DLIST_REMOVE(p->conn->pending, req);
1692 static void dcerpc_io_trigger(struct tevent_context *ctx,
1693 struct tevent_immediate *im,
1696 struct dcecli_connection *c =
1697 talloc_get_type_abort(private_data,
1698 struct dcecli_connection);
1700 c->io_trigger_pending = false;
1702 dcerpc_schedule_io_trigger(c);
1704 dcerpc_ship_next_request(c);
1707 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1713 if (c->request_queue == NULL) {
1717 if (c->request_queue->wait_for_sync && c->pending) {
1721 if (c->io_trigger_pending) {
1725 c->io_trigger_pending = true;
1727 tevent_schedule_immediate(c->io_trigger,
1734 return the event context for a dcerpc pipe
1735 used by callers who wish to operate asynchronously
1737 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1739 return p->conn->event_ctx;
1745 perform the receive side of a async dcerpc request
1747 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1748 TALLOC_CTX *mem_ctx,
1749 DATA_BLOB *stub_data)
1753 while (req->state != RPC_REQUEST_DONE) {
1754 struct tevent_context *ctx = dcerpc_event_context(req->p);
1755 if (tevent_loop_once(ctx) != 0) {
1756 return NT_STATUS_CONNECTION_DISCONNECTED;
1759 *stub_data = req->payload;
1760 status = req->status;
1761 if (stub_data->data) {
1762 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1764 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1765 req->p->last_fault_code = req->fault_code;
1767 talloc_unlink(talloc_parent(req), req);
1772 this is a paranoid NDR validator. For every packet we push onto the wire
1773 we pull it back again, then push it again. Then we compare the raw NDR data
1774 for that to the NDR we initially generated. If they don't match then we know
1775 we must have a bug in either the pull or push side of our code
1777 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1778 TALLOC_CTX *mem_ctx,
1781 ndr_push_flags_fn_t ndr_push,
1782 ndr_pull_flags_fn_t ndr_pull)
1785 struct ndr_pull *pull;
1786 struct ndr_push *push;
1788 enum ndr_err_code ndr_err;
1790 st = talloc_size(mem_ctx, struct_size);
1792 return NT_STATUS_NO_MEMORY;
1795 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1797 return NT_STATUS_NO_MEMORY;
1799 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1801 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1802 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1805 if (c->flags & DCERPC_NDR64) {
1806 pull->flags |= LIBNDR_FLAG_NDR64;
1809 ndr_err = ndr_pull(pull, NDR_IN, st);
1810 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1811 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1812 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1813 "failed input validation pull - %s",
1815 return ndr_map_error2ntstatus(ndr_err);
1818 push = ndr_push_init_ctx(mem_ctx);
1820 return NT_STATUS_NO_MEMORY;
1823 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1824 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1827 if (c->flags & DCERPC_NDR64) {
1828 push->flags |= LIBNDR_FLAG_NDR64;
1831 ndr_err = ndr_push(push, NDR_IN, st);
1832 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1833 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1834 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1835 "failed input validation push - %s",
1837 return ndr_map_error2ntstatus(ndr_err);
1840 blob2 = ndr_push_blob(push);
1842 if (data_blob_cmp(&blob, &blob2) != 0) {
1843 DEBUG(3,("original:\n"));
1844 dump_data(3, blob.data, blob.length);
1845 DEBUG(3,("secondary:\n"));
1846 dump_data(3, blob2.data, blob2.length);
1847 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1848 "failed input validation blobs doesn't match");
1849 return ndr_map_error2ntstatus(ndr_err);
1852 return NT_STATUS_OK;
1856 this is a paranoid NDR input validator. For every packet we pull
1857 from the wire we push it back again then pull and push it
1858 again. Then we compare the raw NDR data for that to the NDR we
1859 initially generated. If they don't match then we know we must have a
1860 bug in either the pull or push side of our code
1862 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1863 struct ndr_pull *pull_in,
1866 ndr_push_flags_fn_t ndr_push,
1867 ndr_pull_flags_fn_t ndr_pull,
1868 ndr_print_function_t ndr_print)
1871 struct ndr_pull *pull;
1872 struct ndr_push *push;
1873 DATA_BLOB blob, blob2;
1874 TALLOC_CTX *mem_ctx = pull_in;
1876 enum ndr_err_code ndr_err;
1878 st = talloc_size(mem_ctx, struct_size);
1880 return NT_STATUS_NO_MEMORY;
1882 memcpy(st, struct_ptr, struct_size);
1884 push = ndr_push_init_ctx(mem_ctx);
1886 return NT_STATUS_NO_MEMORY;
1889 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1890 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1891 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1892 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1893 "failed output validation push - %s",
1895 return ndr_map_error2ntstatus(ndr_err);
1898 blob = ndr_push_blob(push);
1900 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1902 return NT_STATUS_NO_MEMORY;
1905 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1906 ndr_err = ndr_pull(pull, NDR_OUT, st);
1907 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1908 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1909 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1910 "failed output validation pull - %s",
1912 return ndr_map_error2ntstatus(ndr_err);
1915 push = ndr_push_init_ctx(mem_ctx);
1917 return NT_STATUS_NO_MEMORY;
1920 ndr_err = ndr_push(push, NDR_OUT, st);
1921 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1922 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1923 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1924 "failed output validation push2 - %s",
1926 return ndr_map_error2ntstatus(ndr_err);
1929 blob2 = ndr_push_blob(push);
1931 if (data_blob_cmp(&blob, &blob2) != 0) {
1932 DEBUG(3,("original:\n"));
1933 dump_data(3, blob.data, blob.length);
1934 DEBUG(3,("secondary:\n"));
1935 dump_data(3, blob2.data, blob2.length);
1936 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1937 "failed output validation blobs doesn't match");
1938 return ndr_map_error2ntstatus(ndr_err);
1941 /* this checks the printed forms of the two structures, which effectively
1942 tests all of the value() attributes */
1943 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1944 NDR_OUT, struct_ptr);
1945 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1947 if (strcmp(s1, s2) != 0) {
1949 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1951 /* this is sometimes useful */
1952 printf("VALIDATE ERROR\n");
1953 file_save("wire.dat", s1, strlen(s1));
1954 file_save("gen.dat", s2, strlen(s2));
1955 system("diff -u wire.dat gen.dat");
1957 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1958 "failed output validation strings doesn't match");
1959 return ndr_map_error2ntstatus(ndr_err);
1962 return NT_STATUS_OK;
1966 a useful function for retrieving the server name we connected to
1968 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1970 if (!p->conn->transport.target_hostname) {
1971 if (!p->conn->transport.peer_name) {
1974 return p->conn->transport.peer_name(p->conn);
1976 return p->conn->transport.target_hostname(p->conn);
1981 get the dcerpc auth_level for a open connection
1983 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1987 if (c->flags & DCERPC_SEAL) {
1988 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1989 } else if (c->flags & DCERPC_SIGN) {
1990 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1991 } else if (c->flags & DCERPC_CONNECT) {
1992 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1994 auth_level = DCERPC_AUTH_LEVEL_NONE;
1999 struct dcerpc_alter_context_state {
2000 struct tevent_context *ev;
2001 struct dcerpc_pipe *p;
2004 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2005 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2006 DATA_BLOB *raw_packet,
2007 struct ncacn_packet *pkt);
2009 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2010 struct tevent_context *ev,
2011 struct dcerpc_pipe *p,
2012 const struct ndr_syntax_id *syntax,
2013 const struct ndr_syntax_id *transfer_syntax)
2015 struct tevent_req *req;
2016 struct dcerpc_alter_context_state *state;
2017 struct ncacn_packet pkt;
2020 struct rpc_request *subreq;
2022 req = tevent_req_create(mem_ctx, &state,
2023 struct dcerpc_alter_context_state);
2031 p->syntax = *syntax;
2032 p->transfer_syntax = *transfer_syntax;
2034 init_ncacn_hdr(p->conn, &pkt);
2036 pkt.ptype = DCERPC_PKT_ALTER;
2037 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2038 pkt.call_id = p->conn->call_id;
2039 pkt.auth_length = 0;
2041 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
2042 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2045 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
2046 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
2049 pkt.u.alter.max_xmit_frag = 5840;
2050 pkt.u.alter.max_recv_frag = 5840;
2051 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
2052 pkt.u.alter.num_contexts = 1;
2053 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2054 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2055 return tevent_req_post(req, ev);
2057 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2058 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2059 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2060 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2061 pkt.u.alter.auth_info = data_blob(NULL, 0);
2063 /* construct the NDR form of the packet */
2064 status = ncacn_push_auth(&blob, state, &pkt,
2065 p->conn->security_state.auth_info);
2066 if (tevent_req_nterror(req, status)) {
2067 return tevent_req_post(req, ev);
2070 p->conn->transport.recv_data = dcerpc_recv_data;
2073 * we allocate a dcerpc_request so we can be in the same
2074 * request queue as normal requests
2076 subreq = talloc_zero(state, struct rpc_request);
2077 if (tevent_req_nomem(subreq, req)) {
2078 return tevent_req_post(req, ev);
2081 subreq->state = RPC_REQUEST_PENDING;
2082 subreq->call_id = pkt.call_id;
2083 subreq->async.private_data = req;
2084 subreq->async.callback = dcerpc_alter_context_fail_handler;
2086 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2087 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2088 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2090 status = p->conn->transport.send_request(p->conn, &blob, true);
2091 if (tevent_req_nterror(req, status)) {
2092 return tevent_req_post(req, ev);
2095 tevent_add_timer(ev, subreq,
2096 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2097 dcerpc_timeout_handler, subreq);
2102 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2104 struct tevent_req *req =
2105 talloc_get_type_abort(subreq->async.private_data,
2107 struct dcerpc_alter_context_state *state =
2108 tevent_req_data(req,
2109 struct dcerpc_alter_context_state);
2110 NTSTATUS status = subreq->status;
2112 TALLOC_FREE(subreq);
2115 * We trigger the callback in the next event run
2116 * because the code in this file might trigger
2117 * multiple request callbacks from within a single
2120 * In order to avoid segfaults from within
2121 * dcerpc_connection_dead() we call
2122 * tevent_req_defer_callback().
2124 tevent_req_defer_callback(req, state->ev);
2126 tevent_req_nterror(req, status);
2129 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2130 DATA_BLOB *raw_packet,
2131 struct ncacn_packet *pkt)
2133 struct tevent_req *req =
2134 talloc_get_type_abort(subreq->async.private_data,
2136 struct dcerpc_alter_context_state *state =
2137 tevent_req_data(req,
2138 struct dcerpc_alter_context_state);
2139 struct dcecli_connection *conn = state->p->conn;
2143 * Note that pkt is allocated under raw_packet->data,
2144 * while raw_packet->data is a child of subreq.
2146 talloc_steal(state, raw_packet->data);
2147 TALLOC_FREE(subreq);
2150 * We trigger the callback in the next event run
2151 * because the code in this file might trigger
2152 * multiple request callbacks from within a single
2155 * In order to avoid segfaults from within
2156 * dcerpc_connection_dead() we call
2157 * tevent_req_defer_callback().
2159 tevent_req_defer_callback(req, state->ev);
2161 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2162 pkt->u.alter_resp.num_results == 1 &&
2163 pkt->u.alter_resp.ctx_list[0].result != 0) {
2164 status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason);
2165 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2166 pkt->u.alter_resp.ctx_list[0].reason,
2167 nt_errstr(status)));
2168 tevent_req_nterror(req, status);
2172 if (pkt->ptype == DCERPC_PKT_FAULT) {
2173 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2174 dcerpc_errstr(state, pkt->u.fault.status)));
2175 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2176 state->p->last_fault_code = pkt->u.fault.status;
2177 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2179 state->p->last_fault_code = pkt->u.fault.status;
2180 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2185 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2186 pkt->u.alter_resp.num_results == 0 ||
2187 pkt->u.alter_resp.ctx_list[0].result != 0) {
2188 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2189 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2193 /* the alter_resp might contain a reply set of credentials */
2194 if (conn->security_state.auth_info &&
2195 pkt->u.alter_resp.auth_info.length) {
2196 uint32_t auth_length;
2198 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2199 conn->security_state.auth_info, &auth_length, true);
2200 if (tevent_req_nterror(req, status)) {
2205 tevent_req_done(req);
2208 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2210 return tevent_req_simple_recv_ntstatus(req);
2214 send a dcerpc alter_context request
2216 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2217 TALLOC_CTX *mem_ctx,
2218 const struct ndr_syntax_id *syntax,
2219 const struct ndr_syntax_id *transfer_syntax)
2221 struct tevent_req *subreq;
2222 struct tevent_context *ev = p->conn->event_ctx;
2225 /* TODO: create a new event context here */
2227 subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx,
2228 p, syntax, transfer_syntax);
2229 if (subreq == NULL) {
2230 return NT_STATUS_NO_MEMORY;
2233 ok = tevent_req_poll(subreq, ev);
2236 status = map_nt_error_from_unix_common(errno);
2240 return dcerpc_alter_context_recv(subreq);