lib: Give lib/util/util_file.c its own header file
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blob58f00b7f9d2c24335b9dea627d17b83812861944
1 /*
2 Unix SMB/CIFS implementation.
3 raw dcerpc operations
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/>.
23 #include "includes.h"
24 #include "lib/util/util_file.h"
25 #include "system/filesys.h"
26 #include "../lib/util/dlinklist.h"
27 #include "lib/events/events.h"
28 #include "librpc/rpc/dcerpc.h"
29 #include "librpc/rpc/dcerpc_proto.h"
30 #include "librpc/rpc/dcerpc_util.h"
31 #include "librpc/rpc/dcerpc_pkt_auth.h"
32 #include "librpc/gen_ndr/ndr_misc.h"
33 #include "librpc/gen_ndr/ndr_dcerpc.h"
34 #include "auth/gensec/gensec.h"
35 #include "param/param.h"
36 #include "lib/util/tevent_ntstatus.h"
37 #include "librpc/rpc/rpc_common.h"
38 #include "lib/tsocket/tsocket.h"
39 #include "libcli/smb/tstream_smbXcli_np.h"
42 enum rpc_request_state {
43 RPC_REQUEST_QUEUED,
44 RPC_REQUEST_PENDING,
45 RPC_REQUEST_DONE
49 handle for an async dcerpc request
51 struct rpc_request {
52 struct rpc_request *next, *prev;
53 struct dcerpc_pipe *p;
54 NTSTATUS status;
55 uint32_t call_id;
56 enum rpc_request_state state;
57 DATA_BLOB payload;
58 uint32_t flags;
59 uint32_t fault_code;
61 /* this is used to distinguish bind and alter_context requests
62 from normal requests */
63 void (*recv_handler)(struct rpc_request *conn,
64 DATA_BLOB *blob, struct ncacn_packet *pkt);
66 const struct GUID *object;
67 uint16_t opnum;
68 DATA_BLOB request_data;
69 bool ignore_timeout;
70 bool wait_for_sync;
71 bool verify_bitmask1;
72 bool verify_pcontext;
74 struct {
75 void (*callback)(struct rpc_request *);
76 void *private_data;
77 } async;
80 _PUBLIC_ NTSTATUS dcerpc_init(void)
82 return gensec_init();
85 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
86 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
88 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
89 struct dcerpc_pipe *p,
90 const struct GUID *object,
91 uint16_t opnum,
92 DATA_BLOB *stub_data);
93 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
94 TALLOC_CTX *mem_ctx,
95 DATA_BLOB *stub_data);
96 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
97 TALLOC_CTX *mem_ctx,
98 DATA_BLOB blob,
99 size_t struct_size,
100 ndr_push_flags_fn_t ndr_push,
101 ndr_pull_flags_fn_t ndr_pull);
102 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
103 struct ndr_pull *pull_in,
104 void *struct_ptr,
105 size_t struct_size,
106 ndr_push_flags_fn_t ndr_push,
107 ndr_pull_flags_fn_t ndr_pull,
108 ndr_print_function_t ndr_print);
109 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
110 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
111 bool trigger_read);
112 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
114 /* destroy a dcerpc connection */
115 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
117 if (conn->dead) {
118 conn->free_skipped = true;
119 return -1;
121 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
122 return 0;
126 /* initialise a dcerpc connection.
127 the event context is optional
129 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
130 struct tevent_context *ev)
132 struct dcecli_connection *c;
134 c = talloc_zero(mem_ctx, struct dcecli_connection);
135 if (!c) {
136 return NULL;
139 c->event_ctx = ev;
141 if (c->event_ctx == NULL) {
142 talloc_free(c);
143 return NULL;
146 c->call_id = 1;
147 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
148 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
149 c->security_state.auth_context_id = 0;
150 c->security_state.session_key = dcecli_generic_session_key;
151 c->security_state.generic_state = NULL;
152 c->flags = 0;
154 * Windows uses 5840 for ncacn_ip_tcp,
155 * so we also use it (for every transport)
156 * by default. But we give the transport
157 * the chance to overwrite it.
159 c->srv_max_xmit_frag = 5840;
160 c->srv_max_recv_frag = 5840;
161 c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
162 c->pending = NULL;
164 c->io_trigger = tevent_create_immediate(c);
165 if (c->io_trigger == NULL) {
166 talloc_free(c);
167 return NULL;
170 talloc_set_destructor(c, dcerpc_connection_destructor);
172 return c;
175 struct dcerpc_bh_state {
176 struct dcerpc_pipe *p;
179 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
181 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
182 struct dcerpc_bh_state);
184 if (!hs->p) {
185 return false;
188 if (!hs->p->conn) {
189 return false;
192 if (hs->p->conn->dead) {
193 return false;
196 return true;
199 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
200 uint32_t timeout)
202 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
203 struct dcerpc_bh_state);
204 uint32_t old;
206 if (!hs->p) {
207 return DCERPC_REQUEST_TIMEOUT;
210 old = hs->p->request_timeout;
211 hs->p->request_timeout = timeout;
213 return old;
216 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
217 enum dcerpc_AuthType *auth_type,
218 enum dcerpc_AuthLevel *auth_level)
220 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
221 struct dcerpc_bh_state);
223 if (hs->p == NULL) {
224 return;
227 if (hs->p->conn == NULL) {
228 return;
231 *auth_type = hs->p->conn->security_state.auth_type;
232 *auth_level = hs->p->conn->security_state.auth_level;
235 struct dcerpc_bh_raw_call_state {
236 struct tevent_context *ev;
237 struct dcerpc_binding_handle *h;
238 DATA_BLOB in_data;
239 DATA_BLOB out_data;
240 uint32_t out_flags;
243 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
245 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
246 struct tevent_context *ev,
247 struct dcerpc_binding_handle *h,
248 const struct GUID *object,
249 uint32_t opnum,
250 uint32_t in_flags,
251 const uint8_t *in_data,
252 size_t in_length)
254 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
255 struct dcerpc_bh_state);
256 struct tevent_req *req;
257 struct dcerpc_bh_raw_call_state *state;
258 bool ok;
259 struct rpc_request *subreq;
261 req = tevent_req_create(mem_ctx, &state,
262 struct dcerpc_bh_raw_call_state);
263 if (req == NULL) {
264 return NULL;
266 state->ev = ev;
267 state->h = h;
268 state->in_data.data = discard_const_p(uint8_t, in_data);
269 state->in_data.length = in_length;
271 ok = dcerpc_bh_is_connected(h);
272 if (!ok) {
273 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
274 return tevent_req_post(req, ev);
277 subreq = dcerpc_request_send(state,
278 hs->p,
279 object,
280 opnum,
281 &state->in_data);
282 if (tevent_req_nomem(subreq, req)) {
283 return tevent_req_post(req, ev);
285 subreq->async.callback = dcerpc_bh_raw_call_done;
286 subreq->async.private_data = req;
288 return req;
291 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
293 struct tevent_req *req =
294 talloc_get_type_abort(subreq->async.private_data,
295 struct tevent_req);
296 struct dcerpc_bh_raw_call_state *state =
297 tevent_req_data(req,
298 struct dcerpc_bh_raw_call_state);
299 NTSTATUS status;
300 uint32_t fault_code;
302 state->out_flags = 0;
303 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
304 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
307 fault_code = subreq->fault_code;
309 status = dcerpc_request_recv(subreq, state, &state->out_data);
310 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
311 status = dcerpc_fault_to_nt_status(fault_code);
315 * We trigger the callback in the next event run
316 * because the code in this file might trigger
317 * multiple request callbacks from within a single
318 * while loop.
320 * In order to avoid segfaults from within
321 * dcerpc_connection_dead() we call
322 * tevent_req_defer_callback().
324 tevent_req_defer_callback(req, state->ev);
326 if (!NT_STATUS_IS_OK(status)) {
327 tevent_req_nterror(req, status);
328 return;
331 tevent_req_done(req);
334 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
335 TALLOC_CTX *mem_ctx,
336 uint8_t **out_data,
337 size_t *out_length,
338 uint32_t *out_flags)
340 struct dcerpc_bh_raw_call_state *state =
341 tevent_req_data(req,
342 struct dcerpc_bh_raw_call_state);
343 NTSTATUS status;
345 if (tevent_req_is_nterror(req, &status)) {
346 tevent_req_received(req);
347 return status;
350 *out_data = talloc_move(mem_ctx, &state->out_data.data);
351 *out_length = state->out_data.length;
352 *out_flags = state->out_flags;
353 tevent_req_received(req);
354 return NT_STATUS_OK;
357 struct dcerpc_bh_disconnect_state {
358 uint8_t _dummy;
361 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
362 struct tevent_context *ev,
363 struct dcerpc_binding_handle *h)
365 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
366 struct dcerpc_bh_state);
367 struct tevent_req *req;
368 struct dcerpc_bh_disconnect_state *state;
369 bool ok;
371 req = tevent_req_create(mem_ctx, &state,
372 struct dcerpc_bh_disconnect_state);
373 if (req == NULL) {
374 return NULL;
377 ok = dcerpc_bh_is_connected(h);
378 if (!ok) {
379 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
380 return tevent_req_post(req, ev);
383 /* TODO: do a real disconnect ... */
384 hs->p = NULL;
386 tevent_req_done(req);
387 return tevent_req_post(req, ev);
390 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
392 NTSTATUS status;
394 if (tevent_req_is_nterror(req, &status)) {
395 tevent_req_received(req);
396 return status;
399 tevent_req_received(req);
400 return NT_STATUS_OK;
403 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
405 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
406 struct dcerpc_bh_state);
408 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
409 return true;
412 return false;
415 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
417 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
418 struct dcerpc_bh_state);
420 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
421 return true;
424 return false;
427 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
429 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
430 struct dcerpc_bh_state);
432 if (hs->p->conn->flags & DCERPC_NDR64) {
433 return true;
436 return false;
439 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
440 ndr_flags_type ndr_flags,
441 const void *_struct_ptr,
442 const struct ndr_interface_call *call)
444 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
445 struct dcerpc_bh_state);
446 void *struct_ptr = discard_const(_struct_ptr);
447 bool print_in = false;
448 bool print_out = false;
450 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
451 print_in = true;
454 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
455 print_out = true;
458 if (DEBUGLEVEL >= 11) {
459 print_in = true;
460 print_out = true;
463 if (ndr_flags & NDR_IN) {
464 if (print_in) {
465 ndr_print_function_debug(call->ndr_print,
466 call->name,
467 ndr_flags,
468 struct_ptr);
471 if (ndr_flags & NDR_OUT) {
472 if (print_out) {
473 ndr_print_function_debug(call->ndr_print,
474 call->name,
475 ndr_flags,
476 struct_ptr);
481 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
482 NTSTATUS error,
483 const void *struct_ptr,
484 const struct ndr_interface_call *call)
486 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
487 call->name, nt_errstr(error)));
490 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
491 NTSTATUS error,
492 const DATA_BLOB *blob,
493 const struct ndr_interface_call *call)
495 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
496 struct dcerpc_bh_state);
497 const uint32_t num_examples = 20;
498 uint32_t i;
500 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
501 call->name, nt_errstr(error)));
503 if (hs->p->conn->packet_log_dir == NULL) return;
505 for (i=0;i<num_examples;i++) {
506 char *name=NULL;
507 int ret;
509 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
510 hs->p->conn->packet_log_dir,
511 call->name, i);
512 if (ret == -1) {
513 return;
515 if (!file_exist(name)) {
516 if (file_save(name, blob->data, blob->length)) {
517 DEBUG(10,("Logged rpc packet to %s\n", name));
519 free(name);
520 break;
522 free(name);
526 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
527 TALLOC_CTX *mem_ctx,
528 const DATA_BLOB *blob,
529 const struct ndr_interface_call *call)
531 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
532 struct dcerpc_bh_state);
534 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
535 NTSTATUS status;
537 status = dcerpc_ndr_validate_in(hs->p->conn,
538 mem_ctx,
539 *blob,
540 call->struct_size,
541 call->ndr_push,
542 call->ndr_pull);
543 if (!NT_STATUS_IS_OK(status)) {
544 DEBUG(0,("Validation [in] failed for %s - %s\n",
545 call->name, nt_errstr(status)));
546 return status;
550 DEBUG(10,("rpc request data:\n"));
551 dump_data(10, blob->data, blob->length);
553 return NT_STATUS_OK;
556 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
557 struct ndr_pull *pull_in,
558 const void *_struct_ptr,
559 const struct ndr_interface_call *call)
561 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
562 struct dcerpc_bh_state);
563 void *struct_ptr = discard_const(_struct_ptr);
565 DEBUG(10,("rpc reply data:\n"));
566 dump_data(10, pull_in->data, pull_in->data_size);
568 if (pull_in->offset != pull_in->data_size) {
569 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
570 pull_in->data_size - pull_in->offset,
571 pull_in->offset, pull_in->offset,
572 call->name));
573 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
574 but it turns out that early versions of NT
575 (specifically NT3.1) add junk onto the end of rpc
576 packets, so if we want to interoperate at all with
577 those versions then we need to ignore this error */
580 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
581 NTSTATUS status;
583 status = dcerpc_ndr_validate_out(hs->p->conn,
584 pull_in,
585 struct_ptr,
586 call->struct_size,
587 call->ndr_push,
588 call->ndr_pull,
589 call->ndr_print);
590 if (!NT_STATUS_IS_OK(status)) {
591 DEBUG(2,("Validation [out] failed for %s - %s\n",
592 call->name, nt_errstr(status)));
593 return status;
597 return NT_STATUS_OK;
600 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
601 .name = "dcerpc",
602 .is_connected = dcerpc_bh_is_connected,
603 .set_timeout = dcerpc_bh_set_timeout,
604 .auth_info = dcerpc_bh_auth_info,
605 .raw_call_send = dcerpc_bh_raw_call_send,
606 .raw_call_recv = dcerpc_bh_raw_call_recv,
607 .disconnect_send = dcerpc_bh_disconnect_send,
608 .disconnect_recv = dcerpc_bh_disconnect_recv,
610 .push_bigendian = dcerpc_bh_push_bigendian,
611 .ref_alloc = dcerpc_bh_ref_alloc,
612 .use_ndr64 = dcerpc_bh_use_ndr64,
613 .do_ndr_print = dcerpc_bh_do_ndr_print,
614 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
615 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
616 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
617 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
620 /* initialise a dcerpc pipe. */
621 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p,
622 const struct GUID *object,
623 const struct ndr_interface_table *table)
625 struct dcerpc_binding_handle *h;
626 struct dcerpc_bh_state *hs;
628 h = dcerpc_binding_handle_create(p,
629 &dcerpc_bh_ops,
630 object,
631 table,
632 &hs,
633 struct dcerpc_bh_state,
634 __location__);
635 if (h == NULL) {
636 return NULL;
638 hs->p = p;
640 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
642 return h;
645 /* initialise a dcerpc pipe. */
646 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
648 struct dcerpc_pipe *p;
650 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
651 if (!p) {
652 return NULL;
655 p->conn = dcerpc_connection_init(p, ev);
656 if (p->conn == NULL) {
657 talloc_free(p);
658 return NULL;
661 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
663 if (DEBUGLVL(100)) {
664 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
667 return p;
672 choose the next call id to use
674 static uint32_t next_call_id(struct dcecli_connection *c)
676 c->call_id++;
677 if (c->call_id == 0) {
678 c->call_id++;
680 return c->call_id;
684 setup for a ndr pull, also setting up any flags from the binding string
686 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
687 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
689 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
691 if (ndr == NULL) return ndr;
693 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
694 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
697 if (c->flags & DCERPC_NDR_REF_ALLOC) {
698 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
701 if (c->flags & DCERPC_NDR64) {
702 ndr->flags |= LIBNDR_FLAG_NDR64;
705 return ndr;
709 parse the authentication information on a dcerpc response packet
711 static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
712 TALLOC_CTX *mem_ctx,
713 enum dcerpc_pkt_type ptype,
714 uint8_t required_flags,
715 uint8_t optional_flags,
716 uint8_t payload_offset,
717 DATA_BLOB *payload_and_verifier,
718 DATA_BLOB *raw_packet,
719 const struct ncacn_packet *pkt)
721 const struct dcerpc_auth tmp_auth = {
722 .auth_type = c->security_state.auth_type,
723 .auth_level = c->security_state.auth_level,
724 .auth_context_id = c->security_state.auth_context_id,
726 NTSTATUS status;
728 status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
729 c->security_state.generic_state,
730 true, /* check_pkt_auth_fields */
731 mem_ctx,
732 ptype,
733 required_flags,
734 optional_flags,
735 payload_offset,
736 payload_and_verifier,
737 raw_packet,
738 pkt);
739 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
740 return NT_STATUS_INVALID_NETWORK_RESPONSE;
742 if (!NT_STATUS_IS_OK(status)) {
743 return status;
746 return NT_STATUS_OK;
751 push a dcerpc request packet into a blob, possibly signing it.
753 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
754 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
755 size_t sig_size,
756 struct ncacn_packet *pkt)
758 const struct dcerpc_auth tmp_auth = {
759 .auth_type = c->security_state.auth_type,
760 .auth_level = c->security_state.auth_level,
761 .auth_context_id = c->security_state.auth_context_id,
763 NTSTATUS status;
764 uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
766 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
767 payload_offset += 16;
770 status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
771 c->security_state.generic_state,
772 mem_ctx, blob,
773 sig_size,
774 payload_offset,
775 &pkt->u.request.stub_and_verifier,
776 pkt);
777 if (!NT_STATUS_IS_OK(status)) {
778 return status;
781 return NT_STATUS_OK;
786 fill in the fixed values in a dcerpc header
788 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
790 pkt->rpc_vers = 5;
791 pkt->rpc_vers_minor = 0;
792 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
793 pkt->drep[0] = 0;
794 } else {
795 pkt->drep[0] = DCERPC_DREP_LE;
797 pkt->drep[1] = 0;
798 pkt->drep[2] = 0;
799 pkt->drep[3] = 0;
803 map a bind nak reason to a NTSTATUS
805 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
807 switch (reason) {
808 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
809 return NT_STATUS_REVISION_MISMATCH;
810 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
811 return NT_STATUS_INVALID_PARAMETER;
812 default:
813 break;
815 return NT_STATUS_UNSUCCESSFUL;
818 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
820 if (ack == NULL) {
821 return NT_STATUS_RPC_PROTOCOL_ERROR;
824 switch (ack->result) {
825 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
827 * We have not asked for this...
829 return NT_STATUS_RPC_PROTOCOL_ERROR;
830 default:
831 break;
834 switch (ack->reason.value) {
835 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
836 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
837 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
838 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
839 default:
840 break;
842 return NT_STATUS_UNSUCCESSFUL;
846 remove requests from the pending or queued queues
848 static int dcerpc_req_dequeue(struct rpc_request *req)
850 switch (req->state) {
851 case RPC_REQUEST_QUEUED:
852 DLIST_REMOVE(req->p->conn->request_queue, req);
853 break;
854 case RPC_REQUEST_PENDING:
855 DLIST_REMOVE(req->p->conn->pending, req);
856 break;
857 case RPC_REQUEST_DONE:
858 break;
860 return 0;
865 mark the dcerpc connection dead. All outstanding requests get an error
867 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
869 if (conn->dead) return;
871 conn->dead = true;
873 TALLOC_FREE(conn->io_trigger);
874 conn->io_trigger_pending = false;
876 dcerpc_shutdown_pipe(conn, status);
878 /* all pending requests get the error */
879 while (conn->pending) {
880 struct rpc_request *req = conn->pending;
881 dcerpc_req_dequeue(req);
882 req->state = RPC_REQUEST_DONE;
883 req->status = status;
884 if (req->async.callback) {
885 req->async.callback(req);
889 /* all requests, which are not shipped */
890 while (conn->request_queue) {
891 struct rpc_request *req = conn->request_queue;
892 dcerpc_req_dequeue(req);
893 req->state = RPC_REQUEST_DONE;
894 req->status = status;
895 if (req->async.callback) {
896 req->async.callback(req);
900 talloc_set_destructor(conn, NULL);
901 if (conn->free_skipped) {
902 talloc_free(conn);
907 forward declarations of the recv_data handlers for the types of
908 packets we need to handle
910 static void dcerpc_request_recv_data(struct dcecli_connection *c,
911 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
914 receive a dcerpc reply from the transport. Here we work out what
915 type of reply it is (normal request, bind or alter context) and
916 dispatch to the appropriate handler
918 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
920 struct ncacn_packet pkt;
922 if (conn->dead) {
923 return;
926 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
927 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
930 /* the transport may be telling us of a severe error, such as
931 a dropped socket */
932 if (!NT_STATUS_IS_OK(status)) {
933 data_blob_free(blob);
934 dcerpc_connection_dead(conn, status);
935 return;
938 /* parse the basic packet to work out what type of response this is */
939 status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
940 if (!NT_STATUS_IS_OK(status)) {
941 data_blob_free(blob);
942 dcerpc_connection_dead(conn, status);
943 return;
946 dcerpc_request_recv_data(conn, blob, &pkt);
950 handle timeouts of individual dcerpc requests
952 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
953 struct timeval t, void *private_data)
955 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
957 if (req->ignore_timeout) {
958 dcerpc_req_dequeue(req);
959 req->state = RPC_REQUEST_DONE;
960 req->status = NT_STATUS_IO_TIMEOUT;
961 if (req->async.callback) {
962 req->async.callback(req);
964 return;
967 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
970 struct dcerpc_bind_state {
971 struct tevent_context *ev;
972 struct dcerpc_pipe *p;
975 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
976 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
977 DATA_BLOB *raw_packet,
978 struct ncacn_packet *pkt);
980 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
981 struct tevent_context *ev,
982 struct dcerpc_pipe *p,
983 const struct ndr_syntax_id *syntax,
984 const struct ndr_syntax_id *transfer_syntax)
986 struct tevent_req *req;
987 struct dcerpc_bind_state *state;
988 struct ncacn_packet pkt;
989 DATA_BLOB blob;
990 NTSTATUS status;
991 struct rpc_request *subreq;
992 uint32_t flags;
993 struct ndr_syntax_id bind_time_features;
995 bind_time_features = dcerpc_construct_bind_time_features(
996 DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
997 DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
999 req = tevent_req_create(mem_ctx, &state,
1000 struct dcerpc_bind_state);
1001 if (req == NULL) {
1002 return NULL;
1005 state->ev = ev;
1006 state->p = p;
1008 p->syntax = *syntax;
1009 p->transfer_syntax = *transfer_syntax;
1011 flags = dcerpc_binding_get_flags(p->binding);
1013 init_ncacn_hdr(p->conn, &pkt);
1015 pkt.ptype = DCERPC_PKT_BIND;
1016 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1017 pkt.call_id = p->conn->call_id;
1018 pkt.auth_length = 0;
1020 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1021 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1024 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1025 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1028 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1029 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1030 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1031 pkt.u.bind.num_contexts = 2;
1032 pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
1033 pkt.u.bind.num_contexts);
1034 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1035 return tevent_req_post(req, ev);
1037 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1038 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1039 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1040 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1041 pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
1042 pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
1043 pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
1044 pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
1045 pkt.u.bind.auth_info = data_blob(NULL, 0);
1047 /* construct the NDR form of the packet */
1048 status = dcerpc_ncacn_push_auth(&blob,
1049 state,
1050 &pkt,
1051 p->conn->security_state.tmp_auth_info.out);
1052 if (tevent_req_nterror(req, status)) {
1053 return tevent_req_post(req, ev);
1057 * we allocate a dcerpc_request so we can be in the same
1058 * request queue as normal requests
1060 subreq = talloc_zero(state, struct rpc_request);
1061 if (tevent_req_nomem(subreq, req)) {
1062 return tevent_req_post(req, ev);
1065 subreq->state = RPC_REQUEST_PENDING;
1066 subreq->call_id = pkt.call_id;
1067 subreq->async.private_data = req;
1068 subreq->async.callback = dcerpc_bind_fail_handler;
1069 subreq->p = p;
1070 subreq->recv_handler = dcerpc_bind_recv_handler;
1071 DLIST_ADD_END(p->conn->pending, subreq);
1072 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1074 status = dcerpc_send_request(p->conn, &blob, true);
1075 if (tevent_req_nterror(req, status)) {
1076 return tevent_req_post(req, ev);
1079 tevent_add_timer(ev, subreq,
1080 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1081 dcerpc_timeout_handler, subreq);
1083 return req;
1086 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1088 struct tevent_req *req =
1089 talloc_get_type_abort(subreq->async.private_data,
1090 struct tevent_req);
1091 struct dcerpc_bind_state *state =
1092 tevent_req_data(req,
1093 struct dcerpc_bind_state);
1094 NTSTATUS status = subreq->status;
1096 TALLOC_FREE(subreq);
1099 * We trigger the callback in the next event run
1100 * because the code in this file might trigger
1101 * multiple request callbacks from within a single
1102 * while loop.
1104 * In order to avoid segfaults from within
1105 * dcerpc_connection_dead() we call
1106 * tevent_req_defer_callback().
1108 tevent_req_defer_callback(req, state->ev);
1110 tevent_req_nterror(req, status);
1113 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1114 DATA_BLOB *raw_packet,
1115 struct ncacn_packet *pkt)
1117 struct tevent_req *req =
1118 talloc_get_type_abort(subreq->async.private_data,
1119 struct tevent_req);
1120 struct dcerpc_bind_state *state =
1121 tevent_req_data(req,
1122 struct dcerpc_bind_state);
1123 struct dcecli_connection *conn = state->p->conn;
1124 struct dcecli_security *sec = &conn->security_state;
1125 struct dcerpc_binding *b = NULL;
1126 NTSTATUS status;
1127 uint32_t flags;
1130 * Note that pkt is allocated under raw_packet->data,
1131 * while raw_packet->data is a child of subreq.
1133 talloc_steal(state, raw_packet->data);
1134 TALLOC_FREE(subreq);
1137 * We trigger the callback in the next event run
1138 * because the code in this file might trigger
1139 * multiple request callbacks from within a single
1140 * while loop.
1142 * In order to avoid segfaults from within
1143 * dcerpc_connection_dead() we call
1144 * tevent_req_defer_callback().
1146 tevent_req_defer_callback(req, state->ev);
1148 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1149 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1151 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1152 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1154 tevent_req_nterror(req, status);
1155 return;
1158 status = dcerpc_verify_ncacn_packet_header(pkt,
1159 DCERPC_PKT_BIND_ACK,
1160 pkt->u.bind_ack.auth_info.length,
1161 DCERPC_PFC_FLAG_FIRST |
1162 DCERPC_PFC_FLAG_LAST,
1163 DCERPC_PFC_FLAG_CONC_MPX |
1164 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1165 if (!NT_STATUS_IS_OK(status)) {
1166 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1167 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1168 return;
1171 if (pkt->u.bind_ack.num_results < 1) {
1172 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1173 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1174 return;
1177 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1178 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1179 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1180 pkt->u.bind_ack.ctx_list[0].reason.value,
1181 nt_errstr(status)));
1182 tevent_req_nterror(req, status);
1183 return;
1186 if (pkt->u.bind_ack.num_results >= 2) {
1187 if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1188 conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
1189 } else {
1190 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
1191 DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
1192 pkt->u.bind_ack.ctx_list[1].reason.value,
1193 nt_errstr(status)));
1194 status = NT_STATUS_OK;
1199 * DCE-RPC 1.1 (c706) specifies
1200 * CONST_MUST_RCV_FRAG_SIZE as 1432
1202 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1203 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1204 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1205 return;
1207 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1208 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1209 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1210 return;
1212 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1213 pkt->u.bind_ack.max_xmit_frag);
1214 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1215 pkt->u.bind_ack.max_recv_frag);
1217 flags = dcerpc_binding_get_flags(state->p->binding);
1219 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1220 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1221 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1222 } else {
1223 conn->flags &= ~DCERPC_CONCURRENT_MULTIPLEX;
1227 if (!(conn->flags & DCERPC_CONCURRENT_MULTIPLEX)) {
1228 struct dcerpc_binding *pb =
1229 discard_const_p(struct dcerpc_binding, state->p->binding);
1231 * clear DCERPC_CONCURRENT_MULTIPLEX
1233 status = dcerpc_binding_set_flags(pb, 0,
1234 DCERPC_CONCURRENT_MULTIPLEX);
1235 if (tevent_req_nterror(req, status)) {
1236 return;
1239 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1240 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1241 conn->flags |= DCERPC_HEADER_SIGNING;
1244 /* the bind_ack might contain a reply set of credentials */
1245 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1246 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1247 &pkt->u.bind_ack.auth_info,
1248 sec->tmp_auth_info.in,
1249 NULL, true);
1250 if (tevent_req_nterror(req, status)) {
1251 return;
1256 * We're the owner of the binding, so we're allowed to modify it.
1258 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1259 status = dcerpc_binding_set_assoc_group_id(b,
1260 pkt->u.bind_ack.assoc_group_id);
1261 if (tevent_req_nterror(req, status)) {
1262 return;
1265 tevent_req_done(req);
1268 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1270 return tevent_req_simple_recv_ntstatus(req);
1274 perform a continued bind (and auth3)
1276 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1277 TALLOC_CTX *mem_ctx)
1279 struct ncacn_packet pkt;
1280 NTSTATUS status;
1281 DATA_BLOB blob;
1282 uint32_t flags;
1284 flags = dcerpc_binding_get_flags(p->binding);
1286 init_ncacn_hdr(p->conn, &pkt);
1288 pkt.ptype = DCERPC_PKT_AUTH3;
1289 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1290 pkt.call_id = next_call_id(p->conn);
1291 pkt.auth_length = 0;
1292 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1294 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1295 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1298 /* construct the NDR form of the packet */
1299 status = dcerpc_ncacn_push_auth(&blob,
1300 mem_ctx,
1301 &pkt,
1302 p->conn->security_state.tmp_auth_info.out);
1303 if (!NT_STATUS_IS_OK(status)) {
1304 return status;
1307 /* send it on its way */
1308 status = dcerpc_send_request(p->conn, &blob, false);
1309 if (!NT_STATUS_IS_OK(status)) {
1310 return status;
1313 return NT_STATUS_OK;
1318 process a fragment received from the transport layer during a
1319 request
1321 This function frees the data
1323 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1324 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1326 struct rpc_request *req;
1327 unsigned int length;
1328 NTSTATUS status = NT_STATUS_OK;
1331 if this is an authenticated connection then parse and check
1332 the auth info. We have to do this before finding the
1333 matching packet, as the request structure might have been
1334 removed due to a timeout, but if it has been we still need
1335 to run the auth routines so that we don't get the sign/seal
1336 info out of step with the server
1338 switch (pkt->ptype) {
1339 case DCERPC_PKT_RESPONSE:
1340 status = ncacn_pull_pkt_auth(c, raw_packet->data,
1341 DCERPC_PKT_RESPONSE,
1342 0, /* required_flags */
1343 DCERPC_PFC_FLAG_FIRST |
1344 DCERPC_PFC_FLAG_LAST,
1345 DCERPC_REQUEST_LENGTH,
1346 &pkt->u.response.stub_and_verifier,
1347 raw_packet, pkt);
1348 break;
1349 default:
1350 break;
1353 /* find the matching request */
1354 for (req=c->pending;req;req=req->next) {
1355 if (pkt->call_id == req->call_id) break;
1358 #if 0
1359 /* useful for testing certain vendors RPC servers */
1360 if (req == NULL && c->pending && pkt->call_id == 0) {
1361 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1362 req = c->pending;
1364 #endif
1366 if (req == NULL) {
1367 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1368 data_blob_free(raw_packet);
1369 return;
1372 talloc_steal(req, raw_packet->data);
1374 if (req->recv_handler != NULL) {
1375 dcerpc_req_dequeue(req);
1376 req->state = RPC_REQUEST_DONE;
1379 * We have to look at shipping further requests before calling
1380 * the async function, that one might close the pipe
1382 dcerpc_schedule_io_trigger(c);
1384 req->recv_handler(req, raw_packet, pkt);
1385 return;
1388 if (pkt->ptype == DCERPC_PKT_FAULT) {
1389 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1390 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1391 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1392 dcerpc_connection_dead(c, status);
1393 return;
1395 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1396 dcerpc_connection_dead(c, status);
1397 return;
1399 req->fault_code = pkt->u.fault.status;
1400 req->status = NT_STATUS_NET_WRITE_FAULT;
1401 goto req_done;
1404 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1405 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1406 (int)pkt->ptype));
1407 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1408 return;
1411 /* now check the status from the auth routines, and if it failed then fail
1412 this request accordingly */
1413 if (!NT_STATUS_IS_OK(status)) {
1414 dcerpc_connection_dead(c, status);
1415 return;
1418 length = pkt->u.response.stub_and_verifier.length;
1420 if (req->payload.length + length > c->max_total_response_size) {
1421 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1422 (unsigned)req->payload.length + length,
1423 (unsigned)c->max_total_response_size));
1424 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1425 return;
1428 if (length > 0) {
1429 req->payload.data = talloc_realloc(req,
1430 req->payload.data,
1431 uint8_t,
1432 req->payload.length + length);
1433 if (!req->payload.data) {
1434 req->status = NT_STATUS_NO_MEMORY;
1435 goto req_done;
1437 memcpy(req->payload.data+req->payload.length,
1438 pkt->u.response.stub_and_verifier.data, length);
1439 req->payload.length += length;
1442 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1443 data_blob_free(raw_packet);
1444 dcerpc_send_read(c);
1445 return;
1448 if (req->verify_bitmask1) {
1449 req->p->conn->security_state.verified_bitmask1 = true;
1451 if (req->verify_pcontext) {
1452 req->p->verified_pcontext = true;
1455 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1456 req->flags |= DCERPC_PULL_BIGENDIAN;
1457 } else {
1458 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1461 req_done:
1462 data_blob_free(raw_packet);
1464 /* we've got the full payload */
1465 dcerpc_req_dequeue(req);
1466 req->state = RPC_REQUEST_DONE;
1469 * We have to look at shipping further requests before calling
1470 * the async function, that one might close the pipe
1472 dcerpc_schedule_io_trigger(c);
1474 if (req->async.callback) {
1475 req->async.callback(req);
1479 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1482 perform the send side of a async dcerpc request
1484 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1485 struct dcerpc_pipe *p,
1486 const struct GUID *object,
1487 uint16_t opnum,
1488 DATA_BLOB *stub_data)
1490 struct rpc_request *req;
1491 NTSTATUS status;
1493 req = talloc_zero(mem_ctx, struct rpc_request);
1494 if (req == NULL) {
1495 return NULL;
1498 req->p = p;
1499 req->call_id = next_call_id(p->conn);
1500 req->state = RPC_REQUEST_QUEUED;
1502 if (object != NULL) {
1503 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1504 if (req->object == NULL) {
1505 talloc_free(req);
1506 return NULL;
1510 req->opnum = opnum;
1511 req->request_data.length = stub_data->length;
1512 req->request_data.data = stub_data->data;
1514 status = dcerpc_request_prepare_vt(req);
1515 if (!NT_STATUS_IS_OK(status)) {
1516 talloc_free(req);
1517 return NULL;
1520 DLIST_ADD_END(p->conn->request_queue, req);
1521 talloc_set_destructor(req, dcerpc_req_dequeue);
1523 dcerpc_schedule_io_trigger(p->conn);
1525 if (p->request_timeout) {
1526 tevent_add_timer(p->conn->event_ctx, req,
1527 timeval_current_ofs(p->request_timeout, 0),
1528 dcerpc_timeout_handler, req);
1531 return req;
1534 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1536 struct dcecli_security *sec = &req->p->conn->security_state;
1537 struct dcerpc_sec_verification_trailer *t;
1538 struct dcerpc_sec_vt *c = NULL;
1539 struct ndr_push *ndr = NULL;
1540 enum ndr_err_code ndr_err;
1542 if (sec->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1543 return NT_STATUS_OK;
1546 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1547 if (t == NULL) {
1548 return NT_STATUS_NO_MEMORY;
1551 if (!sec->verified_bitmask1) {
1552 t->commands = talloc_realloc(t, t->commands,
1553 struct dcerpc_sec_vt,
1554 t->count.count + 1);
1555 if (t->commands == NULL) {
1556 return NT_STATUS_NO_MEMORY;
1558 c = &t->commands[t->count.count++];
1559 ZERO_STRUCTP(c);
1561 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1562 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1563 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1565 req->verify_bitmask1 = true;
1568 if (!req->p->verified_pcontext) {
1569 t->commands = talloc_realloc(t, t->commands,
1570 struct dcerpc_sec_vt,
1571 t->count.count + 1);
1572 if (t->commands == NULL) {
1573 return NT_STATUS_NO_MEMORY;
1575 c = &t->commands[t->count.count++];
1576 ZERO_STRUCTP(c);
1578 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1579 c->u.pcontext.abstract_syntax = req->p->syntax;
1580 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1582 req->verify_pcontext = true;
1585 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1586 t->commands = talloc_realloc(t, t->commands,
1587 struct dcerpc_sec_vt,
1588 t->count.count + 1);
1589 if (t->commands == NULL) {
1590 return NT_STATUS_NO_MEMORY;
1592 c = &t->commands[t->count.count++];
1593 ZERO_STRUCTP(c);
1595 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1596 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1597 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1598 c->u.header2.drep[0] = 0;
1599 } else {
1600 c->u.header2.drep[0] = DCERPC_DREP_LE;
1602 c->u.header2.drep[1] = 0;
1603 c->u.header2.drep[2] = 0;
1604 c->u.header2.drep[3] = 0;
1605 c->u.header2.call_id = req->call_id;
1606 c->u.header2.context_id = req->p->context_id;
1607 c->u.header2.opnum = req->opnum;
1610 if (t->count.count == 0) {
1611 TALLOC_FREE(t);
1612 return NT_STATUS_OK;
1615 c = &t->commands[t->count.count - 1];
1616 c->command |= DCERPC_SEC_VT_COMMAND_END;
1618 if (DEBUGLEVEL >= 10) {
1619 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1622 ndr = ndr_push_init_ctx(req);
1623 if (ndr == NULL) {
1624 return NT_STATUS_NO_MEMORY;
1628 * for now we just copy and append
1631 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1632 req->request_data.length);
1633 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1634 return ndr_map_error2ntstatus(ndr_err);
1637 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1638 NDR_SCALARS | NDR_BUFFERS,
1640 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1641 return ndr_map_error2ntstatus(ndr_err);
1643 req->request_data = ndr_push_blob(ndr);
1645 return NT_STATUS_OK;
1649 Send a request using the transport
1652 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1654 struct rpc_request *req;
1655 struct dcerpc_pipe *p;
1656 DATA_BLOB *stub_data;
1657 struct ncacn_packet pkt;
1658 DATA_BLOB blob;
1659 uint32_t remaining, chunk_size;
1660 bool first_packet = true;
1661 size_t sig_size = 0;
1662 bool need_async = false;
1663 bool can_async = true;
1665 req = c->request_queue;
1666 if (req == NULL) {
1667 return;
1670 p = req->p;
1671 stub_data = &req->request_data;
1673 if (c->pending) {
1674 need_async = true;
1677 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1678 can_async = gensec_have_feature(c->security_state.generic_state,
1679 GENSEC_FEATURE_ASYNC_REPLIES);
1682 if (need_async && !can_async) {
1683 req->wait_for_sync = true;
1684 return;
1687 DLIST_REMOVE(c->request_queue, req);
1688 DLIST_ADD(c->pending, req);
1689 req->state = RPC_REQUEST_PENDING;
1691 init_ncacn_hdr(p->conn, &pkt);
1693 remaining = stub_data->length;
1695 /* we can write a full max_recv_frag size, minus the dcerpc
1696 request header size */
1697 chunk_size = p->conn->srv_max_recv_frag;
1698 chunk_size -= DCERPC_REQUEST_LENGTH;
1699 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1700 size_t max_payload = chunk_size;
1702 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1703 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1705 sig_size = gensec_sig_size(c->security_state.generic_state,
1706 max_payload);
1707 if (sig_size) {
1708 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1709 chunk_size -= sig_size;
1712 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1714 pkt.ptype = DCERPC_PKT_REQUEST;
1715 pkt.call_id = req->call_id;
1716 pkt.auth_length = 0;
1717 pkt.pfc_flags = 0;
1718 pkt.u.request.context_id = p->context_id;
1719 pkt.u.request.opnum = req->opnum;
1721 if (req->object) {
1722 pkt.u.request.object.object = *req->object;
1723 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1724 chunk_size -= ndr_size_GUID(req->object,0);
1727 /* we send a series of pdus without waiting for a reply */
1728 while (remaining > 0 || first_packet) {
1729 uint32_t chunk = MIN(chunk_size, remaining);
1730 bool last_frag = false;
1731 bool do_trans = false;
1733 first_packet = false;
1734 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1736 if (remaining == stub_data->length) {
1737 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1739 if (chunk == remaining) {
1740 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1741 last_frag = true;
1744 pkt.u.request.alloc_hint = remaining;
1745 pkt.u.request.stub_and_verifier.data = stub_data->data +
1746 (stub_data->length - remaining);
1747 pkt.u.request.stub_and_verifier.length = chunk;
1749 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1750 if (!NT_STATUS_IS_OK(req->status)) {
1751 req->state = RPC_REQUEST_DONE;
1752 DLIST_REMOVE(p->conn->pending, req);
1753 return;
1756 if (last_frag && !need_async) {
1757 do_trans = true;
1760 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1761 if (!NT_STATUS_IS_OK(req->status)) {
1762 req->state = RPC_REQUEST_DONE;
1763 DLIST_REMOVE(p->conn->pending, req);
1764 return;
1767 if (last_frag && !do_trans) {
1768 req->status = dcerpc_send_read(p->conn);
1769 if (!NT_STATUS_IS_OK(req->status)) {
1770 req->state = RPC_REQUEST_DONE;
1771 DLIST_REMOVE(p->conn->pending, req);
1772 return;
1776 remaining -= chunk;
1780 static void dcerpc_io_trigger(struct tevent_context *ctx,
1781 struct tevent_immediate *im,
1782 void *private_data)
1784 struct dcecli_connection *c =
1785 talloc_get_type_abort(private_data,
1786 struct dcecli_connection);
1788 c->io_trigger_pending = false;
1790 dcerpc_schedule_io_trigger(c);
1792 dcerpc_ship_next_request(c);
1795 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1797 if (c->dead) {
1798 return;
1801 if (c->request_queue == NULL) {
1802 return;
1805 if (c->request_queue->wait_for_sync && c->pending) {
1806 return;
1809 if (c->io_trigger_pending) {
1810 return;
1813 c->io_trigger_pending = true;
1815 tevent_schedule_immediate(c->io_trigger,
1816 c->event_ctx,
1817 dcerpc_io_trigger,
1822 perform the receive side of a async dcerpc request
1824 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1825 TALLOC_CTX *mem_ctx,
1826 DATA_BLOB *stub_data)
1828 NTSTATUS status;
1830 while (req->state != RPC_REQUEST_DONE) {
1831 struct tevent_context *ctx = req->p->conn->event_ctx;
1832 if (tevent_loop_once(ctx) != 0) {
1833 return NT_STATUS_CONNECTION_DISCONNECTED;
1836 *stub_data = req->payload;
1837 status = req->status;
1838 if (stub_data->data) {
1839 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1841 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1842 req->p->last_fault_code = req->fault_code;
1844 talloc_unlink(talloc_parent(req), req);
1845 return status;
1849 this is a paranoid NDR validator. For every packet we push onto the wire
1850 we pull it back again, then push it again. Then we compare the raw NDR data
1851 for that to the NDR we initially generated. If they don't match then we know
1852 we must have a bug in either the pull or push side of our code
1854 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1855 TALLOC_CTX *mem_ctx,
1856 DATA_BLOB blob,
1857 size_t struct_size,
1858 ndr_push_flags_fn_t ndr_push,
1859 ndr_pull_flags_fn_t ndr_pull)
1861 void *st;
1862 struct ndr_pull *pull;
1863 struct ndr_push *push;
1864 DATA_BLOB blob2;
1865 enum ndr_err_code ndr_err;
1867 st = talloc_size(mem_ctx, struct_size);
1868 if (!st) {
1869 return NT_STATUS_NO_MEMORY;
1872 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1873 if (!pull) {
1874 return NT_STATUS_NO_MEMORY;
1876 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1878 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1879 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1882 if (c->flags & DCERPC_NDR64) {
1883 pull->flags |= LIBNDR_FLAG_NDR64;
1886 ndr_err = ndr_pull(pull, NDR_IN, st);
1887 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1888 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1889 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1890 "failed input validation pull - %s",
1891 nt_errstr(status));
1892 return ndr_map_error2ntstatus(ndr_err);
1895 push = ndr_push_init_ctx(mem_ctx);
1896 if (!push) {
1897 return NT_STATUS_NO_MEMORY;
1900 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1901 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1904 if (c->flags & DCERPC_NDR64) {
1905 push->flags |= LIBNDR_FLAG_NDR64;
1908 ndr_err = ndr_push(push, NDR_IN, st);
1909 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1910 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1911 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1912 "failed input validation push - %s",
1913 nt_errstr(status));
1914 return ndr_map_error2ntstatus(ndr_err);
1917 blob2 = ndr_push_blob(push);
1919 if (data_blob_cmp(&blob, &blob2) != 0) {
1920 DEBUG(3,("original:\n"));
1921 dump_data(3, blob.data, blob.length);
1922 DEBUG(3,("secondary:\n"));
1923 dump_data(3, blob2.data, blob2.length);
1924 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1925 "failed input validation blobs doesn't match");
1926 return ndr_map_error2ntstatus(ndr_err);
1929 return NT_STATUS_OK;
1933 this is a paranoid NDR input validator. For every packet we pull
1934 from the wire we push it back again then pull and push it
1935 again. Then we compare the raw NDR data for that to the NDR we
1936 initially generated. If they don't match then we know we must have a
1937 bug in either the pull or push side of our code
1939 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1940 struct ndr_pull *pull_in,
1941 void *struct_ptr,
1942 size_t struct_size,
1943 ndr_push_flags_fn_t ndr_push,
1944 ndr_pull_flags_fn_t ndr_pull,
1945 ndr_print_function_t ndr_print)
1947 void *st;
1948 struct ndr_pull *pull;
1949 struct ndr_push *push;
1950 DATA_BLOB blob, blob2;
1951 TALLOC_CTX *mem_ctx = pull_in;
1952 char *s1, *s2;
1953 enum ndr_err_code ndr_err;
1955 st = talloc_size(mem_ctx, struct_size);
1956 if (!st) {
1957 return NT_STATUS_NO_MEMORY;
1959 memcpy(st, struct_ptr, struct_size);
1961 push = ndr_push_init_ctx(mem_ctx);
1962 if (!push) {
1963 return NT_STATUS_NO_MEMORY;
1966 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1967 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1968 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1969 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1970 "failed output validation push - %s",
1971 nt_errstr(status));
1972 return ndr_map_error2ntstatus(ndr_err);
1975 blob = ndr_push_blob(push);
1977 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1978 if (!pull) {
1979 return NT_STATUS_NO_MEMORY;
1982 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1983 ndr_err = ndr_pull(pull, NDR_OUT, st);
1984 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1985 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1986 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1987 "failed output validation pull - %s",
1988 nt_errstr(status));
1989 return ndr_map_error2ntstatus(ndr_err);
1992 push = ndr_push_init_ctx(mem_ctx);
1993 if (!push) {
1994 return NT_STATUS_NO_MEMORY;
1997 ndr_err = ndr_push(push, NDR_OUT, st);
1998 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1999 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2000 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2001 "failed output validation push2 - %s",
2002 nt_errstr(status));
2003 return ndr_map_error2ntstatus(ndr_err);
2006 blob2 = ndr_push_blob(push);
2008 if (data_blob_cmp(&blob, &blob2) != 0) {
2009 DEBUG(3,("original:\n"));
2010 dump_data(3, blob.data, blob.length);
2011 DEBUG(3,("secondary:\n"));
2012 dump_data(3, blob2.data, blob2.length);
2013 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2014 "failed output validation blobs doesn't match");
2015 return ndr_map_error2ntstatus(ndr_err);
2018 /* this checks the printed forms of the two structures, which effectively
2019 tests all of the value() attributes */
2020 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2021 NDR_OUT, struct_ptr);
2022 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2023 NDR_OUT, st);
2024 if (strcmp(s1, s2) != 0) {
2025 #if 1
2026 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2027 #else
2028 /* this is sometimes useful */
2029 printf("VALIDATE ERROR\n");
2030 file_save("wire.dat", s1, strlen(s1));
2031 file_save("gen.dat", s2, strlen(s2));
2032 system("diff -u wire.dat gen.dat");
2033 #endif
2034 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2035 "failed output validation strings doesn't match");
2036 return ndr_map_error2ntstatus(ndr_err);
2039 return NT_STATUS_OK;
2043 a useful function for retrieving the server name we connected to
2045 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2047 return p->conn ? p->conn->server_name : NULL;
2052 get the dcerpc auth_level for a open connection
2054 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2056 uint8_t auth_level;
2058 if (c->flags & DCERPC_SEAL) {
2059 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2060 } else if (c->flags & DCERPC_SIGN) {
2061 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2062 } else if (c->flags & DCERPC_PACKET) {
2063 auth_level = DCERPC_AUTH_LEVEL_PACKET;
2064 } else if (c->flags & DCERPC_CONNECT) {
2065 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2066 } else {
2067 auth_level = DCERPC_AUTH_LEVEL_NONE;
2069 return auth_level;
2072 struct dcerpc_alter_context_state {
2073 struct tevent_context *ev;
2074 struct dcerpc_pipe *p;
2077 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2078 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2079 DATA_BLOB *raw_packet,
2080 struct ncacn_packet *pkt);
2082 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2083 struct tevent_context *ev,
2084 struct dcerpc_pipe *p,
2085 const struct ndr_syntax_id *syntax,
2086 const struct ndr_syntax_id *transfer_syntax)
2088 struct tevent_req *req;
2089 struct dcerpc_alter_context_state *state;
2090 struct ncacn_packet pkt;
2091 DATA_BLOB blob;
2092 NTSTATUS status;
2093 struct rpc_request *subreq;
2094 uint32_t flags;
2096 req = tevent_req_create(mem_ctx, &state,
2097 struct dcerpc_alter_context_state);
2098 if (req == NULL) {
2099 return NULL;
2102 state->ev = ev;
2103 state->p = p;
2105 p->syntax = *syntax;
2106 p->transfer_syntax = *transfer_syntax;
2108 flags = dcerpc_binding_get_flags(p->binding);
2110 init_ncacn_hdr(p->conn, &pkt);
2112 pkt.ptype = DCERPC_PKT_ALTER;
2113 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2114 pkt.call_id = p->conn->call_id;
2115 pkt.auth_length = 0;
2117 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2118 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2121 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2122 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2123 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2124 pkt.u.alter.num_contexts = 1;
2125 pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
2126 pkt.u.alter.num_contexts);
2127 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2128 return tevent_req_post(req, ev);
2130 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2131 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2132 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2133 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2134 pkt.u.alter.auth_info = data_blob(NULL, 0);
2136 /* construct the NDR form of the packet */
2137 status = dcerpc_ncacn_push_auth(&blob,
2138 state,
2139 &pkt,
2140 p->conn->security_state.tmp_auth_info.out);
2141 if (tevent_req_nterror(req, status)) {
2142 return tevent_req_post(req, ev);
2146 * we allocate a dcerpc_request so we can be in the same
2147 * request queue as normal requests
2149 subreq = talloc_zero(state, struct rpc_request);
2150 if (tevent_req_nomem(subreq, req)) {
2151 return tevent_req_post(req, ev);
2154 subreq->state = RPC_REQUEST_PENDING;
2155 subreq->call_id = pkt.call_id;
2156 subreq->async.private_data = req;
2157 subreq->async.callback = dcerpc_alter_context_fail_handler;
2158 subreq->p = p;
2159 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2160 DLIST_ADD_END(p->conn->pending, subreq);
2161 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2163 status = dcerpc_send_request(p->conn, &blob, true);
2164 if (tevent_req_nterror(req, status)) {
2165 return tevent_req_post(req, ev);
2168 tevent_add_timer(ev, subreq,
2169 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2170 dcerpc_timeout_handler, subreq);
2172 return req;
2175 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2177 struct tevent_req *req =
2178 talloc_get_type_abort(subreq->async.private_data,
2179 struct tevent_req);
2180 struct dcerpc_alter_context_state *state =
2181 tevent_req_data(req,
2182 struct dcerpc_alter_context_state);
2183 NTSTATUS status = subreq->status;
2185 TALLOC_FREE(subreq);
2188 * We trigger the callback in the next event run
2189 * because the code in this file might trigger
2190 * multiple request callbacks from within a single
2191 * while loop.
2193 * In order to avoid segfaults from within
2194 * dcerpc_connection_dead() we call
2195 * tevent_req_defer_callback().
2197 tevent_req_defer_callback(req, state->ev);
2199 tevent_req_nterror(req, status);
2202 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2203 DATA_BLOB *raw_packet,
2204 struct ncacn_packet *pkt)
2206 struct tevent_req *req =
2207 talloc_get_type_abort(subreq->async.private_data,
2208 struct tevent_req);
2209 struct dcerpc_alter_context_state *state =
2210 tevent_req_data(req,
2211 struct dcerpc_alter_context_state);
2212 struct dcecli_connection *conn = state->p->conn;
2213 struct dcecli_security *sec = &conn->security_state;
2214 NTSTATUS status;
2217 * Note that pkt is allocated under raw_packet->data,
2218 * while raw_packet->data is a child of subreq.
2220 talloc_steal(state, raw_packet->data);
2221 TALLOC_FREE(subreq);
2224 * We trigger the callback in the next event run
2225 * because the code in this file might trigger
2226 * multiple request callbacks from within a single
2227 * while loop.
2229 * In order to avoid segfaults from within
2230 * dcerpc_connection_dead() we call
2231 * tevent_req_defer_callback().
2233 tevent_req_defer_callback(req, state->ev);
2235 if (pkt->ptype == DCERPC_PKT_FAULT) {
2236 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2237 dcerpc_errstr(state, pkt->u.fault.status)));
2238 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2239 state->p->last_fault_code = pkt->u.fault.status;
2240 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2241 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2242 state->p->last_fault_code = pkt->u.fault.status;
2243 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2244 } else {
2245 state->p->last_fault_code = pkt->u.fault.status;
2246 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2247 tevent_req_nterror(req, status);
2249 return;
2252 status = dcerpc_verify_ncacn_packet_header(pkt,
2253 DCERPC_PKT_ALTER_RESP,
2254 pkt->u.alter_resp.auth_info.length,
2255 DCERPC_PFC_FLAG_FIRST |
2256 DCERPC_PFC_FLAG_LAST,
2257 DCERPC_PFC_FLAG_CONC_MPX |
2258 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2259 if (!NT_STATUS_IS_OK(status)) {
2260 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2261 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2262 return;
2265 if (pkt->u.alter_resp.num_results != 1) {
2266 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2267 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2268 return;
2271 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2272 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2273 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2274 pkt->u.alter_resp.ctx_list[0].reason.value,
2275 nt_errstr(status)));
2276 tevent_req_nterror(req, status);
2277 return;
2280 /* the alter_resp might contain a reply set of credentials */
2281 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2282 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2283 &pkt->u.alter_resp.auth_info,
2284 sec->tmp_auth_info.in,
2285 NULL, true);
2286 if (tevent_req_nterror(req, status)) {
2287 return;
2291 tevent_req_done(req);
2294 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2296 return tevent_req_simple_recv_ntstatus(req);
2300 send a dcerpc alter_context request
2302 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2303 TALLOC_CTX *mem_ctx,
2304 const struct ndr_syntax_id *syntax,
2305 const struct ndr_syntax_id *transfer_syntax)
2307 struct tevent_req *subreq;
2308 struct tevent_context *ev = p->conn->event_ctx;
2309 bool ok;
2311 /* TODO: create a new event context here */
2313 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2314 p, syntax, transfer_syntax);
2315 if (subreq == NULL) {
2316 return NT_STATUS_NO_MEMORY;
2319 ok = tevent_req_poll(subreq, ev);
2320 if (!ok) {
2321 NTSTATUS status;
2322 status = map_nt_error_from_unix_common(errno);
2323 return status;
2326 return dcerpc_alter_context_recv(subreq);
2329 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2331 if (c->transport.stream == NULL) {
2332 return;
2335 tevent_queue_stop(c->transport.write_queue);
2336 TALLOC_FREE(c->transport.read_subreq);
2337 TALLOC_FREE(c->transport.stream);
2339 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2340 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2343 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2344 status = NT_STATUS_END_OF_FILE;
2347 dcerpc_recv_data(c, NULL, status);
2352 shutdown SMB pipe connection
2354 struct dcerpc_shutdown_pipe_state {
2355 struct dcecli_connection *c;
2356 NTSTATUS status;
2359 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2361 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2363 struct dcerpc_shutdown_pipe_state *state;
2364 struct tevent_req *subreq;
2366 if (c->transport.stream == NULL) {
2367 return NT_STATUS_OK;
2370 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2371 if (state == NULL) {
2372 return NT_STATUS_NO_MEMORY;
2374 state->c = c;
2375 state->status = status;
2377 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2378 if (subreq == NULL) {
2379 return NT_STATUS_NO_MEMORY;
2381 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2383 return status;
2386 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2388 struct dcerpc_shutdown_pipe_state *state =
2389 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2390 struct dcecli_connection *c = state->c;
2391 NTSTATUS status = state->status;
2392 int error;
2395 * here we ignore the return values...
2397 tstream_disconnect_recv(subreq, &error);
2398 TALLOC_FREE(subreq);
2400 TALLOC_FREE(state);
2402 dcerpc_transport_dead(c, status);
2407 struct dcerpc_send_read_state {
2408 struct dcecli_connection *p;
2411 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2413 struct dcecli_connection *p = state->p;
2415 p->transport.read_subreq = NULL;
2417 return 0;
2420 static void dcerpc_send_read_done(struct tevent_req *subreq);
2422 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2424 struct dcerpc_send_read_state *state;
2426 if (p->transport.read_subreq != NULL) {
2427 p->transport.pending_reads++;
2428 return NT_STATUS_OK;
2431 state = talloc_zero(p, struct dcerpc_send_read_state);
2432 if (state == NULL) {
2433 return NT_STATUS_NO_MEMORY;
2435 state->p = p;
2437 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2439 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2440 p->event_ctx,
2441 p->transport.stream);
2442 if (p->transport.read_subreq == NULL) {
2443 return NT_STATUS_NO_MEMORY;
2445 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2447 return NT_STATUS_OK;
2450 static void dcerpc_send_read_done(struct tevent_req *subreq)
2452 struct dcerpc_send_read_state *state =
2453 tevent_req_callback_data(subreq,
2454 struct dcerpc_send_read_state);
2455 struct dcecli_connection *p = state->p;
2456 NTSTATUS status;
2457 struct ncacn_packet *pkt;
2458 DATA_BLOB blob;
2460 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2461 &pkt, &blob);
2462 TALLOC_FREE(subreq);
2463 if (!NT_STATUS_IS_OK(status)) {
2464 TALLOC_FREE(state);
2465 dcerpc_transport_dead(p, status);
2466 return;
2470 * here we steal into thet connection context,
2471 * but p->transport.recv_data() will steal or free it again
2473 talloc_steal(p, blob.data);
2474 TALLOC_FREE(state);
2476 if (p->transport.pending_reads > 0) {
2477 p->transport.pending_reads--;
2479 status = dcerpc_send_read(p);
2480 if (!NT_STATUS_IS_OK(status)) {
2481 dcerpc_transport_dead(p, status);
2482 return;
2486 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2489 struct dcerpc_send_request_state {
2490 struct dcecli_connection *p;
2491 DATA_BLOB blob;
2492 struct iovec iov;
2495 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2497 struct dcecli_connection *p = state->p;
2499 p->transport.read_subreq = NULL;
2501 return 0;
2504 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2505 static void dcerpc_send_request_done(struct tevent_req *subreq);
2507 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2508 bool trigger_read)
2510 struct dcerpc_send_request_state *state;
2511 struct tevent_req *subreq;
2512 bool use_trans = trigger_read;
2514 if (p->transport.stream == NULL) {
2515 return NT_STATUS_CONNECTION_DISCONNECTED;
2518 state = talloc_zero(p, struct dcerpc_send_request_state);
2519 if (state == NULL) {
2520 return NT_STATUS_NO_MEMORY;
2522 state->p = p;
2524 state->blob = data_blob_talloc(state, data->data, data->length);
2525 if (state->blob.data == NULL) {
2526 TALLOC_FREE(state);
2527 return NT_STATUS_NO_MEMORY;
2529 state->iov.iov_base = (void *)state->blob.data;
2530 state->iov.iov_len = state->blob.length;
2532 if (p->transport.read_subreq != NULL) {
2533 use_trans = false;
2536 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2537 use_trans = false;
2540 if (use_trans) {
2542 * we need to block reads until our write is
2543 * the next in the write queue.
2545 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2546 p->transport.write_queue);
2547 if (p->transport.read_subreq == NULL) {
2548 TALLOC_FREE(state);
2549 return NT_STATUS_NO_MEMORY;
2551 tevent_req_set_callback(p->transport.read_subreq,
2552 dcerpc_send_request_wait_done,
2553 state);
2555 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2557 trigger_read = false;
2560 subreq = tstream_writev_queue_send(state, p->event_ctx,
2561 p->transport.stream,
2562 p->transport.write_queue,
2563 &state->iov, 1);
2564 if (subreq == NULL) {
2565 TALLOC_FREE(state);
2566 return NT_STATUS_NO_MEMORY;
2568 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2570 if (trigger_read) {
2571 dcerpc_send_read(p);
2574 return NT_STATUS_OK;
2577 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2579 struct dcerpc_send_request_state *state =
2580 tevent_req_callback_data(subreq,
2581 struct dcerpc_send_request_state);
2582 struct dcecli_connection *p = state->p;
2583 NTSTATUS status;
2584 bool ok;
2586 p->transport.read_subreq = NULL;
2587 talloc_set_destructor(state, NULL);
2589 ok = tevent_queue_wait_recv(subreq);
2590 if (!ok) {
2591 TALLOC_FREE(state);
2592 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2593 return;
2596 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2597 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2598 if (!NT_STATUS_IS_OK(status)) {
2599 TALLOC_FREE(state);
2600 dcerpc_transport_dead(p, status);
2601 return;
2605 /* we free subreq after tstream_cli_np_use_trans */
2606 TALLOC_FREE(subreq);
2608 dcerpc_send_read(p);
2611 static void dcerpc_send_request_done(struct tevent_req *subreq)
2613 struct dcerpc_send_request_state *state =
2614 tevent_req_callback_data(subreq,
2615 struct dcerpc_send_request_state);
2616 int ret;
2617 int error;
2619 ret = tstream_writev_queue_recv(subreq, &error);
2620 TALLOC_FREE(subreq);
2621 if (ret == -1) {
2622 struct dcecli_connection *p = state->p;
2623 NTSTATUS status = map_nt_error_from_unix_common(error);
2625 TALLOC_FREE(state);
2626 dcerpc_transport_dead(p, status);
2627 return;
2630 TALLOC_FREE(state);