s4:librpc/rpc: avoid an unused talloc_reference() from dcerpc_request_send()
[Samba/id10ts.git] / source4 / librpc / rpc / dcerpc.c
blobebf6f33aa5f21329f892d70a76e7fd1a283e1045
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/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "auth/gensec/gensec.h"
31 #include "param/param.h"
32 #include "lib/util/tevent_ntstatus.h"
33 #include "librpc/rpc/rpc_common.h"
35 enum rpc_request_state {
36 RPC_REQUEST_QUEUED,
37 RPC_REQUEST_PENDING,
38 RPC_REQUEST_DONE
42 handle for an async dcerpc request
44 struct rpc_request {
45 struct rpc_request *next, *prev;
46 struct dcerpc_pipe *p;
47 NTSTATUS status;
48 uint32_t call_id;
49 enum rpc_request_state state;
50 DATA_BLOB payload;
51 uint32_t flags;
52 uint32_t fault_code;
54 /* this is used to distinguish bind and alter_context requests
55 from normal requests */
56 void (*recv_handler)(struct rpc_request *conn,
57 DATA_BLOB *blob, struct ncacn_packet *pkt);
59 const struct GUID *object;
60 uint16_t opnum;
61 DATA_BLOB request_data;
62 bool ignore_timeout;
64 /* use by the ndr level async recv call */
65 struct {
66 const struct ndr_interface_table *table;
67 uint32_t opnum;
68 void *struct_ptr;
69 TALLOC_CTX *mem_ctx;
70 } ndr;
72 struct {
73 void (*callback)(struct rpc_request *);
74 void *private_data;
75 } async;
78 _PUBLIC_ NTSTATUS dcerpc_init(void)
80 return gensec_init();
83 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
84 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
86 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
87 struct dcerpc_pipe *p,
88 const struct GUID *object,
89 uint16_t opnum,
90 DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
92 TALLOC_CTX *mem_ctx,
93 DATA_BLOB *stub_data);
94 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
95 TALLOC_CTX *mem_ctx,
96 DATA_BLOB blob,
97 size_t struct_size,
98 ndr_push_flags_fn_t ndr_push,
99 ndr_pull_flags_fn_t ndr_pull);
100 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
101 struct ndr_pull *pull_in,
102 void *struct_ptr,
103 size_t struct_size,
104 ndr_push_flags_fn_t ndr_push,
105 ndr_pull_flags_fn_t ndr_pull,
106 ndr_print_function_t ndr_print);
108 /* destroy a dcerpc connection */
109 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
111 if (conn->dead) {
112 conn->free_skipped = true;
113 return -1;
115 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
116 return 0;
120 /* initialise a dcerpc connection.
121 the event context is optional
123 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
124 struct tevent_context *ev)
126 struct dcecli_connection *c;
128 c = talloc_zero(mem_ctx, struct dcecli_connection);
129 if (!c) {
130 return NULL;
133 c->event_ctx = ev;
135 if (c->event_ctx == NULL) {
136 talloc_free(c);
137 return NULL;
140 c->call_id = 1;
141 c->security_state.auth_info = NULL;
142 c->security_state.session_key = dcerpc_generic_session_key;
143 c->security_state.generic_state = NULL;
144 c->binding_string = NULL;
145 c->flags = 0;
146 c->srv_max_xmit_frag = 0;
147 c->srv_max_recv_frag = 0;
148 c->pending = NULL;
150 c->io_trigger = tevent_create_immediate(c);
151 if (c->io_trigger == NULL) {
152 talloc_free(c);
153 return NULL;
156 talloc_set_destructor(c, dcerpc_connection_destructor);
158 return c;
161 struct dcerpc_bh_state {
162 struct dcerpc_pipe *p;
165 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
167 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
168 struct dcerpc_bh_state);
170 if (!hs->p) {
171 return false;
174 if (!hs->p->conn) {
175 return false;
178 if (hs->p->conn->dead) {
179 return false;
182 return true;
185 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
186 uint32_t timeout)
188 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
189 struct dcerpc_bh_state);
190 uint32_t old;
192 if (!hs->p) {
193 return DCERPC_REQUEST_TIMEOUT;
196 old = hs->p->request_timeout;
197 hs->p->request_timeout = timeout;
199 return old;
202 struct dcerpc_bh_raw_call_state {
203 struct tevent_context *ev;
204 struct dcerpc_binding_handle *h;
205 DATA_BLOB in_data;
206 DATA_BLOB out_data;
207 uint32_t out_flags;
210 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
212 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
213 struct tevent_context *ev,
214 struct dcerpc_binding_handle *h,
215 const struct GUID *object,
216 uint32_t opnum,
217 uint32_t in_flags,
218 const uint8_t *in_data,
219 size_t in_length)
221 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
222 struct dcerpc_bh_state);
223 struct tevent_req *req;
224 struct dcerpc_bh_raw_call_state *state;
225 bool ok;
226 struct rpc_request *subreq;
228 req = tevent_req_create(mem_ctx, &state,
229 struct dcerpc_bh_raw_call_state);
230 if (req == NULL) {
231 return NULL;
233 state->ev = ev;
234 state->h = h;
235 state->in_data.data = discard_const_p(uint8_t, in_data);
236 state->in_data.length = in_length;
238 ok = dcerpc_bh_is_connected(h);
239 if (!ok) {
240 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
241 return tevent_req_post(req, ev);
244 subreq = dcerpc_request_send(state,
245 hs->p,
246 object,
247 opnum,
248 &state->in_data);
249 if (tevent_req_nomem(subreq, req)) {
250 return tevent_req_post(req, ev);
252 subreq->async.callback = dcerpc_bh_raw_call_done;
253 subreq->async.private_data = req;
255 return req;
258 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
260 struct tevent_req *req =
261 talloc_get_type_abort(subreq->async.private_data,
262 struct tevent_req);
263 struct dcerpc_bh_raw_call_state *state =
264 tevent_req_data(req,
265 struct dcerpc_bh_raw_call_state);
266 NTSTATUS status;
267 uint32_t fault_code;
269 state->out_flags = 0;
270 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
271 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
274 fault_code = subreq->fault_code;
276 status = dcerpc_request_recv(subreq, state, &state->out_data);
277 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
278 status = dcerpc_fault_to_nt_status(fault_code);
282 * We trigger the callback in the next event run
283 * because the code in this file might trigger
284 * multiple request callbacks from within a single
285 * while loop.
287 * In order to avoid segfaults from within
288 * dcerpc_connection_dead() we call
289 * tevent_req_defer_callback().
291 tevent_req_defer_callback(req, state->ev);
293 if (!NT_STATUS_IS_OK(status)) {
294 tevent_req_nterror(req, status);
295 return;
298 tevent_req_done(req);
301 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
302 TALLOC_CTX *mem_ctx,
303 uint8_t **out_data,
304 size_t *out_length,
305 uint32_t *out_flags)
307 struct dcerpc_bh_raw_call_state *state =
308 tevent_req_data(req,
309 struct dcerpc_bh_raw_call_state);
310 NTSTATUS status;
312 if (tevent_req_is_nterror(req, &status)) {
313 tevent_req_received(req);
314 return status;
317 *out_data = talloc_move(mem_ctx, &state->out_data.data);
318 *out_length = state->out_data.length;
319 *out_flags = state->out_flags;
320 tevent_req_received(req);
321 return NT_STATUS_OK;
324 struct dcerpc_bh_disconnect_state {
325 uint8_t _dummy;
328 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
329 struct tevent_context *ev,
330 struct dcerpc_binding_handle *h)
332 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
333 struct dcerpc_bh_state);
334 struct tevent_req *req;
335 struct dcerpc_bh_disconnect_state *state;
336 bool ok;
338 req = tevent_req_create(mem_ctx, &state,
339 struct dcerpc_bh_disconnect_state);
340 if (req == NULL) {
341 return NULL;
344 ok = dcerpc_bh_is_connected(h);
345 if (!ok) {
346 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
347 return tevent_req_post(req, ev);
350 /* TODO: do a real disconnect ... */
351 hs->p = NULL;
353 tevent_req_done(req);
354 return tevent_req_post(req, ev);
357 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
359 NTSTATUS status;
361 if (tevent_req_is_nterror(req, &status)) {
362 tevent_req_received(req);
363 return status;
366 tevent_req_received(req);
367 return NT_STATUS_OK;
370 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
372 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
373 struct dcerpc_bh_state);
375 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
376 return true;
379 return false;
382 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
384 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
385 struct dcerpc_bh_state);
387 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
388 return true;
391 return false;
394 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
396 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
397 struct dcerpc_bh_state);
399 if (hs->p->conn->flags & DCERPC_NDR64) {
400 return true;
403 return false;
406 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
407 int ndr_flags,
408 const void *_struct_ptr,
409 const struct ndr_interface_call *call)
411 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
412 struct dcerpc_bh_state);
413 void *struct_ptr = discard_const(_struct_ptr);
415 if (ndr_flags & NDR_IN) {
416 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
417 ndr_print_function_debug(call->ndr_print,
418 call->name,
419 ndr_flags,
420 struct_ptr);
423 if (ndr_flags & NDR_OUT) {
424 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
425 ndr_print_function_debug(call->ndr_print,
426 call->name,
427 ndr_flags,
428 struct_ptr);
433 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
434 NTSTATUS error,
435 const void *struct_ptr,
436 const struct ndr_interface_call *call)
438 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
439 call->name, nt_errstr(error)));
442 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
443 NTSTATUS error,
444 const DATA_BLOB *blob,
445 const struct ndr_interface_call *call)
447 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
448 struct dcerpc_bh_state);
449 const uint32_t num_examples = 20;
450 uint32_t i;
452 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
453 call->name, nt_errstr(error)));
455 if (hs->p->conn->packet_log_dir == NULL) return;
457 for (i=0;i<num_examples;i++) {
458 char *name=NULL;
459 asprintf(&name, "%s/rpclog/%s-out.%d",
460 hs->p->conn->packet_log_dir,
461 call->name, i);
462 if (name == NULL) {
463 return;
465 if (!file_exist(name)) {
466 if (file_save(name, blob->data, blob->length)) {
467 DEBUG(10,("Logged rpc packet to %s\n", name));
469 free(name);
470 break;
472 free(name);
476 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
477 TALLOC_CTX *mem_ctx,
478 const DATA_BLOB *blob,
479 const struct ndr_interface_call *call)
481 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
482 struct dcerpc_bh_state);
484 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
485 NTSTATUS status;
487 status = dcerpc_ndr_validate_in(hs->p->conn,
488 mem_ctx,
489 *blob,
490 call->struct_size,
491 call->ndr_push,
492 call->ndr_pull);
493 if (!NT_STATUS_IS_OK(status)) {
494 DEBUG(0,("Validation [in] failed for %s - %s\n",
495 call->name, nt_errstr(status)));
496 return status;
500 DEBUG(10,("rpc request data:\n"));
501 dump_data(10, blob->data, blob->length);
503 return NT_STATUS_OK;
506 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
507 struct ndr_pull *pull_in,
508 const void *_struct_ptr,
509 const struct ndr_interface_call *call)
511 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
512 struct dcerpc_bh_state);
513 void *struct_ptr = discard_const(_struct_ptr);
515 DEBUG(10,("rpc reply data:\n"));
516 dump_data(10, pull_in->data, pull_in->data_size);
518 if (pull_in->offset != pull_in->data_size) {
519 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
520 pull_in->data_size - pull_in->offset,
521 pull_in->offset, pull_in->offset,
522 call->name));
523 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
524 but it turns out that early versions of NT
525 (specifically NT3.1) add junk onto the end of rpc
526 packets, so if we want to interoperate at all with
527 those versions then we need to ignore this error */
530 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
531 NTSTATUS status;
533 status = dcerpc_ndr_validate_out(hs->p->conn,
534 pull_in,
535 struct_ptr,
536 call->struct_size,
537 call->ndr_push,
538 call->ndr_pull,
539 call->ndr_print);
540 if (!NT_STATUS_IS_OK(status)) {
541 DEBUG(2,("Validation [out] failed for %s - %s\n",
542 call->name, nt_errstr(status)));
543 return status;
547 return NT_STATUS_OK;
550 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
551 .name = "dcerpc",
552 .is_connected = dcerpc_bh_is_connected,
553 .set_timeout = dcerpc_bh_set_timeout,
554 .raw_call_send = dcerpc_bh_raw_call_send,
555 .raw_call_recv = dcerpc_bh_raw_call_recv,
556 .disconnect_send = dcerpc_bh_disconnect_send,
557 .disconnect_recv = dcerpc_bh_disconnect_recv,
559 .push_bigendian = dcerpc_bh_push_bigendian,
560 .ref_alloc = dcerpc_bh_ref_alloc,
561 .use_ndr64 = dcerpc_bh_use_ndr64,
562 .do_ndr_print = dcerpc_bh_do_ndr_print,
563 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
564 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
565 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
566 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
569 /* initialise a dcerpc pipe. */
570 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
572 struct dcerpc_binding_handle *h;
573 struct dcerpc_bh_state *hs;
575 h = dcerpc_binding_handle_create(p,
576 &dcerpc_bh_ops,
577 NULL,
578 NULL, /* TODO */
579 &hs,
580 struct dcerpc_bh_state,
581 __location__);
582 if (h == NULL) {
583 return NULL;
585 hs->p = p;
587 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
589 return h;
592 /* initialise a dcerpc pipe. */
593 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
595 struct dcerpc_pipe *p;
597 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
598 if (!p) {
599 return NULL;
602 p->conn = dcerpc_connection_init(p, ev);
603 if (p->conn == NULL) {
604 talloc_free(p);
605 return NULL;
608 p->last_fault_code = 0;
609 p->context_id = 0;
610 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
611 p->binding = NULL;
613 ZERO_STRUCT(p->syntax);
614 ZERO_STRUCT(p->transfer_syntax);
616 if (DEBUGLVL(100)) {
617 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
620 p->binding_handle = dcerpc_pipe_binding_handle(p);
621 if (p->binding_handle == NULL) {
622 talloc_free(p);
623 return NULL;
626 return p;
631 choose the next call id to use
633 static uint32_t next_call_id(struct dcecli_connection *c)
635 c->call_id++;
636 if (c->call_id == 0) {
637 c->call_id++;
639 return c->call_id;
643 setup for a ndr pull, also setting up any flags from the binding string
645 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
646 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
648 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
650 if (ndr == NULL) return ndr;
652 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
653 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
656 if (c->flags & DCERPC_NDR_REF_ALLOC) {
657 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
660 if (c->flags & DCERPC_NDR64) {
661 ndr->flags |= LIBNDR_FLAG_NDR64;
664 return ndr;
668 parse a data blob into a ncacn_packet structure. This handles both
669 input and output packets
671 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
672 struct ncacn_packet *pkt)
674 struct ndr_pull *ndr;
675 enum ndr_err_code ndr_err;
677 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
678 if (!ndr) {
679 return NT_STATUS_NO_MEMORY;
682 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
683 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
686 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
687 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
688 return ndr_map_error2ntstatus(ndr_err);
691 return NT_STATUS_OK;
695 parse the authentication information on a dcerpc response packet
697 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
698 DATA_BLOB *raw_packet,
699 struct ncacn_packet *pkt)
701 NTSTATUS status;
702 struct dcerpc_auth auth;
703 uint32_t auth_length;
705 if (!c->security_state.auth_info ||
706 !c->security_state.generic_state) {
707 return NT_STATUS_OK;
710 switch (c->security_state.auth_info->auth_level) {
711 case DCERPC_AUTH_LEVEL_PRIVACY:
712 case DCERPC_AUTH_LEVEL_INTEGRITY:
713 break;
715 case DCERPC_AUTH_LEVEL_CONNECT:
716 if (pkt->auth_length != 0) {
717 break;
719 return NT_STATUS_OK;
720 case DCERPC_AUTH_LEVEL_NONE:
721 if (pkt->auth_length != 0) {
722 return NT_STATUS_INVALID_NETWORK_RESPONSE;
724 return NT_STATUS_OK;
726 default:
727 return NT_STATUS_INVALID_LEVEL;
730 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
731 &pkt->u.response.stub_and_verifier,
732 &auth, &auth_length, false);
733 NT_STATUS_NOT_OK_RETURN(status);
735 pkt->u.response.stub_and_verifier.length -= auth_length;
737 /* check signature or unseal the packet */
738 switch (c->security_state.auth_info->auth_level) {
739 case DCERPC_AUTH_LEVEL_PRIVACY:
740 status = gensec_unseal_packet(c->security_state.generic_state,
741 raw_packet->data + DCERPC_REQUEST_LENGTH,
742 pkt->u.response.stub_and_verifier.length,
743 raw_packet->data,
744 raw_packet->length - auth.credentials.length,
745 &auth.credentials);
746 memcpy(pkt->u.response.stub_and_verifier.data,
747 raw_packet->data + DCERPC_REQUEST_LENGTH,
748 pkt->u.response.stub_and_verifier.length);
749 break;
751 case DCERPC_AUTH_LEVEL_INTEGRITY:
752 status = gensec_check_packet(c->security_state.generic_state,
753 pkt->u.response.stub_and_verifier.data,
754 pkt->u.response.stub_and_verifier.length,
755 raw_packet->data,
756 raw_packet->length - auth.credentials.length,
757 &auth.credentials);
758 break;
760 case DCERPC_AUTH_LEVEL_CONNECT:
761 /* for now we ignore possible signatures here */
762 status = NT_STATUS_OK;
763 break;
765 default:
766 status = NT_STATUS_INVALID_LEVEL;
767 break;
770 /* remove the indicated amount of padding */
771 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
772 return NT_STATUS_INFO_LENGTH_MISMATCH;
774 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
776 return status;
781 push a dcerpc request packet into a blob, possibly signing it.
783 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
784 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
785 size_t sig_size,
786 struct ncacn_packet *pkt)
788 NTSTATUS status;
789 struct ndr_push *ndr;
790 DATA_BLOB creds2;
791 size_t payload_length;
792 enum ndr_err_code ndr_err;
793 size_t hdr_size = DCERPC_REQUEST_LENGTH;
795 /* non-signed packets are simpler */
796 if (sig_size == 0) {
797 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
800 switch (c->security_state.auth_info->auth_level) {
801 case DCERPC_AUTH_LEVEL_PRIVACY:
802 case DCERPC_AUTH_LEVEL_INTEGRITY:
803 break;
805 case DCERPC_AUTH_LEVEL_CONNECT:
806 /* TODO: let the gensec mech decide if it wants to generate a signature */
807 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
809 case DCERPC_AUTH_LEVEL_NONE:
810 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
812 default:
813 return NT_STATUS_INVALID_LEVEL;
816 ndr = ndr_push_init_ctx(mem_ctx);
817 if (!ndr) {
818 return NT_STATUS_NO_MEMORY;
821 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
822 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
825 if (c->flags & DCERPC_NDR64) {
826 ndr->flags |= LIBNDR_FLAG_NDR64;
829 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
830 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
831 hdr_size += 16;
834 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
835 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
836 return ndr_map_error2ntstatus(ndr_err);
839 /* pad to 16 byte multiple in the payload portion of the
840 packet. This matches what w2k3 does. Note that we can't use
841 ndr_push_align() as that is relative to the start of the
842 whole packet, whereas w2k8 wants it relative to the start
843 of the stub */
844 c->security_state.auth_info->auth_pad_length =
845 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
846 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
847 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
848 return ndr_map_error2ntstatus(ndr_err);
851 payload_length = pkt->u.request.stub_and_verifier.length +
852 c->security_state.auth_info->auth_pad_length;
854 /* we start without signature, it will appended later */
855 c->security_state.auth_info->credentials = data_blob(NULL,0);
857 /* add the auth verifier */
858 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
859 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
860 return ndr_map_error2ntstatus(ndr_err);
863 /* extract the whole packet as a blob */
864 *blob = ndr_push_blob(ndr);
867 * Setup the frag and auth length in the packet buffer.
868 * This is needed if the GENSEC mech does AEAD signing
869 * of the packet headers. The signature itself will be
870 * appended later.
872 dcerpc_set_frag_length(blob, blob->length + sig_size);
873 dcerpc_set_auth_length(blob, sig_size);
875 /* sign or seal the packet */
876 switch (c->security_state.auth_info->auth_level) {
877 case DCERPC_AUTH_LEVEL_PRIVACY:
878 status = gensec_seal_packet(c->security_state.generic_state,
879 mem_ctx,
880 blob->data + hdr_size,
881 payload_length,
882 blob->data,
883 blob->length,
884 &creds2);
885 if (!NT_STATUS_IS_OK(status)) {
886 return status;
888 break;
890 case DCERPC_AUTH_LEVEL_INTEGRITY:
891 status = gensec_sign_packet(c->security_state.generic_state,
892 mem_ctx,
893 blob->data + hdr_size,
894 payload_length,
895 blob->data,
896 blob->length,
897 &creds2);
898 if (!NT_STATUS_IS_OK(status)) {
899 return status;
901 break;
903 default:
904 status = NT_STATUS_INVALID_LEVEL;
905 break;
908 if (creds2.length != sig_size) {
909 /* this means the sig_size estimate for the signature
910 was incorrect. We have to correct the packet
911 sizes. That means we could go over the max fragment
912 length */
913 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
914 (unsigned) creds2.length,
915 (unsigned) sig_size,
916 (unsigned) c->security_state.auth_info->auth_pad_length,
917 (unsigned) pkt->u.request.stub_and_verifier.length));
918 dcerpc_set_frag_length(blob, blob->length + creds2.length);
919 dcerpc_set_auth_length(blob, creds2.length);
922 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
923 return NT_STATUS_NO_MEMORY;
926 return NT_STATUS_OK;
931 fill in the fixed values in a dcerpc header
933 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
935 pkt->rpc_vers = 5;
936 pkt->rpc_vers_minor = 0;
937 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
938 pkt->drep[0] = 0;
939 } else {
940 pkt->drep[0] = DCERPC_DREP_LE;
942 pkt->drep[1] = 0;
943 pkt->drep[2] = 0;
944 pkt->drep[3] = 0;
948 map a bind nak reason to a NTSTATUS
950 static NTSTATUS dcerpc_map_reason(uint16_t reason)
952 switch (reason) {
953 case DCERPC_BIND_REASON_ASYNTAX:
954 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
955 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
956 return NT_STATUS_INVALID_PARAMETER;
958 return NT_STATUS_UNSUCCESSFUL;
962 remove requests from the pending or queued queues
964 static int dcerpc_req_dequeue(struct rpc_request *req)
966 switch (req->state) {
967 case RPC_REQUEST_QUEUED:
968 DLIST_REMOVE(req->p->conn->request_queue, req);
969 break;
970 case RPC_REQUEST_PENDING:
971 DLIST_REMOVE(req->p->conn->pending, req);
972 break;
973 case RPC_REQUEST_DONE:
974 break;
976 return 0;
981 mark the dcerpc connection dead. All outstanding requests get an error
983 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
985 if (conn->dead) return;
987 conn->dead = true;
989 TALLOC_FREE(conn->io_trigger);
990 conn->io_trigger_pending = false;
992 conn->transport.recv_data = NULL;
994 if (conn->transport.shutdown_pipe) {
995 conn->transport.shutdown_pipe(conn, status);
998 /* all pending requests get the error */
999 while (conn->pending) {
1000 struct rpc_request *req = conn->pending;
1001 dcerpc_req_dequeue(req);
1002 req->state = RPC_REQUEST_DONE;
1003 req->status = status;
1004 if (req->async.callback) {
1005 req->async.callback(req);
1009 /* all requests, which are not shipped */
1010 while (conn->request_queue) {
1011 struct rpc_request *req = conn->request_queue;
1012 dcerpc_req_dequeue(req);
1013 req->state = RPC_REQUEST_DONE;
1014 req->status = status;
1015 if (req->async.callback) {
1016 req->async.callback(req);
1020 talloc_set_destructor(conn, NULL);
1021 if (conn->free_skipped) {
1022 talloc_free(conn);
1027 forward declarations of the recv_data handlers for the types of
1028 packets we need to handle
1030 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1031 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1034 receive a dcerpc reply from the transport. Here we work out what
1035 type of reply it is (normal request, bind or alter context) and
1036 dispatch to the appropriate handler
1038 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1040 struct ncacn_packet pkt;
1042 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1043 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1046 /* the transport may be telling us of a severe error, such as
1047 a dropped socket */
1048 if (!NT_STATUS_IS_OK(status)) {
1049 data_blob_free(blob);
1050 dcerpc_connection_dead(conn, status);
1051 return;
1054 /* parse the basic packet to work out what type of response this is */
1055 status = ncacn_pull(conn, blob, blob->data, &pkt);
1056 if (!NT_STATUS_IS_OK(status)) {
1057 data_blob_free(blob);
1058 dcerpc_connection_dead(conn, status);
1059 return;
1062 dcerpc_request_recv_data(conn, blob, &pkt);
1066 handle timeouts of individual dcerpc requests
1068 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1069 struct timeval t, void *private_data)
1071 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1073 if (req->ignore_timeout) {
1074 dcerpc_req_dequeue(req);
1075 req->state = RPC_REQUEST_DONE;
1076 req->status = NT_STATUS_IO_TIMEOUT;
1077 if (req->async.callback) {
1078 req->async.callback(req);
1080 return;
1083 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1086 struct dcerpc_bind_state {
1087 struct tevent_context *ev;
1088 struct dcerpc_pipe *p;
1091 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1092 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1093 DATA_BLOB *raw_packet,
1094 struct ncacn_packet *pkt);
1096 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1097 struct tevent_context *ev,
1098 struct dcerpc_pipe *p,
1099 const struct ndr_syntax_id *syntax,
1100 const struct ndr_syntax_id *transfer_syntax)
1102 struct tevent_req *req;
1103 struct dcerpc_bind_state *state;
1104 struct ncacn_packet pkt;
1105 DATA_BLOB blob;
1106 NTSTATUS status;
1107 struct rpc_request *subreq;
1109 req = tevent_req_create(mem_ctx, &state,
1110 struct dcerpc_bind_state);
1111 if (req == NULL) {
1112 return NULL;
1115 state->ev = ev;
1116 state->p = p;
1118 p->syntax = *syntax;
1119 p->transfer_syntax = *transfer_syntax;
1121 init_ncacn_hdr(p->conn, &pkt);
1123 pkt.ptype = DCERPC_PKT_BIND;
1124 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1125 pkt.call_id = p->conn->call_id;
1126 pkt.auth_length = 0;
1128 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1129 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1132 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1133 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1136 pkt.u.bind.max_xmit_frag = 5840;
1137 pkt.u.bind.max_recv_frag = 5840;
1138 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1139 pkt.u.bind.num_contexts = 1;
1140 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1141 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1142 return tevent_req_post(req, ev);
1144 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1145 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1146 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1147 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1148 pkt.u.bind.auth_info = data_blob(NULL, 0);
1150 /* construct the NDR form of the packet */
1151 status = ncacn_push_auth(&blob, state, &pkt,
1152 p->conn->security_state.auth_info);
1153 if (tevent_req_nterror(req, status)) {
1154 return tevent_req_post(req, ev);
1157 p->conn->transport.recv_data = dcerpc_recv_data;
1160 * we allocate a dcerpc_request so we can be in the same
1161 * request queue as normal requests
1163 subreq = talloc_zero(state, struct rpc_request);
1164 if (tevent_req_nomem(subreq, req)) {
1165 return tevent_req_post(req, ev);
1168 subreq->state = RPC_REQUEST_PENDING;
1169 subreq->call_id = pkt.call_id;
1170 subreq->async.private_data = req;
1171 subreq->async.callback = dcerpc_bind_fail_handler;
1172 subreq->p = p;
1173 subreq->recv_handler = dcerpc_bind_recv_handler;
1174 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1175 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1177 status = p->conn->transport.send_request(p->conn, &blob, true);
1178 if (tevent_req_nterror(req, status)) {
1179 return tevent_req_post(req, ev);
1182 tevent_add_timer(ev, subreq,
1183 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1184 dcerpc_timeout_handler, subreq);
1186 return req;
1189 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1191 struct tevent_req *req =
1192 talloc_get_type_abort(subreq->async.private_data,
1193 struct tevent_req);
1194 struct dcerpc_bind_state *state =
1195 tevent_req_data(req,
1196 struct dcerpc_bind_state);
1197 NTSTATUS status = subreq->status;
1199 TALLOC_FREE(subreq);
1202 * We trigger the callback in the next event run
1203 * because the code in this file might trigger
1204 * multiple request callbacks from within a single
1205 * while loop.
1207 * In order to avoid segfaults from within
1208 * dcerpc_connection_dead() we call
1209 * tevent_req_defer_callback().
1211 tevent_req_defer_callback(req, state->ev);
1213 tevent_req_nterror(req, status);
1216 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1217 DATA_BLOB *raw_packet,
1218 struct ncacn_packet *pkt)
1220 struct tevent_req *req =
1221 talloc_get_type_abort(subreq->async.private_data,
1222 struct tevent_req);
1223 struct dcerpc_bind_state *state =
1224 tevent_req_data(req,
1225 struct dcerpc_bind_state);
1226 struct dcecli_connection *conn = state->p->conn;
1227 NTSTATUS status;
1230 * Note that pkt is allocated under raw_packet->data,
1231 * while raw_packet->data is a child of subreq.
1233 talloc_steal(state, raw_packet->data);
1234 TALLOC_FREE(subreq);
1237 * We trigger the callback in the next event run
1238 * because the code in this file might trigger
1239 * multiple request callbacks from within a single
1240 * while loop.
1242 * In order to avoid segfaults from within
1243 * dcerpc_connection_dead() we call
1244 * tevent_req_defer_callback().
1246 tevent_req_defer_callback(req, state->ev);
1248 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1249 status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason);
1251 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1252 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1254 tevent_req_nterror(req, status);
1255 return;
1258 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1259 (pkt->u.bind_ack.num_results == 0) ||
1260 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1261 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1262 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1263 return;
1266 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1267 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1269 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1270 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1271 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1274 if ((state->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1275 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1276 conn->flags |= DCERPC_HEADER_SIGNING;
1279 /* the bind_ack might contain a reply set of credentials */
1280 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1281 uint32_t auth_length;
1283 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1284 conn->security_state.auth_info, &auth_length, true);
1285 if (tevent_req_nterror(req, status)) {
1286 return;
1290 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1292 tevent_req_done(req);
1295 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1297 return tevent_req_simple_recv_ntstatus(req);
1301 perform a continued bind (and auth3)
1303 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1304 TALLOC_CTX *mem_ctx)
1306 struct ncacn_packet pkt;
1307 NTSTATUS status;
1308 DATA_BLOB blob;
1310 init_ncacn_hdr(p->conn, &pkt);
1312 pkt.ptype = DCERPC_PKT_AUTH3;
1313 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1314 pkt.call_id = next_call_id(p->conn);
1315 pkt.auth_length = 0;
1316 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1318 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1319 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1322 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1323 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1326 /* construct the NDR form of the packet */
1327 status = ncacn_push_auth(&blob, mem_ctx,
1328 &pkt,
1329 p->conn->security_state.auth_info);
1330 if (!NT_STATUS_IS_OK(status)) {
1331 return status;
1334 /* send it on its way */
1335 status = p->conn->transport.send_request(p->conn, &blob, false);
1336 if (!NT_STATUS_IS_OK(status)) {
1337 return status;
1340 return NT_STATUS_OK;
1345 process a fragment received from the transport layer during a
1346 request
1348 This function frees the data
1350 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1351 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1353 struct rpc_request *req;
1354 unsigned int length;
1355 NTSTATUS status = NT_STATUS_OK;
1358 if this is an authenticated connection then parse and check
1359 the auth info. We have to do this before finding the
1360 matching packet, as the request structure might have been
1361 removed due to a timeout, but if it has been we still need
1362 to run the auth routines so that we don't get the sign/seal
1363 info out of step with the server
1365 if (c->security_state.auth_info && c->security_state.generic_state &&
1366 pkt->ptype == DCERPC_PKT_RESPONSE) {
1367 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1370 /* find the matching request */
1371 for (req=c->pending;req;req=req->next) {
1372 if (pkt->call_id == req->call_id) break;
1375 #if 0
1376 /* useful for testing certain vendors RPC servers */
1377 if (req == NULL && c->pending && pkt->call_id == 0) {
1378 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1379 req = c->pending;
1381 #endif
1383 if (req == NULL) {
1384 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1385 data_blob_free(raw_packet);
1386 return;
1389 talloc_steal(req, raw_packet->data);
1391 if (req->recv_handler != NULL) {
1392 dcerpc_req_dequeue(req);
1393 req->state = RPC_REQUEST_DONE;
1394 req->recv_handler(req, raw_packet, pkt);
1395 return;
1398 if (pkt->ptype == DCERPC_PKT_FAULT) {
1399 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1400 req->fault_code = pkt->u.fault.status;
1401 req->status = NT_STATUS_NET_WRITE_FAULT;
1402 goto req_done;
1405 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1406 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1407 (int)pkt->ptype));
1408 req->fault_code = DCERPC_FAULT_OTHER;
1409 req->status = NT_STATUS_NET_WRITE_FAULT;
1410 goto req_done;
1413 /* now check the status from the auth routines, and if it failed then fail
1414 this request accordingly */
1415 if (!NT_STATUS_IS_OK(status)) {
1416 req->status = status;
1417 goto req_done;
1420 length = pkt->u.response.stub_and_verifier.length;
1422 if (length > 0) {
1423 req->payload.data = talloc_realloc(req,
1424 req->payload.data,
1425 uint8_t,
1426 req->payload.length + length);
1427 if (!req->payload.data) {
1428 req->status = NT_STATUS_NO_MEMORY;
1429 goto req_done;
1431 memcpy(req->payload.data+req->payload.length,
1432 pkt->u.response.stub_and_verifier.data, length);
1433 req->payload.length += length;
1436 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1437 c->transport.send_read(c);
1438 return;
1441 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1442 req->flags |= DCERPC_PULL_BIGENDIAN;
1443 } else {
1444 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1448 req_done:
1449 /* we've got the full payload */
1450 req->state = RPC_REQUEST_DONE;
1451 DLIST_REMOVE(c->pending, req);
1454 * We have to look at shipping further requests before calling
1455 * the async function, that one might close the pipe
1457 dcerpc_schedule_io_trigger(c);
1459 if (req->async.callback) {
1460 req->async.callback(req);
1465 perform the send side of a async dcerpc request
1467 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1468 struct dcerpc_pipe *p,
1469 const struct GUID *object,
1470 uint16_t opnum,
1471 DATA_BLOB *stub_data)
1473 struct rpc_request *req;
1475 p->conn->transport.recv_data = dcerpc_recv_data;
1477 req = talloc(mem_ctx, struct rpc_request);
1478 if (req == NULL) {
1479 return NULL;
1482 req->p = p;
1483 req->call_id = next_call_id(p->conn);
1484 req->status = NT_STATUS_OK;
1485 req->state = RPC_REQUEST_QUEUED;
1486 req->payload = data_blob(NULL, 0);
1487 req->flags = 0;
1488 req->fault_code = 0;
1489 req->ignore_timeout = false;
1490 req->async.callback = NULL;
1491 req->async.private_data = NULL;
1492 req->recv_handler = NULL;
1494 if (object != NULL) {
1495 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1496 if (req->object == NULL) {
1497 talloc_free(req);
1498 return NULL;
1500 } else {
1501 req->object = NULL;
1504 req->opnum = opnum;
1505 req->request_data.length = stub_data->length;
1506 req->request_data.data = stub_data->data;
1508 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1509 talloc_set_destructor(req, dcerpc_req_dequeue);
1511 dcerpc_schedule_io_trigger(p->conn);
1513 if (p->request_timeout) {
1514 tevent_add_timer(dcerpc_event_context(p), req,
1515 timeval_current_ofs(p->request_timeout, 0),
1516 dcerpc_timeout_handler, req);
1519 return req;
1523 Send a request using the transport
1526 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1528 struct rpc_request *req;
1529 struct dcerpc_pipe *p;
1530 DATA_BLOB *stub_data;
1531 struct ncacn_packet pkt;
1532 DATA_BLOB blob;
1533 uint32_t remaining, chunk_size;
1534 bool first_packet = true;
1535 size_t sig_size = 0;
1536 bool need_async = false;
1538 req = c->request_queue;
1539 if (req == NULL) {
1540 return;
1543 p = req->p;
1544 stub_data = &req->request_data;
1546 if (c->pending) {
1547 need_async = true;
1550 DLIST_REMOVE(c->request_queue, req);
1551 DLIST_ADD(c->pending, req);
1552 req->state = RPC_REQUEST_PENDING;
1554 init_ncacn_hdr(p->conn, &pkt);
1556 remaining = stub_data->length;
1558 /* we can write a full max_recv_frag size, minus the dcerpc
1559 request header size */
1560 chunk_size = p->conn->srv_max_recv_frag;
1561 chunk_size -= DCERPC_REQUEST_LENGTH;
1562 if (c->security_state.auth_info &&
1563 c->security_state.generic_state) {
1564 sig_size = gensec_sig_size(c->security_state.generic_state,
1565 p->conn->srv_max_recv_frag);
1566 if (sig_size) {
1567 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1568 chunk_size -= sig_size;
1571 chunk_size -= (chunk_size % 16);
1573 pkt.ptype = DCERPC_PKT_REQUEST;
1574 pkt.call_id = req->call_id;
1575 pkt.auth_length = 0;
1576 pkt.pfc_flags = 0;
1577 pkt.u.request.alloc_hint = remaining;
1578 pkt.u.request.context_id = p->context_id;
1579 pkt.u.request.opnum = req->opnum;
1581 if (req->object) {
1582 pkt.u.request.object.object = *req->object;
1583 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1584 chunk_size -= ndr_size_GUID(req->object,0);
1587 /* we send a series of pdus without waiting for a reply */
1588 while (remaining > 0 || first_packet) {
1589 uint32_t chunk = MIN(chunk_size, remaining);
1590 bool last_frag = false;
1591 bool do_trans = false;
1593 first_packet = false;
1594 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1596 if (remaining == stub_data->length) {
1597 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1599 if (chunk == remaining) {
1600 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1601 last_frag = true;
1604 pkt.u.request.stub_and_verifier.data = stub_data->data +
1605 (stub_data->length - remaining);
1606 pkt.u.request.stub_and_verifier.length = chunk;
1608 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1609 if (!NT_STATUS_IS_OK(req->status)) {
1610 req->state = RPC_REQUEST_DONE;
1611 DLIST_REMOVE(p->conn->pending, req);
1612 return;
1615 if (last_frag && !need_async) {
1616 do_trans = true;
1619 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1620 if (!NT_STATUS_IS_OK(req->status)) {
1621 req->state = RPC_REQUEST_DONE;
1622 DLIST_REMOVE(p->conn->pending, req);
1623 return;
1626 if (last_frag && !do_trans) {
1627 req->status = p->conn->transport.send_read(p->conn);
1628 if (!NT_STATUS_IS_OK(req->status)) {
1629 req->state = RPC_REQUEST_DONE;
1630 DLIST_REMOVE(p->conn->pending, req);
1631 return;
1635 remaining -= chunk;
1639 static void dcerpc_io_trigger(struct tevent_context *ctx,
1640 struct tevent_immediate *im,
1641 void *private_data)
1643 struct dcecli_connection *c =
1644 talloc_get_type_abort(private_data,
1645 struct dcecli_connection);
1647 c->io_trigger_pending = false;
1649 dcerpc_schedule_io_trigger(c);
1651 dcerpc_ship_next_request(c);
1654 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1656 if (c->dead) {
1657 return;
1660 if (c->request_queue == NULL) {
1661 return;
1664 if (c->io_trigger_pending) {
1665 return;
1668 c->io_trigger_pending = true;
1670 tevent_schedule_immediate(c->io_trigger,
1671 c->event_ctx,
1672 dcerpc_io_trigger,
1677 return the event context for a dcerpc pipe
1678 used by callers who wish to operate asynchronously
1680 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1682 return p->conn->event_ctx;
1688 perform the receive side of a async dcerpc request
1690 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1691 TALLOC_CTX *mem_ctx,
1692 DATA_BLOB *stub_data)
1694 NTSTATUS status;
1696 while (req->state != RPC_REQUEST_DONE) {
1697 struct tevent_context *ctx = dcerpc_event_context(req->p);
1698 if (tevent_loop_once(ctx) != 0) {
1699 return NT_STATUS_CONNECTION_DISCONNECTED;
1702 *stub_data = req->payload;
1703 status = req->status;
1704 if (stub_data->data) {
1705 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1707 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1708 req->p->last_fault_code = req->fault_code;
1710 talloc_unlink(talloc_parent(req), req);
1711 return status;
1715 this is a paranoid NDR validator. For every packet we push onto the wire
1716 we pull it back again, then push it again. Then we compare the raw NDR data
1717 for that to the NDR we initially generated. If they don't match then we know
1718 we must have a bug in either the pull or push side of our code
1720 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1721 TALLOC_CTX *mem_ctx,
1722 DATA_BLOB blob,
1723 size_t struct_size,
1724 ndr_push_flags_fn_t ndr_push,
1725 ndr_pull_flags_fn_t ndr_pull)
1727 void *st;
1728 struct ndr_pull *pull;
1729 struct ndr_push *push;
1730 DATA_BLOB blob2;
1731 enum ndr_err_code ndr_err;
1733 st = talloc_size(mem_ctx, struct_size);
1734 if (!st) {
1735 return NT_STATUS_NO_MEMORY;
1738 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1739 if (!pull) {
1740 return NT_STATUS_NO_MEMORY;
1742 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1744 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1745 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1748 if (c->flags & DCERPC_NDR64) {
1749 pull->flags |= LIBNDR_FLAG_NDR64;
1752 ndr_err = ndr_pull(pull, NDR_IN, st);
1753 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1754 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1755 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1756 "failed input validation pull - %s",
1757 nt_errstr(status));
1758 return ndr_map_error2ntstatus(ndr_err);
1761 push = ndr_push_init_ctx(mem_ctx);
1762 if (!push) {
1763 return NT_STATUS_NO_MEMORY;
1766 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1767 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1770 if (c->flags & DCERPC_NDR64) {
1771 push->flags |= LIBNDR_FLAG_NDR64;
1774 ndr_err = ndr_push(push, NDR_IN, st);
1775 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1776 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1777 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1778 "failed input validation push - %s",
1779 nt_errstr(status));
1780 return ndr_map_error2ntstatus(ndr_err);
1783 blob2 = ndr_push_blob(push);
1785 if (data_blob_cmp(&blob, &blob2) != 0) {
1786 DEBUG(3,("original:\n"));
1787 dump_data(3, blob.data, blob.length);
1788 DEBUG(3,("secondary:\n"));
1789 dump_data(3, blob2.data, blob2.length);
1790 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1791 "failed input validation blobs doesn't match");
1792 return ndr_map_error2ntstatus(ndr_err);
1795 return NT_STATUS_OK;
1799 this is a paranoid NDR input validator. For every packet we pull
1800 from the wire we push it back again then pull and push it
1801 again. Then we compare the raw NDR data for that to the NDR we
1802 initially generated. If they don't match then we know we must have a
1803 bug in either the pull or push side of our code
1805 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1806 struct ndr_pull *pull_in,
1807 void *struct_ptr,
1808 size_t struct_size,
1809 ndr_push_flags_fn_t ndr_push,
1810 ndr_pull_flags_fn_t ndr_pull,
1811 ndr_print_function_t ndr_print)
1813 void *st;
1814 struct ndr_pull *pull;
1815 struct ndr_push *push;
1816 DATA_BLOB blob, blob2;
1817 TALLOC_CTX *mem_ctx = pull_in;
1818 char *s1, *s2;
1819 enum ndr_err_code ndr_err;
1821 st = talloc_size(mem_ctx, struct_size);
1822 if (!st) {
1823 return NT_STATUS_NO_MEMORY;
1825 memcpy(st, struct_ptr, struct_size);
1827 push = ndr_push_init_ctx(mem_ctx);
1828 if (!push) {
1829 return NT_STATUS_NO_MEMORY;
1832 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1833 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1834 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1835 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1836 "failed output validation push - %s",
1837 nt_errstr(status));
1838 return ndr_map_error2ntstatus(ndr_err);
1841 blob = ndr_push_blob(push);
1843 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1844 if (!pull) {
1845 return NT_STATUS_NO_MEMORY;
1848 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1849 ndr_err = ndr_pull(pull, NDR_OUT, st);
1850 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1851 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1852 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1853 "failed output validation pull - %s",
1854 nt_errstr(status));
1855 return ndr_map_error2ntstatus(ndr_err);
1858 push = ndr_push_init_ctx(mem_ctx);
1859 if (!push) {
1860 return NT_STATUS_NO_MEMORY;
1863 ndr_err = ndr_push(push, NDR_OUT, st);
1864 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1865 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1866 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1867 "failed output validation push2 - %s",
1868 nt_errstr(status));
1869 return ndr_map_error2ntstatus(ndr_err);
1872 blob2 = ndr_push_blob(push);
1874 if (data_blob_cmp(&blob, &blob2) != 0) {
1875 DEBUG(3,("original:\n"));
1876 dump_data(3, blob.data, blob.length);
1877 DEBUG(3,("secondary:\n"));
1878 dump_data(3, blob2.data, blob2.length);
1879 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1880 "failed output validation blobs doesn't match");
1881 return ndr_map_error2ntstatus(ndr_err);
1884 /* this checks the printed forms of the two structures, which effectively
1885 tests all of the value() attributes */
1886 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1887 NDR_OUT, struct_ptr);
1888 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1889 NDR_OUT, st);
1890 if (strcmp(s1, s2) != 0) {
1891 #if 1
1892 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1893 #else
1894 /* this is sometimes useful */
1895 printf("VALIDATE ERROR\n");
1896 file_save("wire.dat", s1, strlen(s1));
1897 file_save("gen.dat", s2, strlen(s2));
1898 system("diff -u wire.dat gen.dat");
1899 #endif
1900 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1901 "failed output validation strings doesn't match");
1902 return ndr_map_error2ntstatus(ndr_err);
1905 return NT_STATUS_OK;
1909 a useful function for retrieving the server name we connected to
1911 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1913 if (!p->conn->transport.target_hostname) {
1914 if (!p->conn->transport.peer_name) {
1915 return "";
1917 return p->conn->transport.peer_name(p->conn);
1919 return p->conn->transport.target_hostname(p->conn);
1924 get the dcerpc auth_level for a open connection
1926 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1928 uint8_t auth_level;
1930 if (c->flags & DCERPC_SEAL) {
1931 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1932 } else if (c->flags & DCERPC_SIGN) {
1933 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1934 } else if (c->flags & DCERPC_CONNECT) {
1935 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1936 } else {
1937 auth_level = DCERPC_AUTH_LEVEL_NONE;
1939 return auth_level;
1942 struct dcerpc_alter_context_state {
1943 struct tevent_context *ev;
1944 struct dcerpc_pipe *p;
1947 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
1948 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
1949 DATA_BLOB *raw_packet,
1950 struct ncacn_packet *pkt);
1952 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
1953 struct tevent_context *ev,
1954 struct dcerpc_pipe *p,
1955 const struct ndr_syntax_id *syntax,
1956 const struct ndr_syntax_id *transfer_syntax)
1958 struct tevent_req *req;
1959 struct dcerpc_alter_context_state *state;
1960 struct ncacn_packet pkt;
1961 DATA_BLOB blob;
1962 NTSTATUS status;
1963 struct rpc_request *subreq;
1965 req = tevent_req_create(mem_ctx, &state,
1966 struct dcerpc_alter_context_state);
1967 if (req == NULL) {
1968 return NULL;
1971 state->ev = ev;
1972 state->p = p;
1974 p->syntax = *syntax;
1975 p->transfer_syntax = *transfer_syntax;
1977 init_ncacn_hdr(p->conn, &pkt);
1979 pkt.ptype = DCERPC_PKT_ALTER;
1980 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1981 pkt.call_id = p->conn->call_id;
1982 pkt.auth_length = 0;
1984 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1985 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1988 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1989 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1992 pkt.u.alter.max_xmit_frag = 5840;
1993 pkt.u.alter.max_recv_frag = 5840;
1994 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1995 pkt.u.alter.num_contexts = 1;
1996 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
1997 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
1998 return tevent_req_post(req, ev);
2000 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2001 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2002 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2003 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2004 pkt.u.alter.auth_info = data_blob(NULL, 0);
2006 /* construct the NDR form of the packet */
2007 status = ncacn_push_auth(&blob, state, &pkt,
2008 p->conn->security_state.auth_info);
2009 if (tevent_req_nterror(req, status)) {
2010 return tevent_req_post(req, ev);
2013 p->conn->transport.recv_data = dcerpc_recv_data;
2016 * we allocate a dcerpc_request so we can be in the same
2017 * request queue as normal requests
2019 subreq = talloc_zero(state, struct rpc_request);
2020 if (tevent_req_nomem(subreq, req)) {
2021 return tevent_req_post(req, ev);
2024 subreq->state = RPC_REQUEST_PENDING;
2025 subreq->call_id = pkt.call_id;
2026 subreq->async.private_data = req;
2027 subreq->async.callback = dcerpc_alter_context_fail_handler;
2028 subreq->p = p;
2029 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2030 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2031 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2033 status = p->conn->transport.send_request(p->conn, &blob, true);
2034 if (tevent_req_nterror(req, status)) {
2035 return tevent_req_post(req, ev);
2038 tevent_add_timer(ev, subreq,
2039 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2040 dcerpc_timeout_handler, subreq);
2042 return req;
2045 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2047 struct tevent_req *req =
2048 talloc_get_type_abort(subreq->async.private_data,
2049 struct tevent_req);
2050 struct dcerpc_alter_context_state *state =
2051 tevent_req_data(req,
2052 struct dcerpc_alter_context_state);
2053 NTSTATUS status = subreq->status;
2055 TALLOC_FREE(subreq);
2058 * We trigger the callback in the next event run
2059 * because the code in this file might trigger
2060 * multiple request callbacks from within a single
2061 * while loop.
2063 * In order to avoid segfaults from within
2064 * dcerpc_connection_dead() we call
2065 * tevent_req_defer_callback().
2067 tevent_req_defer_callback(req, state->ev);
2069 tevent_req_nterror(req, status);
2072 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2073 DATA_BLOB *raw_packet,
2074 struct ncacn_packet *pkt)
2076 struct tevent_req *req =
2077 talloc_get_type_abort(subreq->async.private_data,
2078 struct tevent_req);
2079 struct dcerpc_alter_context_state *state =
2080 tevent_req_data(req,
2081 struct dcerpc_alter_context_state);
2082 struct dcecli_connection *conn = state->p->conn;
2083 NTSTATUS status;
2086 * Note that pkt is allocated under raw_packet->data,
2087 * while raw_packet->data is a child of subreq.
2089 talloc_steal(state, raw_packet->data);
2090 TALLOC_FREE(subreq);
2093 * We trigger the callback in the next event run
2094 * because the code in this file might trigger
2095 * multiple request callbacks from within a single
2096 * while loop.
2098 * In order to avoid segfaults from within
2099 * dcerpc_connection_dead() we call
2100 * tevent_req_defer_callback().
2102 tevent_req_defer_callback(req, state->ev);
2104 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2105 pkt->u.alter_resp.num_results == 1 &&
2106 pkt->u.alter_resp.ctx_list[0].result != 0) {
2107 status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason);
2108 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2109 pkt->u.alter_resp.ctx_list[0].reason,
2110 nt_errstr(status)));
2111 tevent_req_nterror(req, status);
2112 return;
2115 if (pkt->ptype == DCERPC_PKT_FAULT) {
2116 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2117 dcerpc_errstr(state, pkt->u.fault.status)));
2118 state->p->last_fault_code = pkt->u.fault.status;
2119 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2120 return;
2123 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2124 pkt->u.alter_resp.num_results == 0 ||
2125 pkt->u.alter_resp.ctx_list[0].result != 0) {
2126 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2127 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2128 return;
2131 /* the alter_resp might contain a reply set of credentials */
2132 if (conn->security_state.auth_info &&
2133 pkt->u.alter_resp.auth_info.length) {
2134 uint32_t auth_length;
2136 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2137 conn->security_state.auth_info, &auth_length, true);
2138 if (tevent_req_nterror(req, status)) {
2139 return;
2143 tevent_req_done(req);
2146 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2148 return tevent_req_simple_recv_ntstatus(req);
2152 send a dcerpc alter_context request
2154 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2155 TALLOC_CTX *mem_ctx,
2156 const struct ndr_syntax_id *syntax,
2157 const struct ndr_syntax_id *transfer_syntax)
2159 struct tevent_req *subreq;
2160 struct tevent_context *ev = p->conn->event_ctx;
2161 bool ok;
2163 /* TODO: create a new event context here */
2165 subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx,
2166 p, syntax, transfer_syntax);
2167 if (subreq == NULL) {
2168 return NT_STATUS_NO_MEMORY;
2171 ok = tevent_req_poll(subreq, ev);
2172 if (!ok) {
2173 NTSTATUS status;
2174 status = map_nt_error_from_unix_common(errno);
2175 return status;
2178 return dcerpc_alter_context_recv(subreq);