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 "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.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"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
39 enum rpc_request_state {
46 handle for an async dcerpc request
49 struct rpc_request *next, *prev;
50 struct dcerpc_pipe *p;
53 enum rpc_request_state state;
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler)(struct rpc_request *conn,
61 DATA_BLOB *blob, struct ncacn_packet *pkt);
63 const struct GUID *object;
65 DATA_BLOB request_data;
66 bool request_data_can_append;
67 struct tevent_req *stub_subreq;
73 bool incomplete_request_data;
74 bool incomplete_payload;
78 void (*callback)(struct rpc_request *);
83 _PUBLIC_ NTSTATUS dcerpc_init(void)
88 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
89 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
91 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
92 struct dcerpc_pipe *p,
93 const struct GUID *object,
95 DATA_BLOB *stub_data);
96 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
98 DATA_BLOB *stub_data);
99 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
103 ndr_push_flags_fn_t ndr_push,
104 ndr_pull_flags_fn_t ndr_pull);
105 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
106 struct ndr_pull *pull_in,
109 ndr_push_flags_fn_t ndr_push,
110 ndr_pull_flags_fn_t ndr_pull,
111 ndr_print_function_t ndr_print);
112 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
113 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
115 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
117 /* destroy a dcerpc connection */
118 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
121 conn->free_skipped = true;
124 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
129 /* initialise a dcerpc connection.
130 the event context is optional
132 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
133 struct tevent_context *ev)
135 struct dcecli_connection *c;
137 c = talloc_zero(mem_ctx, struct dcecli_connection);
144 if (c->event_ctx == NULL) {
150 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
151 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
152 c->security_state.auth_context_id = 0;
153 c->security_state.session_key = dcerpc_generic_session_key;
154 c->security_state.generic_state = NULL;
157 * Windows uses 5840 for ncacn_ip_tcp,
158 * so we also use it (for every transport)
159 * by default. But we give the transport
160 * the chance to overwrite it.
162 c->srv_max_xmit_frag = 5840;
163 c->srv_max_recv_frag = 5840;
164 c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
167 c->io_trigger = tevent_create_immediate(c);
168 if (c->io_trigger == NULL) {
173 talloc_set_destructor(c, dcerpc_connection_destructor);
178 struct dcerpc_bh_state {
179 struct dcerpc_pipe *p;
182 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
184 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
185 struct dcerpc_bh_state);
195 if (hs->p->conn->dead) {
202 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
205 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
206 struct dcerpc_bh_state);
210 return DCERPC_REQUEST_TIMEOUT;
213 old = hs->p->request_timeout;
214 hs->p->request_timeout = timeout;
219 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
220 enum dcerpc_AuthType *auth_type,
221 enum dcerpc_AuthLevel *auth_level)
223 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
224 struct dcerpc_bh_state);
230 if (hs->p->conn == NULL) {
234 *auth_type = hs->p->conn->security_state.auth_type;
235 *auth_level = hs->p->conn->security_state.auth_level;
238 struct dcerpc_bh_raw_call_state {
239 struct tevent_context *ev;
240 struct dcerpc_binding_handle *h;
245 struct rpc_request *subreq;
248 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
250 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
251 struct tevent_context *ev,
252 struct dcerpc_binding_handle *h,
253 const struct GUID *object,
256 const uint8_t *in_data,
259 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
260 struct dcerpc_bh_state);
261 struct tevent_req *req;
262 struct dcerpc_bh_raw_call_state *state;
265 req = tevent_req_create(mem_ctx, &state,
266 struct dcerpc_bh_raw_call_state);
272 state->in_flags = in_flags;
273 state->in_data.data = discard_const_p(uint8_t, in_data);
274 state->in_data.length = in_length;
276 ok = dcerpc_bh_is_connected(h);
278 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
279 return tevent_req_post(req, ev);
282 state->subreq = dcerpc_request_send(state,
287 if (tevent_req_nomem(state->subreq, req)) {
288 return tevent_req_post(req, ev);
290 state->subreq->async.callback = dcerpc_bh_raw_call_done;
291 state->subreq->async.private_data = req;
293 if (state->in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
294 state->subreq->incomplete_request_data = true;
295 state->subreq->incomplete_payload = true;
301 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
303 struct tevent_req *req =
304 talloc_get_type_abort(subreq->async.private_data,
306 struct dcerpc_bh_raw_call_state *state =
308 struct dcerpc_bh_raw_call_state);
312 state->out_flags = 0;
313 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
314 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
317 if (subreq->state == RPC_REQUEST_PENDING) {
318 state->out_flags |= LIBNDR_FLAG_INCOMPLETE_BUFFER;
320 state->subreq = NULL;
321 state->out_flags &= ~LIBNDR_FLAG_INCOMPLETE_BUFFER;
324 fault_code = subreq->fault_code;
326 status = dcerpc_request_recv(subreq, state, &state->out_data);
327 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
328 status = dcerpc_fault_to_nt_status(fault_code);
332 * We trigger the callback in the next event run
333 * because the code in this file might trigger
334 * multiple request callbacks from within a single
337 * In order to avoid segfaults from within
338 * dcerpc_connection_dead() we call
339 * tevent_req_defer_callback().
341 tevent_req_defer_callback(req, state->ev);
343 if (!NT_STATUS_IS_OK(status)) {
344 tevent_req_nterror(req, status);
348 if (state->out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
349 tevent_req_notify_callback(req);
353 tevent_req_done(req);
356 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
362 struct dcerpc_bh_raw_call_state *state =
364 struct dcerpc_bh_raw_call_state);
365 NTSTATUS status = NT_STATUS_OK;
367 if (!tevent_req_is_in_progress(req)) {
368 if (tevent_req_is_nterror(req, &status)) {
369 tevent_req_received(req);
374 *out_data = talloc_move(mem_ctx, &state->out_data.data);
375 *out_length = state->out_data.length;
376 *out_flags = state->out_flags;
377 if (!(state->out_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
378 tevent_req_received(req);
383 struct dcerpc_bh_raw_call_in_state {
387 static struct tevent_req *dcerpc_bh_raw_call_in_send(TALLOC_CTX *mem_ctx,
388 struct tevent_context *ev,
389 struct tevent_req *raw_call_req,
391 const uint8_t *in_data,
394 struct dcerpc_bh_raw_call_state *raw_call_state = NULL;
395 struct tevent_req *req;
396 struct dcerpc_bh_raw_call_in_state *state;
397 struct rpc_request *rpcreq = NULL;
401 req = tevent_req_create(mem_ctx, &state,
402 struct dcerpc_bh_raw_call_in_state);
407 if (!tevent_req_is_in_progress(raw_call_req)) {
408 tevent_req_nterror(req, NT_STATUS_RPC_CALL_FAILED);
409 return tevent_req_post(req, ev);
412 raw_call_state = tevent_req_data(raw_call_req,
413 struct dcerpc_bh_raw_call_state);
415 if (raw_call_state->subreq == NULL) {
416 tevent_req_nterror(req, NT_STATUS_RPC_CALL_FAILED);
417 return tevent_req_post(req, ev);
420 rpcreq = raw_call_state->subreq;
422 if (rpcreq->state != RPC_REQUEST_QUEUED) {
423 tevent_req_nterror(req, NT_STATUS_RPC_INVALID_PIPE_OPERATION);
424 return tevent_req_post(req, ev);
427 if (!(in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER)) {
428 rpcreq->incomplete_request_data = false;
431 b = &rpcreq->request_data;
433 if (in_length == 0) {
434 if (in_flags & LIBNDR_FLAG_INCOMPLETE_BUFFER) {
436 * with LIBNDR_FLAG_INCOMPLETE_BUFFER
437 * we need to make sure we make any progress...
439 tevent_req_nterror(req, NT_STATUS_RPC_INVALID_PIPE_OPERATION);
440 return tevent_req_post(req, ev);
446 } else if (rpcreq->request_data_can_append) {
447 ok = data_blob_append(rpcreq, b, in_data, in_length);
449 tevent_req_nomem(NULL, req);
450 return tevent_req_post(req, ev);
453 *b = data_blob_talloc(rpcreq, b->data, b->length);
454 if (tevent_req_nomem(b->data, req)) {
455 return tevent_req_post(req, ev);
457 rpcreq->request_data_can_append = true;
458 ok = data_blob_append(rpcreq, b, in_data, in_length);
460 tevent_req_nomem(NULL, req);
461 return tevent_req_post(req, ev);
465 dcerpc_schedule_io_trigger(rpcreq->p->conn);
467 if (b->length > (rpcreq->p->conn->srv_max_xmit_frag * 10)) {
468 rpcreq->stub_subreq = req;
473 tevent_req_done(req);
474 return tevent_req_post(req, ev);
477 static NTSTATUS dcerpc_bh_raw_call_in_recv(struct tevent_req *req)
479 return tevent_req_simple_recv_ntstatus(req);
482 struct dcerpc_bh_disconnect_state {
486 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
487 struct tevent_context *ev,
488 struct dcerpc_binding_handle *h)
490 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
491 struct dcerpc_bh_state);
492 struct tevent_req *req;
493 struct dcerpc_bh_disconnect_state *state;
496 req = tevent_req_create(mem_ctx, &state,
497 struct dcerpc_bh_disconnect_state);
502 ok = dcerpc_bh_is_connected(h);
504 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
505 return tevent_req_post(req, ev);
508 /* TODO: do a real disconnect ... */
511 tevent_req_done(req);
512 return tevent_req_post(req, ev);
515 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
519 if (tevent_req_is_nterror(req, &status)) {
520 tevent_req_received(req);
524 tevent_req_received(req);
528 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
530 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
531 struct dcerpc_bh_state);
533 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
540 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
542 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
543 struct dcerpc_bh_state);
545 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
552 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
554 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
555 struct dcerpc_bh_state);
557 if (hs->p->conn->flags & DCERPC_NDR64) {
564 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
566 const void *_struct_ptr,
567 const struct ndr_interface_call *call)
569 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
570 struct dcerpc_bh_state);
571 void *struct_ptr = discard_const(_struct_ptr);
572 bool print_in = false;
573 bool print_out = false;
575 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
579 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
583 if (DEBUGLEVEL >= 11) {
588 if (ndr_flags & NDR_IN) {
590 ndr_print_function_debug(call->ndr_print,
596 if (ndr_flags & NDR_OUT) {
598 ndr_print_function_debug(call->ndr_print,
606 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
608 const void *struct_ptr,
609 const struct ndr_interface_call *call)
611 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
612 call->name, nt_errstr(error)));
615 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
617 const DATA_BLOB *blob,
618 const struct ndr_interface_call *call)
620 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
621 struct dcerpc_bh_state);
622 const uint32_t num_examples = 20;
625 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
626 call->name, nt_errstr(error)));
628 if (hs->p->conn->packet_log_dir == NULL) return;
630 for (i=0;i<num_examples;i++) {
634 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
635 hs->p->conn->packet_log_dir,
640 if (!file_exist(name)) {
641 if (file_save(name, blob->data, blob->length)) {
642 DEBUG(10,("Logged rpc packet to %s\n", name));
651 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
653 const DATA_BLOB *blob,
654 const struct ndr_interface_call *call)
656 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
657 struct dcerpc_bh_state);
659 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
662 status = dcerpc_ndr_validate_in(hs->p->conn,
668 if (!NT_STATUS_IS_OK(status)) {
669 DEBUG(0,("Validation [in] failed for %s - %s\n",
670 call->name, nt_errstr(status)));
675 DEBUG(10,("rpc request data:\n"));
676 dump_data(10, blob->data, blob->length);
681 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
682 struct ndr_pull *pull_in,
683 const void *_struct_ptr,
684 const struct ndr_interface_call *call)
686 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
687 struct dcerpc_bh_state);
688 void *struct_ptr = discard_const(_struct_ptr);
690 DEBUG(10,("rpc reply data:\n"));
691 dump_data(10, pull_in->data, pull_in->data_size);
693 if (pull_in->offset != pull_in->data_size) {
694 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
695 pull_in->data_size - pull_in->offset,
696 pull_in->offset, pull_in->offset,
698 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
699 but it turns out that early versions of NT
700 (specifically NT3.1) add junk onto the end of rpc
701 packets, so if we want to interoperate at all with
702 those versions then we need to ignore this error */
705 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
708 status = dcerpc_ndr_validate_out(hs->p->conn,
715 if (!NT_STATUS_IS_OK(status)) {
716 DEBUG(2,("Validation [out] failed for %s - %s\n",
717 call->name, nt_errstr(status)));
725 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
727 .is_connected = dcerpc_bh_is_connected,
728 .set_timeout = dcerpc_bh_set_timeout,
729 .auth_info = dcerpc_bh_auth_info,
730 .raw_call_send = dcerpc_bh_raw_call_send,
731 .raw_call_recv = dcerpc_bh_raw_call_recv,
732 .raw_call_in_send = dcerpc_bh_raw_call_in_send,
733 .raw_call_in_recv = dcerpc_bh_raw_call_in_recv,
734 .disconnect_send = dcerpc_bh_disconnect_send,
735 .disconnect_recv = dcerpc_bh_disconnect_recv,
737 .push_bigendian = dcerpc_bh_push_bigendian,
738 .ref_alloc = dcerpc_bh_ref_alloc,
739 .use_ndr64 = dcerpc_bh_use_ndr64,
740 .do_ndr_print = dcerpc_bh_do_ndr_print,
741 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
742 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
743 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
744 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
747 /* initialise a dcerpc pipe. */
748 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p,
749 const struct GUID *object,
750 const struct ndr_interface_table *table)
752 struct dcerpc_binding_handle *h;
753 struct dcerpc_bh_state *hs;
755 h = dcerpc_binding_handle_create(p,
760 struct dcerpc_bh_state,
767 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
772 /* initialise a dcerpc pipe. */
773 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
775 struct dcerpc_pipe *p;
777 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
782 p->conn = dcerpc_connection_init(p, ev);
783 if (p->conn == NULL) {
788 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
791 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
799 choose the next call id to use
801 static uint32_t next_call_id(struct dcecli_connection *c)
804 if (c->call_id == 0) {
811 setup for a ndr pull, also setting up any flags from the binding string
813 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
814 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
816 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
818 if (ndr == NULL) return ndr;
820 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
821 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
824 if (c->flags & DCERPC_NDR_REF_ALLOC) {
825 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
828 if (c->flags & DCERPC_NDR64) {
829 ndr->flags |= LIBNDR_FLAG_NDR64;
836 parse the authentication information on a dcerpc response packet
838 static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
840 enum dcerpc_pkt_type ptype,
841 uint8_t required_flags,
842 uint8_t optional_flags,
843 uint8_t payload_offset,
844 DATA_BLOB *payload_and_verifier,
845 DATA_BLOB *raw_packet,
846 const struct ncacn_packet *pkt)
848 const struct dcerpc_auth tmp_auth = {
849 .auth_type = c->security_state.auth_type,
850 .auth_level = c->security_state.auth_level,
851 .auth_context_id = c->security_state.auth_context_id,
855 status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
856 c->security_state.generic_state,
862 payload_and_verifier,
865 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
866 return NT_STATUS_INVALID_NETWORK_RESPONSE;
868 if (!NT_STATUS_IS_OK(status)) {
877 push a dcerpc request packet into a blob, possibly signing it.
879 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
880 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
882 struct ncacn_packet *pkt)
884 const struct dcerpc_auth tmp_auth = {
885 .auth_type = c->security_state.auth_type,
886 .auth_level = c->security_state.auth_level,
887 .auth_context_id = c->security_state.auth_context_id,
890 uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
892 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
893 payload_offset += 16;
896 status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
897 c->security_state.generic_state,
901 &pkt->u.request.stub_and_verifier,
903 if (!NT_STATUS_IS_OK(status)) {
912 fill in the fixed values in a dcerpc header
914 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
917 pkt->rpc_vers_minor = 0;
918 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
921 pkt->drep[0] = DCERPC_DREP_LE;
929 map a bind nak reason to a NTSTATUS
931 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
934 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
935 return NT_STATUS_REVISION_MISMATCH;
936 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
937 return NT_STATUS_INVALID_PARAMETER;
941 return NT_STATUS_UNSUCCESSFUL;
944 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
947 return NT_STATUS_RPC_PROTOCOL_ERROR;
950 switch (ack->result) {
951 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
953 * We have not asked for this...
955 return NT_STATUS_RPC_PROTOCOL_ERROR;
960 switch (ack->reason.value) {
961 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
962 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
963 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
964 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
968 return NT_STATUS_UNSUCCESSFUL;
972 remove requests from the pending or queued queues
974 static int dcerpc_req_dequeue(struct rpc_request *req)
976 switch (req->state) {
977 case RPC_REQUEST_QUEUED:
978 DLIST_REMOVE(req->p->conn->request_queue, req);
980 case RPC_REQUEST_PENDING:
981 DLIST_REMOVE(req->p->conn->pending, req);
983 case RPC_REQUEST_DONE:
991 mark the dcerpc connection dead. All outstanding requests get an error
993 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
995 if (conn->dead) return;
999 TALLOC_FREE(conn->io_trigger);
1000 conn->io_trigger_pending = false;
1002 dcerpc_shutdown_pipe(conn, status);
1004 /* all pending requests get the error */
1005 while (conn->pending) {
1006 struct rpc_request *req = conn->pending;
1007 dcerpc_req_dequeue(req);
1008 req->state = RPC_REQUEST_DONE;
1009 req->status = status;
1010 if (req->async.callback) {
1011 req->async.callback(req);
1015 /* all requests, which are not shipped */
1016 while (conn->request_queue) {
1017 struct rpc_request *req = conn->request_queue;
1018 dcerpc_req_dequeue(req);
1019 req->state = RPC_REQUEST_DONE;
1020 req->status = status;
1021 if (req->async.callback) {
1022 req->async.callback(req);
1026 talloc_set_destructor(conn, NULL);
1027 if (conn->free_skipped) {
1033 forward declarations of the recv_data handlers for the types of
1034 packets we need to handle
1036 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1037 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1040 receive a dcerpc reply from the transport. Here we work out what
1041 type of reply it is (normal request, bind or alter context) and
1042 dispatch to the appropriate handler
1044 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1046 struct ncacn_packet pkt;
1052 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1053 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1056 /* the transport may be telling us of a severe error, such as
1058 if (!NT_STATUS_IS_OK(status)) {
1059 data_blob_free(blob);
1060 dcerpc_connection_dead(conn, status);
1064 /* parse the basic packet to work out what type of response this is */
1065 status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
1066 if (!NT_STATUS_IS_OK(status)) {
1067 data_blob_free(blob);
1068 dcerpc_connection_dead(conn, status);
1072 dcerpc_request_recv_data(conn, blob, &pkt);
1076 handle timeouts of individual dcerpc requests
1078 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1079 struct timeval t, void *private_data)
1081 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1083 if (req->ignore_timeout) {
1084 dcerpc_req_dequeue(req);
1085 req->state = RPC_REQUEST_DONE;
1086 req->status = NT_STATUS_IO_TIMEOUT;
1087 if (req->async.callback) {
1088 req->async.callback(req);
1093 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1096 struct dcerpc_bind_state {
1097 struct tevent_context *ev;
1098 struct dcerpc_pipe *p;
1101 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1102 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1103 DATA_BLOB *raw_packet,
1104 struct ncacn_packet *pkt);
1106 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1107 struct tevent_context *ev,
1108 struct dcerpc_pipe *p,
1109 const struct ndr_syntax_id *syntax,
1110 const struct ndr_syntax_id *transfer_syntax)
1112 struct tevent_req *req;
1113 struct dcerpc_bind_state *state;
1114 struct ncacn_packet pkt;
1117 struct rpc_request *subreq;
1119 struct ndr_syntax_id bind_time_features;
1121 bind_time_features = dcerpc_construct_bind_time_features(
1122 DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
1123 DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
1125 req = tevent_req_create(mem_ctx, &state,
1126 struct dcerpc_bind_state);
1134 p->syntax = *syntax;
1135 p->transfer_syntax = *transfer_syntax;
1137 flags = dcerpc_binding_get_flags(p->binding);
1139 init_ncacn_hdr(p->conn, &pkt);
1141 pkt.ptype = DCERPC_PKT_BIND;
1142 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1143 pkt.call_id = p->conn->call_id;
1144 pkt.auth_length = 0;
1146 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1147 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1150 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1151 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1154 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1155 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1156 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1157 pkt.u.bind.num_contexts = 2;
1158 pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
1159 pkt.u.bind.num_contexts);
1160 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1161 return tevent_req_post(req, ev);
1163 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1164 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1165 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1166 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1167 pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
1168 pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
1169 pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
1170 pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
1171 pkt.u.bind.auth_info = data_blob(NULL, 0);
1173 /* construct the NDR form of the packet */
1174 status = ncacn_push_auth(&blob, state, &pkt,
1175 p->conn->security_state.tmp_auth_info.out);
1176 if (tevent_req_nterror(req, status)) {
1177 return tevent_req_post(req, ev);
1181 * we allocate a dcerpc_request so we can be in the same
1182 * request queue as normal requests
1184 subreq = talloc_zero(state, struct rpc_request);
1185 if (tevent_req_nomem(subreq, req)) {
1186 return tevent_req_post(req, ev);
1189 subreq->state = RPC_REQUEST_PENDING;
1190 subreq->call_id = pkt.call_id;
1191 subreq->async.private_data = req;
1192 subreq->async.callback = dcerpc_bind_fail_handler;
1194 subreq->recv_handler = dcerpc_bind_recv_handler;
1195 DLIST_ADD_END(p->conn->pending, subreq);
1196 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1198 status = dcerpc_send_request(p->conn, &blob, true);
1199 if (tevent_req_nterror(req, status)) {
1200 return tevent_req_post(req, ev);
1203 tevent_add_timer(ev, subreq,
1204 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1205 dcerpc_timeout_handler, subreq);
1210 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1212 struct tevent_req *req =
1213 talloc_get_type_abort(subreq->async.private_data,
1215 struct dcerpc_bind_state *state =
1216 tevent_req_data(req,
1217 struct dcerpc_bind_state);
1218 NTSTATUS status = subreq->status;
1220 TALLOC_FREE(subreq);
1223 * We trigger the callback in the next event run
1224 * because the code in this file might trigger
1225 * multiple request callbacks from within a single
1228 * In order to avoid segfaults from within
1229 * dcerpc_connection_dead() we call
1230 * tevent_req_defer_callback().
1232 tevent_req_defer_callback(req, state->ev);
1234 tevent_req_nterror(req, status);
1237 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1238 DATA_BLOB *raw_packet,
1239 struct ncacn_packet *pkt)
1241 struct tevent_req *req =
1242 talloc_get_type_abort(subreq->async.private_data,
1244 struct dcerpc_bind_state *state =
1245 tevent_req_data(req,
1246 struct dcerpc_bind_state);
1247 struct dcecli_connection *conn = state->p->conn;
1248 struct dcecli_security *sec = &conn->security_state;
1249 struct dcerpc_binding *b = NULL;
1254 * Note that pkt is allocated under raw_packet->data,
1255 * while raw_packet->data is a child of subreq.
1257 talloc_steal(state, raw_packet->data);
1258 TALLOC_FREE(subreq);
1261 * We trigger the callback in the next event run
1262 * because the code in this file might trigger
1263 * multiple request callbacks from within a single
1266 * In order to avoid segfaults from within
1267 * dcerpc_connection_dead() we call
1268 * tevent_req_defer_callback().
1270 tevent_req_defer_callback(req, state->ev);
1272 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1273 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1275 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1276 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1278 tevent_req_nterror(req, status);
1282 status = dcerpc_verify_ncacn_packet_header(pkt,
1283 DCERPC_PKT_BIND_ACK,
1284 pkt->u.bind_ack.auth_info.length,
1285 DCERPC_PFC_FLAG_FIRST |
1286 DCERPC_PFC_FLAG_LAST,
1287 DCERPC_PFC_FLAG_CONC_MPX |
1288 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1289 if (!NT_STATUS_IS_OK(status)) {
1290 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1291 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1295 if (pkt->u.bind_ack.num_results < 1) {
1296 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1297 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1301 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1302 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1303 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1304 pkt->u.bind_ack.ctx_list[0].reason.value,
1305 nt_errstr(status)));
1306 tevent_req_nterror(req, status);
1310 if (pkt->u.bind_ack.num_results >= 2) {
1311 if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1312 conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
1314 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
1315 DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
1316 pkt->u.bind_ack.ctx_list[1].reason.value,
1317 nt_errstr(status)));
1318 status = NT_STATUS_OK;
1323 * DCE-RPC 1.1 (c706) specifies
1324 * CONST_MUST_RCV_FRAG_SIZE as 1432
1326 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1327 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1328 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1331 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1332 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1333 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1336 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1337 pkt->u.bind_ack.max_xmit_frag);
1338 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1339 pkt->u.bind_ack.max_recv_frag);
1341 flags = dcerpc_binding_get_flags(state->p->binding);
1343 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1344 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1345 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1347 conn->flags &= ~DCERPC_CONCURRENT_MULTIPLEX;
1351 if (!(conn->flags & DCERPC_CONCURRENT_MULTIPLEX)) {
1352 struct dcerpc_binding *pb =
1353 discard_const_p(struct dcerpc_binding, state->p->binding);
1355 * clear DCERPC_CONCURRENT_MULTIPLEX
1357 status = dcerpc_binding_set_flags(pb, 0,
1358 DCERPC_CONCURRENT_MULTIPLEX);
1359 if (tevent_req_nterror(req, status)) {
1363 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1364 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1365 conn->flags |= DCERPC_HEADER_SIGNING;
1368 /* the bind_ack might contain a reply set of credentials */
1369 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1370 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1371 &pkt->u.bind_ack.auth_info,
1372 sec->tmp_auth_info.in,
1374 if (tevent_req_nterror(req, status)) {
1380 * We're the owner of the binding, so we're allowed to modify it.
1382 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1383 status = dcerpc_binding_set_assoc_group_id(b,
1384 pkt->u.bind_ack.assoc_group_id);
1385 if (tevent_req_nterror(req, status)) {
1389 tevent_req_done(req);
1392 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1394 return tevent_req_simple_recv_ntstatus(req);
1398 perform a continued bind (and auth3)
1400 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1401 TALLOC_CTX *mem_ctx)
1403 struct ncacn_packet pkt;
1408 flags = dcerpc_binding_get_flags(p->binding);
1410 init_ncacn_hdr(p->conn, &pkt);
1412 pkt.ptype = DCERPC_PKT_AUTH3;
1413 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1414 pkt.call_id = next_call_id(p->conn);
1415 pkt.auth_length = 0;
1416 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1418 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1419 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1422 /* construct the NDR form of the packet */
1423 status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1424 p->conn->security_state.tmp_auth_info.out);
1425 if (!NT_STATUS_IS_OK(status)) {
1429 /* send it on its way */
1430 status = dcerpc_send_request(p->conn, &blob, false);
1431 if (!NT_STATUS_IS_OK(status)) {
1435 return NT_STATUS_OK;
1440 process a fragment received from the transport layer during a
1443 This function frees the data
1445 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1446 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1448 struct rpc_request *req;
1449 unsigned int length;
1450 NTSTATUS status = NT_STATUS_OK;
1453 if this is an authenticated connection then parse and check
1454 the auth info. We have to do this before finding the
1455 matching packet, as the request structure might have been
1456 removed due to a timeout, but if it has been we still need
1457 to run the auth routines so that we don't get the sign/seal
1458 info out of step with the server
1460 switch (pkt->ptype) {
1461 case DCERPC_PKT_RESPONSE:
1462 status = ncacn_pull_pkt_auth(c, raw_packet->data,
1463 DCERPC_PKT_RESPONSE,
1464 0, /* required_flags */
1465 DCERPC_PFC_FLAG_FIRST |
1466 DCERPC_PFC_FLAG_LAST,
1467 DCERPC_REQUEST_LENGTH,
1468 &pkt->u.response.stub_and_verifier,
1475 /* find the matching request */
1476 for (req=c->pending;req;req=req->next) {
1477 if (pkt->call_id == req->call_id) break;
1481 /* useful for testing certain vendors RPC servers */
1482 if (req == NULL && c->pending && pkt->call_id == 0) {
1483 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1489 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1490 data_blob_free(raw_packet);
1494 talloc_steal(req, raw_packet->data);
1496 if (req->recv_handler != NULL) {
1497 dcerpc_req_dequeue(req);
1498 req->state = RPC_REQUEST_DONE;
1501 * We have to look at shipping further requests before calling
1502 * the async function, that one might close the pipe
1504 dcerpc_schedule_io_trigger(c);
1506 req->recv_handler(req, raw_packet, pkt);
1510 if (pkt->ptype == DCERPC_PKT_FAULT) {
1511 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1512 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1513 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1514 dcerpc_connection_dead(c, status);
1517 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1518 dcerpc_connection_dead(c, status);
1521 req->fault_code = pkt->u.fault.status;
1522 req->status = NT_STATUS_NET_WRITE_FAULT;
1526 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1527 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1529 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1533 /* now check the status from the auth routines, and if it failed then fail
1534 this request accordingly */
1535 if (!NT_STATUS_IS_OK(status)) {
1536 dcerpc_connection_dead(c, status);
1540 if (req->state != RPC_REQUEST_PENDING) {
1541 req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
1545 if (pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST) {
1546 if (req->first_pdu_done) {
1547 req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
1550 req->first_pdu_done = true;
1552 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1553 req->flags |= DCERPC_PULL_BIGENDIAN;
1555 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1559 if (!req->first_pdu_done) {
1560 req->status = NT_STATUS_RPC_PROTOCOL_ERROR;
1564 length = pkt->u.response.stub_and_verifier.length;
1566 if (req->payload.length + length > c->max_total_response_size) {
1567 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1568 (unsigned)req->payload.length + length,
1569 (unsigned)c->max_total_response_size));
1570 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1575 req->payload.data = talloc_realloc(req,
1578 req->payload.length + length);
1579 if (!req->payload.data) {
1580 req->status = NT_STATUS_NO_MEMORY;
1583 memcpy(req->payload.data+req->payload.length,
1584 pkt->u.response.stub_and_verifier.data, length);
1585 req->payload.length += length;
1588 if (pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1589 req->last_pdu_done = true;
1592 if (!req->last_pdu_done) {
1593 data_blob_free(raw_packet);
1594 req->status = dcerpc_send_read(c);
1595 if (!NT_STATUS_IS_OK(req->status)) {
1599 if (!req->incomplete_payload) {
1603 if (req->async.callback) {
1604 req->async.callback(req);
1609 if (req->verify_bitmask1) {
1610 req->p->conn->security_state.verified_bitmask1 = true;
1612 if (req->verify_pcontext) {
1613 req->p->verified_pcontext = true;
1616 req->incomplete_payload = false;
1619 data_blob_free(raw_packet);
1621 /* we've got the full payload */
1622 dcerpc_req_dequeue(req);
1623 req->state = RPC_REQUEST_DONE;
1626 * We have to look at shipping further requests before calling
1627 * the async function, that one might close the pipe
1629 dcerpc_schedule_io_trigger(c);
1631 if (req->async.callback) {
1632 req->async.callback(req);
1636 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1639 perform the send side of a async dcerpc request
1641 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1642 struct dcerpc_pipe *p,
1643 const struct GUID *object,
1645 DATA_BLOB *stub_data)
1647 struct rpc_request *req;
1650 req = talloc_zero(mem_ctx, struct rpc_request);
1656 req->call_id = next_call_id(p->conn);
1657 req->state = RPC_REQUEST_QUEUED;
1659 if (object != NULL) {
1660 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1661 if (req->object == NULL) {
1669 if (stub_data->length > 0) {
1670 req->request_data.length = stub_data->length;
1671 req->request_data.data = stub_data->data;
1673 req->request_data_can_append = true;
1676 status = dcerpc_request_prepare_vt(req);
1677 if (!NT_STATUS_IS_OK(status)) {
1682 DLIST_ADD_END(p->conn->request_queue, req);
1683 talloc_set_destructor(req, dcerpc_req_dequeue);
1685 dcerpc_schedule_io_trigger(p->conn);
1687 if (p->request_timeout) {
1688 tevent_add_timer(p->conn->event_ctx, req,
1689 timeval_current_ofs(p->request_timeout, 0),
1690 dcerpc_timeout_handler, req);
1696 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1698 struct dcecli_security *sec = &req->p->conn->security_state;
1699 struct dcerpc_sec_verification_trailer *t;
1700 struct dcerpc_sec_vt *c = NULL;
1701 struct ndr_push *ndr = NULL;
1702 enum ndr_err_code ndr_err;
1704 if (sec->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1705 return NT_STATUS_OK;
1708 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1710 return NT_STATUS_NO_MEMORY;
1713 if (!sec->verified_bitmask1) {
1714 t->commands = talloc_realloc(t, t->commands,
1715 struct dcerpc_sec_vt,
1716 t->count.count + 1);
1717 if (t->commands == NULL) {
1718 return NT_STATUS_NO_MEMORY;
1720 c = &t->commands[t->count.count++];
1723 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1724 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1725 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1727 req->verify_bitmask1 = true;
1730 if (!req->p->verified_pcontext) {
1731 t->commands = talloc_realloc(t, t->commands,
1732 struct dcerpc_sec_vt,
1733 t->count.count + 1);
1734 if (t->commands == NULL) {
1735 return NT_STATUS_NO_MEMORY;
1737 c = &t->commands[t->count.count++];
1740 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1741 c->u.pcontext.abstract_syntax = req->p->syntax;
1742 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1744 req->verify_pcontext = true;
1747 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1748 t->commands = talloc_realloc(t, t->commands,
1749 struct dcerpc_sec_vt,
1750 t->count.count + 1);
1751 if (t->commands == NULL) {
1752 return NT_STATUS_NO_MEMORY;
1754 c = &t->commands[t->count.count++];
1757 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1758 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1759 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1760 c->u.header2.drep[0] = 0;
1762 c->u.header2.drep[0] = DCERPC_DREP_LE;
1764 c->u.header2.drep[1] = 0;
1765 c->u.header2.drep[2] = 0;
1766 c->u.header2.drep[3] = 0;
1767 c->u.header2.call_id = req->call_id;
1768 c->u.header2.context_id = req->p->context_id;
1769 c->u.header2.opnum = req->opnum;
1772 if (t->count.count == 0) {
1774 return NT_STATUS_OK;
1777 c = &t->commands[t->count.count - 1];
1778 c->command |= DCERPC_SEC_VT_COMMAND_END;
1780 if (DEBUGLEVEL >= 10) {
1781 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1784 ndr = ndr_push_init_ctx(req);
1786 return NT_STATUS_NO_MEMORY;
1790 * for now we just copy and append
1793 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1794 req->request_data.length);
1795 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1796 return ndr_map_error2ntstatus(ndr_err);
1799 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1800 NDR_SCALARS | NDR_BUFFERS,
1802 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1803 return ndr_map_error2ntstatus(ndr_err);
1805 req->request_data = ndr_push_blob(ndr);
1807 return NT_STATUS_OK;
1811 Send a request using the transport
1814 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1816 struct rpc_request *req;
1817 struct dcerpc_pipe *p;
1818 DATA_BLOB *stub_data;
1819 struct ncacn_packet pkt;
1821 uint32_t remaining, chunk_size;
1822 size_t sig_size = 0;
1823 bool need_async = false;
1824 bool can_async = true;
1825 bool current_pdus_done = false;
1827 req = c->request_queue;
1833 stub_data = &req->request_data;
1839 remaining = stub_data->length;
1841 if ((remaining == 0) && req->incomplete_request_data) {
1843 * we're waiting for more data
1848 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1849 can_async = gensec_have_feature(c->security_state.generic_state,
1850 GENSEC_FEATURE_ASYNC_REPLIES);
1853 if (need_async && !can_async) {
1854 req->wait_for_sync = true;
1858 init_ncacn_hdr(p->conn, &pkt);
1860 /* we can write a full max_recv_frag size, minus the dcerpc
1861 request header size */
1862 chunk_size = p->conn->srv_max_recv_frag;
1863 chunk_size -= DCERPC_REQUEST_LENGTH;
1864 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1865 size_t max_payload = chunk_size;
1867 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1868 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1870 sig_size = gensec_sig_size(c->security_state.generic_state,
1873 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1874 chunk_size -= sig_size;
1877 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1879 pkt.ptype = DCERPC_PKT_REQUEST;
1880 pkt.call_id = req->call_id;
1881 pkt.auth_length = 0;
1883 pkt.u.request.context_id = p->context_id;
1884 pkt.u.request.opnum = req->opnum;
1887 pkt.u.request.object.object = *req->object;
1888 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1889 chunk_size -= ndr_size_GUID(req->object,0);
1892 /* we send a series of pdus without waiting for a reply */
1893 while (!current_pdus_done) {
1894 uint32_t chunk = MIN(chunk_size, remaining);
1895 bool last_frag = false;
1896 bool do_trans = false;
1898 if ((chunk == remaining) && !req->incomplete_request_data) {
1902 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1904 if (!req->first_pdu_done) {
1905 req->first_pdu_done = true;
1906 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1909 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1912 pkt.u.request.alloc_hint = remaining;
1913 pkt.u.request.stub_and_verifier.data = stub_data->data +
1914 (stub_data->length - remaining);
1915 pkt.u.request.stub_and_verifier.length = chunk;
1917 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1918 if (!NT_STATUS_IS_OK(req->status)) {
1919 req->state = RPC_REQUEST_DONE;
1920 DLIST_REMOVE(c->request_queue, req);
1924 if (last_frag && !need_async) {
1928 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1929 if (!NT_STATUS_IS_OK(req->status)) {
1930 req->state = RPC_REQUEST_DONE;
1931 DLIST_REMOVE(c->request_queue, req);
1935 if (last_frag && !do_trans) {
1936 req->status = dcerpc_send_read(p->conn);
1937 if (!NT_STATUS_IS_OK(req->status)) {
1938 req->state = RPC_REQUEST_DONE;
1939 DLIST_REMOVE(c->request_queue, req);
1945 if (remaining == 0) {
1946 current_pdus_done = true;
1948 req->last_pdu_done = last_frag;
1951 if (req->request_data_can_append) {
1953 * request_data_can_append means the blob
1954 * is a talloc child of req
1956 data_blob_free(&req->request_data);
1958 req->request_data_can_append = true;
1959 req->request_data = data_blob_null;
1961 if (req->last_pdu_done) {
1962 DLIST_REMOVE(c->request_queue, req);
1963 DLIST_ADD(c->pending, req);
1964 req->state = RPC_REQUEST_PENDING;
1966 * we reuse *_pdu_done for the receive side
1968 req->first_pdu_done = false;
1969 req->last_pdu_done = false;
1972 if (req->stub_subreq != NULL) {
1973 struct tevent_req *stub_subreq = req->stub_subreq;
1975 req->stub_subreq = NULL;
1977 tevent_req_done(stub_subreq);
1984 static void dcerpc_io_trigger(struct tevent_context *ctx,
1985 struct tevent_immediate *im,
1988 struct dcecli_connection *c =
1989 talloc_get_type_abort(private_data,
1990 struct dcecli_connection);
1992 c->io_trigger_pending = false;
1994 dcerpc_schedule_io_trigger(c);
1996 dcerpc_ship_next_request(c);
1999 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
2005 if (c->request_queue == NULL) {
2009 if (c->request_queue->wait_for_sync && c->pending) {
2013 if (c->request_queue->request_data.length == 0 &&
2014 c->request_queue->incomplete_request_data)
2019 if (c->io_trigger_pending) {
2023 c->io_trigger_pending = true;
2025 tevent_schedule_immediate(c->io_trigger,
2032 perform the receive side of a async dcerpc request
2034 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
2035 TALLOC_CTX *mem_ctx,
2036 DATA_BLOB *stub_data)
2040 *stub_data = req->payload;
2041 req->payload = data_blob_null;
2042 status = req->status;
2043 if (stub_data->data) {
2044 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
2046 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
2047 req->p->last_fault_code = req->fault_code;
2049 if (req->state == RPC_REQUEST_PENDING) {
2050 if (NT_STATUS_IS_OK(status)) {
2054 talloc_unlink(talloc_parent(req), req);
2059 this is a paranoid NDR validator. For every packet we push onto the wire
2060 we pull it back again, then push it again. Then we compare the raw NDR data
2061 for that to the NDR we initially generated. If they don't match then we know
2062 we must have a bug in either the pull or push side of our code
2064 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
2065 TALLOC_CTX *mem_ctx,
2068 ndr_push_flags_fn_t ndr_push,
2069 ndr_pull_flags_fn_t ndr_pull)
2072 struct ndr_pull *pull;
2073 struct ndr_push *push;
2075 enum ndr_err_code ndr_err;
2077 st = talloc_size(mem_ctx, struct_size);
2079 return NT_STATUS_NO_MEMORY;
2082 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2084 return NT_STATUS_NO_MEMORY;
2086 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2088 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2089 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
2092 if (c->flags & DCERPC_NDR64) {
2093 pull->flags |= LIBNDR_FLAG_NDR64;
2096 ndr_err = ndr_pull(pull, NDR_IN, st);
2097 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2098 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2099 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2100 "failed input validation pull - %s",
2102 return ndr_map_error2ntstatus(ndr_err);
2105 push = ndr_push_init_ctx(mem_ctx);
2107 return NT_STATUS_NO_MEMORY;
2110 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2111 push->flags |= LIBNDR_FLAG_BIGENDIAN;
2114 if (c->flags & DCERPC_NDR64) {
2115 push->flags |= LIBNDR_FLAG_NDR64;
2118 ndr_err = ndr_push(push, NDR_IN, st);
2119 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2120 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2121 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2122 "failed input validation push - %s",
2124 return ndr_map_error2ntstatus(ndr_err);
2127 blob2 = ndr_push_blob(push);
2129 if (data_blob_cmp(&blob, &blob2) != 0) {
2130 DEBUG(3,("original:\n"));
2131 dump_data(3, blob.data, blob.length);
2132 DEBUG(3,("secondary:\n"));
2133 dump_data(3, blob2.data, blob2.length);
2134 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2135 "failed input validation blobs doesn't match");
2136 return ndr_map_error2ntstatus(ndr_err);
2139 return NT_STATUS_OK;
2143 this is a paranoid NDR input validator. For every packet we pull
2144 from the wire we push it back again then pull and push it
2145 again. Then we compare the raw NDR data for that to the NDR we
2146 initially generated. If they don't match then we know we must have a
2147 bug in either the pull or push side of our code
2149 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
2150 struct ndr_pull *pull_in,
2153 ndr_push_flags_fn_t ndr_push,
2154 ndr_pull_flags_fn_t ndr_pull,
2155 ndr_print_function_t ndr_print)
2158 struct ndr_pull *pull;
2159 struct ndr_push *push;
2160 DATA_BLOB blob, blob2;
2161 TALLOC_CTX *mem_ctx = pull_in;
2163 enum ndr_err_code ndr_err;
2165 st = talloc_size(mem_ctx, struct_size);
2167 return NT_STATUS_NO_MEMORY;
2169 memcpy(st, struct_ptr, struct_size);
2171 push = ndr_push_init_ctx(mem_ctx);
2173 return NT_STATUS_NO_MEMORY;
2176 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2177 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2178 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2179 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2180 "failed output validation push - %s",
2182 return ndr_map_error2ntstatus(ndr_err);
2185 blob = ndr_push_blob(push);
2187 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2189 return NT_STATUS_NO_MEMORY;
2192 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2193 ndr_err = ndr_pull(pull, NDR_OUT, st);
2194 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2195 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2196 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2197 "failed output validation pull - %s",
2199 return ndr_map_error2ntstatus(ndr_err);
2202 push = ndr_push_init_ctx(mem_ctx);
2204 return NT_STATUS_NO_MEMORY;
2207 ndr_err = ndr_push(push, NDR_OUT, st);
2208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2209 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2210 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2211 "failed output validation push2 - %s",
2213 return ndr_map_error2ntstatus(ndr_err);
2216 blob2 = ndr_push_blob(push);
2218 if (data_blob_cmp(&blob, &blob2) != 0) {
2219 DEBUG(3,("original:\n"));
2220 dump_data(3, blob.data, blob.length);
2221 DEBUG(3,("secondary:\n"));
2222 dump_data(3, blob2.data, blob2.length);
2223 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2224 "failed output validation blobs doesn't match");
2225 return ndr_map_error2ntstatus(ndr_err);
2228 /* this checks the printed forms of the two structures, which effectively
2229 tests all of the value() attributes */
2230 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2231 NDR_OUT, struct_ptr);
2232 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2234 if (strcmp(s1, s2) != 0) {
2236 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2238 /* this is sometimes useful */
2239 printf("VALIDATE ERROR\n");
2240 file_save("wire.dat", s1, strlen(s1));
2241 file_save("gen.dat", s2, strlen(s2));
2242 system("diff -u wire.dat gen.dat");
2244 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2245 "failed output validation strings doesn't match");
2246 return ndr_map_error2ntstatus(ndr_err);
2249 return NT_STATUS_OK;
2253 a useful function for retrieving the server name we connected to
2255 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2257 return p->conn ? p->conn->server_name : NULL;
2262 get the dcerpc auth_level for a open connection
2264 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2268 if (c->flags & DCERPC_SEAL) {
2269 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2270 } else if (c->flags & DCERPC_SIGN) {
2271 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2272 } else if (c->flags & DCERPC_PACKET) {
2273 auth_level = DCERPC_AUTH_LEVEL_PACKET;
2274 } else if (c->flags & DCERPC_CONNECT) {
2275 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2277 auth_level = DCERPC_AUTH_LEVEL_NONE;
2282 struct dcerpc_alter_context_state {
2283 struct tevent_context *ev;
2284 struct dcerpc_pipe *p;
2287 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2288 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2289 DATA_BLOB *raw_packet,
2290 struct ncacn_packet *pkt);
2292 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2293 struct tevent_context *ev,
2294 struct dcerpc_pipe *p,
2295 const struct ndr_syntax_id *syntax,
2296 const struct ndr_syntax_id *transfer_syntax)
2298 struct tevent_req *req;
2299 struct dcerpc_alter_context_state *state;
2300 struct ncacn_packet pkt;
2303 struct rpc_request *subreq;
2306 req = tevent_req_create(mem_ctx, &state,
2307 struct dcerpc_alter_context_state);
2315 p->syntax = *syntax;
2316 p->transfer_syntax = *transfer_syntax;
2318 flags = dcerpc_binding_get_flags(p->binding);
2320 init_ncacn_hdr(p->conn, &pkt);
2322 pkt.ptype = DCERPC_PKT_ALTER;
2323 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2324 pkt.call_id = p->conn->call_id;
2325 pkt.auth_length = 0;
2327 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2328 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2331 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2332 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2333 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2334 pkt.u.alter.num_contexts = 1;
2335 pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
2336 pkt.u.alter.num_contexts);
2337 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2338 return tevent_req_post(req, ev);
2340 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2341 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2342 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2343 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2344 pkt.u.alter.auth_info = data_blob(NULL, 0);
2346 /* construct the NDR form of the packet */
2347 status = ncacn_push_auth(&blob, state, &pkt,
2348 p->conn->security_state.tmp_auth_info.out);
2349 if (tevent_req_nterror(req, status)) {
2350 return tevent_req_post(req, ev);
2354 * we allocate a dcerpc_request so we can be in the same
2355 * request queue as normal requests
2357 subreq = talloc_zero(state, struct rpc_request);
2358 if (tevent_req_nomem(subreq, req)) {
2359 return tevent_req_post(req, ev);
2362 subreq->state = RPC_REQUEST_PENDING;
2363 subreq->call_id = pkt.call_id;
2364 subreq->async.private_data = req;
2365 subreq->async.callback = dcerpc_alter_context_fail_handler;
2367 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2368 DLIST_ADD_END(p->conn->pending, subreq);
2369 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2371 status = dcerpc_send_request(p->conn, &blob, true);
2372 if (tevent_req_nterror(req, status)) {
2373 return tevent_req_post(req, ev);
2376 tevent_add_timer(ev, subreq,
2377 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2378 dcerpc_timeout_handler, subreq);
2383 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2385 struct tevent_req *req =
2386 talloc_get_type_abort(subreq->async.private_data,
2388 struct dcerpc_alter_context_state *state =
2389 tevent_req_data(req,
2390 struct dcerpc_alter_context_state);
2391 NTSTATUS status = subreq->status;
2393 TALLOC_FREE(subreq);
2396 * We trigger the callback in the next event run
2397 * because the code in this file might trigger
2398 * multiple request callbacks from within a single
2401 * In order to avoid segfaults from within
2402 * dcerpc_connection_dead() we call
2403 * tevent_req_defer_callback().
2405 tevent_req_defer_callback(req, state->ev);
2407 tevent_req_nterror(req, status);
2410 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2411 DATA_BLOB *raw_packet,
2412 struct ncacn_packet *pkt)
2414 struct tevent_req *req =
2415 talloc_get_type_abort(subreq->async.private_data,
2417 struct dcerpc_alter_context_state *state =
2418 tevent_req_data(req,
2419 struct dcerpc_alter_context_state);
2420 struct dcecli_connection *conn = state->p->conn;
2421 struct dcecli_security *sec = &conn->security_state;
2425 * Note that pkt is allocated under raw_packet->data,
2426 * while raw_packet->data is a child of subreq.
2428 talloc_steal(state, raw_packet->data);
2429 TALLOC_FREE(subreq);
2432 * We trigger the callback in the next event run
2433 * because the code in this file might trigger
2434 * multiple request callbacks from within a single
2437 * In order to avoid segfaults from within
2438 * dcerpc_connection_dead() we call
2439 * tevent_req_defer_callback().
2441 tevent_req_defer_callback(req, state->ev);
2443 if (pkt->ptype == DCERPC_PKT_FAULT) {
2444 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2445 dcerpc_errstr(state, pkt->u.fault.status)));
2446 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2447 state->p->last_fault_code = pkt->u.fault.status;
2448 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2449 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2450 state->p->last_fault_code = pkt->u.fault.status;
2451 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2453 state->p->last_fault_code = pkt->u.fault.status;
2454 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2455 tevent_req_nterror(req, status);
2460 status = dcerpc_verify_ncacn_packet_header(pkt,
2461 DCERPC_PKT_ALTER_RESP,
2462 pkt->u.alter_resp.auth_info.length,
2463 DCERPC_PFC_FLAG_FIRST |
2464 DCERPC_PFC_FLAG_LAST,
2465 DCERPC_PFC_FLAG_CONC_MPX |
2466 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2467 if (!NT_STATUS_IS_OK(status)) {
2468 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2469 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2473 if (pkt->u.alter_resp.num_results != 1) {
2474 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2475 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2479 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2480 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2481 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2482 pkt->u.alter_resp.ctx_list[0].reason.value,
2483 nt_errstr(status)));
2484 tevent_req_nterror(req, status);
2488 /* the alter_resp might contain a reply set of credentials */
2489 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2490 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2491 &pkt->u.alter_resp.auth_info,
2492 sec->tmp_auth_info.in,
2494 if (tevent_req_nterror(req, status)) {
2499 tevent_req_done(req);
2502 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2504 return tevent_req_simple_recv_ntstatus(req);
2508 send a dcerpc alter_context request
2510 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2511 TALLOC_CTX *mem_ctx,
2512 const struct ndr_syntax_id *syntax,
2513 const struct ndr_syntax_id *transfer_syntax)
2515 struct tevent_req *subreq;
2516 struct tevent_context *ev = p->conn->event_ctx;
2519 /* TODO: create a new event context here */
2521 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2522 p, syntax, transfer_syntax);
2523 if (subreq == NULL) {
2524 return NT_STATUS_NO_MEMORY;
2527 ok = tevent_req_poll(subreq, ev);
2530 status = map_nt_error_from_unix_common(errno);
2534 return dcerpc_alter_context_recv(subreq);
2537 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2539 if (c->transport.stream == NULL) {
2543 tevent_queue_stop(c->transport.write_queue);
2544 TALLOC_FREE(c->transport.read_subreq);
2545 TALLOC_FREE(c->transport.stream);
2547 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2548 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2551 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2552 status = NT_STATUS_END_OF_FILE;
2555 dcerpc_recv_data(c, NULL, status);
2560 shutdown SMB pipe connection
2562 struct dcerpc_shutdown_pipe_state {
2563 struct dcecli_connection *c;
2567 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2569 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2571 struct dcerpc_shutdown_pipe_state *state;
2572 struct tevent_req *subreq;
2574 if (c->transport.stream == NULL) {
2575 return NT_STATUS_OK;
2578 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2579 if (state == NULL) {
2580 return NT_STATUS_NO_MEMORY;
2583 state->status = status;
2585 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2586 if (subreq == NULL) {
2587 return NT_STATUS_NO_MEMORY;
2589 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2594 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2596 struct dcerpc_shutdown_pipe_state *state =
2597 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2598 struct dcecli_connection *c = state->c;
2599 NTSTATUS status = state->status;
2603 * here we ignore the return values...
2605 tstream_disconnect_recv(subreq, &error);
2606 TALLOC_FREE(subreq);
2610 dcerpc_transport_dead(c, status);
2615 struct dcerpc_send_read_state {
2616 struct dcecli_connection *p;
2619 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2621 struct dcecli_connection *p = state->p;
2623 p->transport.read_subreq = NULL;
2628 static void dcerpc_send_read_done(struct tevent_req *subreq);
2630 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2632 struct dcerpc_send_read_state *state;
2634 if (p->transport.read_subreq != NULL) {
2635 p->transport.pending_reads++;
2636 return NT_STATUS_OK;
2639 state = talloc_zero(p, struct dcerpc_send_read_state);
2640 if (state == NULL) {
2641 return NT_STATUS_NO_MEMORY;
2645 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2647 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2649 p->transport.stream);
2650 if (p->transport.read_subreq == NULL) {
2651 return NT_STATUS_NO_MEMORY;
2653 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2655 return NT_STATUS_OK;
2658 static void dcerpc_send_read_done(struct tevent_req *subreq)
2660 struct dcerpc_send_read_state *state =
2661 tevent_req_callback_data(subreq,
2662 struct dcerpc_send_read_state);
2663 struct dcecli_connection *p = state->p;
2665 struct ncacn_packet *pkt;
2668 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2670 TALLOC_FREE(subreq);
2671 if (!NT_STATUS_IS_OK(status)) {
2673 dcerpc_transport_dead(p, status);
2678 * here we steal into thet connection context,
2679 * but p->transport.recv_data() will steal or free it again
2681 talloc_steal(p, blob.data);
2684 if (p->transport.pending_reads > 0) {
2685 p->transport.pending_reads--;
2687 status = dcerpc_send_read(p);
2688 if (!NT_STATUS_IS_OK(status)) {
2689 dcerpc_transport_dead(p, status);
2694 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2697 struct dcerpc_send_request_state {
2698 struct dcecli_connection *p;
2703 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2705 struct dcecli_connection *p = state->p;
2707 p->transport.read_subreq = NULL;
2712 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2713 static void dcerpc_send_request_done(struct tevent_req *subreq);
2715 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2718 struct dcerpc_send_request_state *state;
2719 struct tevent_req *subreq;
2720 bool use_trans = trigger_read;
2722 if (p->transport.stream == NULL) {
2723 return NT_STATUS_CONNECTION_DISCONNECTED;
2726 state = talloc_zero(p, struct dcerpc_send_request_state);
2727 if (state == NULL) {
2728 return NT_STATUS_NO_MEMORY;
2732 state->blob = data_blob_talloc(state, data->data, data->length);
2733 if (state->blob.data == NULL) {
2735 return NT_STATUS_NO_MEMORY;
2737 state->iov.iov_base = (void *)state->blob.data;
2738 state->iov.iov_len = state->blob.length;
2740 if (p->transport.read_subreq != NULL) {
2744 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2750 * we need to block reads until our write is
2751 * the next in the write queue.
2753 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2754 p->transport.write_queue);
2755 if (p->transport.read_subreq == NULL) {
2757 return NT_STATUS_NO_MEMORY;
2759 tevent_req_set_callback(p->transport.read_subreq,
2760 dcerpc_send_request_wait_done,
2763 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2765 trigger_read = false;
2768 subreq = tstream_writev_queue_send(state, p->event_ctx,
2769 p->transport.stream,
2770 p->transport.write_queue,
2772 if (subreq == NULL) {
2774 return NT_STATUS_NO_MEMORY;
2776 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2779 dcerpc_send_read(p);
2782 return NT_STATUS_OK;
2785 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2787 struct dcerpc_send_request_state *state =
2788 tevent_req_callback_data(subreq,
2789 struct dcerpc_send_request_state);
2790 struct dcecli_connection *p = state->p;
2794 p->transport.read_subreq = NULL;
2795 talloc_set_destructor(state, NULL);
2797 ok = tevent_queue_wait_recv(subreq);
2800 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2804 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2805 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2806 if (!NT_STATUS_IS_OK(status)) {
2808 dcerpc_transport_dead(p, status);
2813 /* we free subreq after tstream_cli_np_use_trans */
2814 TALLOC_FREE(subreq);
2816 dcerpc_send_read(p);
2819 static void dcerpc_send_request_done(struct tevent_req *subreq)
2821 struct dcerpc_send_request_state *state =
2822 tevent_req_callback_data(subreq,
2823 struct dcerpc_send_request_state);
2827 ret = tstream_writev_queue_recv(subreq, &error);
2828 TALLOC_FREE(subreq);
2830 struct dcecli_connection *p = state->p;
2831 NTSTATUS status = map_nt_error_from_unix_common(error);
2834 dcerpc_transport_dead(p, status);