s4:torture: send the TCONX_FLAG_EXTENDED_RESPONSE flag
[Samba/gebeck_regimport.git] / source4 / librpc / rpc / dcerpc.c
blob4cec4b596c79165748234c94f88057bc60c53762
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_blob(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 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
687 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
690 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
691 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
692 return ndr_map_error2ntstatus(ndr_err);
695 return NT_STATUS_OK;
699 parse the authentication information on a dcerpc response packet
701 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
702 DATA_BLOB *raw_packet,
703 struct ncacn_packet *pkt)
705 NTSTATUS status;
706 struct dcerpc_auth auth;
707 uint32_t auth_length;
709 if (!c->security_state.auth_info ||
710 !c->security_state.generic_state) {
711 return NT_STATUS_OK;
714 switch (c->security_state.auth_info->auth_level) {
715 case DCERPC_AUTH_LEVEL_PRIVACY:
716 case DCERPC_AUTH_LEVEL_INTEGRITY:
717 break;
719 case DCERPC_AUTH_LEVEL_CONNECT:
720 if (pkt->auth_length != 0) {
721 break;
723 return NT_STATUS_OK;
724 case DCERPC_AUTH_LEVEL_NONE:
725 if (pkt->auth_length != 0) {
726 return NT_STATUS_INVALID_NETWORK_RESPONSE;
728 return NT_STATUS_OK;
730 default:
731 return NT_STATUS_INVALID_LEVEL;
734 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
735 &pkt->u.response.stub_and_verifier,
736 &auth, &auth_length, false);
737 NT_STATUS_NOT_OK_RETURN(status);
739 pkt->u.response.stub_and_verifier.length -= auth_length;
741 /* check signature or unseal the packet */
742 switch (c->security_state.auth_info->auth_level) {
743 case DCERPC_AUTH_LEVEL_PRIVACY:
744 status = gensec_unseal_packet(c->security_state.generic_state,
745 raw_packet->data + DCERPC_REQUEST_LENGTH,
746 pkt->u.response.stub_and_verifier.length,
747 raw_packet->data,
748 raw_packet->length - auth.credentials.length,
749 &auth.credentials);
750 memcpy(pkt->u.response.stub_and_verifier.data,
751 raw_packet->data + DCERPC_REQUEST_LENGTH,
752 pkt->u.response.stub_and_verifier.length);
753 break;
755 case DCERPC_AUTH_LEVEL_INTEGRITY:
756 status = gensec_check_packet(c->security_state.generic_state,
757 pkt->u.response.stub_and_verifier.data,
758 pkt->u.response.stub_and_verifier.length,
759 raw_packet->data,
760 raw_packet->length - auth.credentials.length,
761 &auth.credentials);
762 break;
764 case DCERPC_AUTH_LEVEL_CONNECT:
765 /* for now we ignore possible signatures here */
766 status = NT_STATUS_OK;
767 break;
769 default:
770 status = NT_STATUS_INVALID_LEVEL;
771 break;
774 /* remove the indicated amount of padding */
775 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
776 return NT_STATUS_INFO_LENGTH_MISMATCH;
778 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
780 return status;
785 push a dcerpc request packet into a blob, possibly signing it.
787 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
788 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
789 size_t sig_size,
790 struct ncacn_packet *pkt)
792 NTSTATUS status;
793 struct ndr_push *ndr;
794 DATA_BLOB creds2;
795 size_t payload_length;
796 enum ndr_err_code ndr_err;
797 size_t hdr_size = DCERPC_REQUEST_LENGTH;
799 /* non-signed packets are simpler */
800 if (sig_size == 0) {
801 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
804 switch (c->security_state.auth_info->auth_level) {
805 case DCERPC_AUTH_LEVEL_PRIVACY:
806 case DCERPC_AUTH_LEVEL_INTEGRITY:
807 break;
809 case DCERPC_AUTH_LEVEL_CONNECT:
810 /* TODO: let the gensec mech decide if it wants to generate a signature */
811 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
813 case DCERPC_AUTH_LEVEL_NONE:
814 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
816 default:
817 return NT_STATUS_INVALID_LEVEL;
820 ndr = ndr_push_init_ctx(mem_ctx);
821 if (!ndr) {
822 return NT_STATUS_NO_MEMORY;
825 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
826 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
829 if (c->flags & DCERPC_NDR64) {
830 ndr->flags |= LIBNDR_FLAG_NDR64;
833 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
834 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
835 hdr_size += 16;
838 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
839 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
840 return ndr_map_error2ntstatus(ndr_err);
843 /* pad to 16 byte multiple in the payload portion of the
844 packet. This matches what w2k3 does. Note that we can't use
845 ndr_push_align() as that is relative to the start of the
846 whole packet, whereas w2k8 wants it relative to the start
847 of the stub */
848 c->security_state.auth_info->auth_pad_length =
849 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
850 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
851 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
852 return ndr_map_error2ntstatus(ndr_err);
855 payload_length = pkt->u.request.stub_and_verifier.length +
856 c->security_state.auth_info->auth_pad_length;
858 /* we start without signature, it will appended later */
859 c->security_state.auth_info->credentials = data_blob(NULL,0);
861 /* add the auth verifier */
862 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
863 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
864 return ndr_map_error2ntstatus(ndr_err);
867 /* extract the whole packet as a blob */
868 *blob = ndr_push_blob(ndr);
871 * Setup the frag and auth length in the packet buffer.
872 * This is needed if the GENSEC mech does AEAD signing
873 * of the packet headers. The signature itself will be
874 * appended later.
876 dcerpc_set_frag_length(blob, blob->length + sig_size);
877 dcerpc_set_auth_length(blob, sig_size);
879 /* sign or seal the packet */
880 switch (c->security_state.auth_info->auth_level) {
881 case DCERPC_AUTH_LEVEL_PRIVACY:
882 status = gensec_seal_packet(c->security_state.generic_state,
883 mem_ctx,
884 blob->data + hdr_size,
885 payload_length,
886 blob->data,
887 blob->length,
888 &creds2);
889 if (!NT_STATUS_IS_OK(status)) {
890 return status;
892 break;
894 case DCERPC_AUTH_LEVEL_INTEGRITY:
895 status = gensec_sign_packet(c->security_state.generic_state,
896 mem_ctx,
897 blob->data + hdr_size,
898 payload_length,
899 blob->data,
900 blob->length,
901 &creds2);
902 if (!NT_STATUS_IS_OK(status)) {
903 return status;
905 break;
907 default:
908 status = NT_STATUS_INVALID_LEVEL;
909 break;
912 if (creds2.length != sig_size) {
913 /* this means the sig_size estimate for the signature
914 was incorrect. We have to correct the packet
915 sizes. That means we could go over the max fragment
916 length */
917 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
918 (unsigned) creds2.length,
919 (unsigned) sig_size,
920 (unsigned) c->security_state.auth_info->auth_pad_length,
921 (unsigned) pkt->u.request.stub_and_verifier.length));
922 dcerpc_set_frag_length(blob, blob->length + creds2.length);
923 dcerpc_set_auth_length(blob, creds2.length);
926 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
927 return NT_STATUS_NO_MEMORY;
930 return NT_STATUS_OK;
935 fill in the fixed values in a dcerpc header
937 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
939 pkt->rpc_vers = 5;
940 pkt->rpc_vers_minor = 0;
941 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
942 pkt->drep[0] = 0;
943 } else {
944 pkt->drep[0] = DCERPC_DREP_LE;
946 pkt->drep[1] = 0;
947 pkt->drep[2] = 0;
948 pkt->drep[3] = 0;
952 map a bind nak reason to a NTSTATUS
954 static NTSTATUS dcerpc_map_reason(uint16_t reason)
956 switch (reason) {
957 case DCERPC_BIND_REASON_ASYNTAX:
958 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
959 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
960 return NT_STATUS_INVALID_PARAMETER;
962 return NT_STATUS_UNSUCCESSFUL;
966 remove requests from the pending or queued queues
968 static int dcerpc_req_dequeue(struct rpc_request *req)
970 switch (req->state) {
971 case RPC_REQUEST_QUEUED:
972 DLIST_REMOVE(req->p->conn->request_queue, req);
973 break;
974 case RPC_REQUEST_PENDING:
975 DLIST_REMOVE(req->p->conn->pending, req);
976 break;
977 case RPC_REQUEST_DONE:
978 break;
980 return 0;
985 mark the dcerpc connection dead. All outstanding requests get an error
987 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
989 if (conn->dead) return;
991 conn->dead = true;
993 TALLOC_FREE(conn->io_trigger);
994 conn->io_trigger_pending = false;
996 conn->transport.recv_data = NULL;
998 if (conn->transport.shutdown_pipe) {
999 conn->transport.shutdown_pipe(conn, status);
1002 /* all pending requests get the error */
1003 while (conn->pending) {
1004 struct rpc_request *req = conn->pending;
1005 dcerpc_req_dequeue(req);
1006 req->state = RPC_REQUEST_DONE;
1007 req->status = status;
1008 if (req->async.callback) {
1009 req->async.callback(req);
1013 /* all requests, which are not shipped */
1014 while (conn->request_queue) {
1015 struct rpc_request *req = conn->request_queue;
1016 dcerpc_req_dequeue(req);
1017 req->state = RPC_REQUEST_DONE;
1018 req->status = status;
1019 if (req->async.callback) {
1020 req->async.callback(req);
1024 talloc_set_destructor(conn, NULL);
1025 if (conn->free_skipped) {
1026 talloc_free(conn);
1031 forward declarations of the recv_data handlers for the types of
1032 packets we need to handle
1034 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1035 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1038 receive a dcerpc reply from the transport. Here we work out what
1039 type of reply it is (normal request, bind or alter context) and
1040 dispatch to the appropriate handler
1042 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1044 struct ncacn_packet pkt;
1046 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1047 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1050 /* the transport may be telling us of a severe error, such as
1051 a dropped socket */
1052 if (!NT_STATUS_IS_OK(status)) {
1053 data_blob_free(blob);
1054 dcerpc_connection_dead(conn, status);
1055 return;
1058 /* parse the basic packet to work out what type of response this is */
1059 status = ncacn_pull(conn, blob, blob->data, &pkt);
1060 if (!NT_STATUS_IS_OK(status)) {
1061 data_blob_free(blob);
1062 dcerpc_connection_dead(conn, status);
1063 return;
1066 dcerpc_request_recv_data(conn, blob, &pkt);
1070 handle timeouts of individual dcerpc requests
1072 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1073 struct timeval t, void *private_data)
1075 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1077 if (req->ignore_timeout) {
1078 dcerpc_req_dequeue(req);
1079 req->state = RPC_REQUEST_DONE;
1080 req->status = NT_STATUS_IO_TIMEOUT;
1081 if (req->async.callback) {
1082 req->async.callback(req);
1084 return;
1087 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1090 struct dcerpc_bind_state {
1091 struct tevent_context *ev;
1092 struct dcerpc_pipe *p;
1095 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1096 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1097 DATA_BLOB *raw_packet,
1098 struct ncacn_packet *pkt);
1100 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1101 struct tevent_context *ev,
1102 struct dcerpc_pipe *p,
1103 const struct ndr_syntax_id *syntax,
1104 const struct ndr_syntax_id *transfer_syntax)
1106 struct tevent_req *req;
1107 struct dcerpc_bind_state *state;
1108 struct ncacn_packet pkt;
1109 DATA_BLOB blob;
1110 NTSTATUS status;
1111 struct rpc_request *subreq;
1113 req = tevent_req_create(mem_ctx, &state,
1114 struct dcerpc_bind_state);
1115 if (req == NULL) {
1116 return NULL;
1119 state->ev = ev;
1120 state->p = p;
1122 p->syntax = *syntax;
1123 p->transfer_syntax = *transfer_syntax;
1125 init_ncacn_hdr(p->conn, &pkt);
1127 pkt.ptype = DCERPC_PKT_BIND;
1128 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1129 pkt.call_id = p->conn->call_id;
1130 pkt.auth_length = 0;
1132 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1133 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1136 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1137 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1140 pkt.u.bind.max_xmit_frag = 5840;
1141 pkt.u.bind.max_recv_frag = 5840;
1142 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1143 pkt.u.bind.num_contexts = 1;
1144 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1145 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1146 return tevent_req_post(req, ev);
1148 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1149 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1150 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1151 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1152 pkt.u.bind.auth_info = data_blob(NULL, 0);
1154 /* construct the NDR form of the packet */
1155 status = ncacn_push_auth(&blob, state, &pkt,
1156 p->conn->security_state.auth_info);
1157 if (tevent_req_nterror(req, status)) {
1158 return tevent_req_post(req, ev);
1161 p->conn->transport.recv_data = dcerpc_recv_data;
1164 * we allocate a dcerpc_request so we can be in the same
1165 * request queue as normal requests
1167 subreq = talloc_zero(state, struct rpc_request);
1168 if (tevent_req_nomem(subreq, req)) {
1169 return tevent_req_post(req, ev);
1172 subreq->state = RPC_REQUEST_PENDING;
1173 subreq->call_id = pkt.call_id;
1174 subreq->async.private_data = req;
1175 subreq->async.callback = dcerpc_bind_fail_handler;
1176 subreq->p = p;
1177 subreq->recv_handler = dcerpc_bind_recv_handler;
1178 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1179 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1181 status = p->conn->transport.send_request(p->conn, &blob, true);
1182 if (tevent_req_nterror(req, status)) {
1183 return tevent_req_post(req, ev);
1186 tevent_add_timer(ev, subreq,
1187 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1188 dcerpc_timeout_handler, subreq);
1190 return req;
1193 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1195 struct tevent_req *req =
1196 talloc_get_type_abort(subreq->async.private_data,
1197 struct tevent_req);
1198 struct dcerpc_bind_state *state =
1199 tevent_req_data(req,
1200 struct dcerpc_bind_state);
1201 NTSTATUS status = subreq->status;
1203 TALLOC_FREE(subreq);
1206 * We trigger the callback in the next event run
1207 * because the code in this file might trigger
1208 * multiple request callbacks from within a single
1209 * while loop.
1211 * In order to avoid segfaults from within
1212 * dcerpc_connection_dead() we call
1213 * tevent_req_defer_callback().
1215 tevent_req_defer_callback(req, state->ev);
1217 tevent_req_nterror(req, status);
1220 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1221 DATA_BLOB *raw_packet,
1222 struct ncacn_packet *pkt)
1224 struct tevent_req *req =
1225 talloc_get_type_abort(subreq->async.private_data,
1226 struct tevent_req);
1227 struct dcerpc_bind_state *state =
1228 tevent_req_data(req,
1229 struct dcerpc_bind_state);
1230 struct dcecli_connection *conn = state->p->conn;
1231 NTSTATUS status;
1234 * Note that pkt is allocated under raw_packet->data,
1235 * while raw_packet->data is a child of subreq.
1237 talloc_steal(state, raw_packet->data);
1238 TALLOC_FREE(subreq);
1241 * We trigger the callback in the next event run
1242 * because the code in this file might trigger
1243 * multiple request callbacks from within a single
1244 * while loop.
1246 * In order to avoid segfaults from within
1247 * dcerpc_connection_dead() we call
1248 * tevent_req_defer_callback().
1250 tevent_req_defer_callback(req, state->ev);
1252 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1253 status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason);
1255 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1256 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1258 tevent_req_nterror(req, status);
1259 return;
1262 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1263 (pkt->u.bind_ack.num_results == 0) ||
1264 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1265 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1266 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1267 return;
1270 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1271 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1273 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1274 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1275 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1278 if ((state->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1279 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1280 conn->flags |= DCERPC_HEADER_SIGNING;
1283 /* the bind_ack might contain a reply set of credentials */
1284 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1285 uint32_t auth_length;
1287 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1288 conn->security_state.auth_info, &auth_length, true);
1289 if (tevent_req_nterror(req, status)) {
1290 return;
1294 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1296 tevent_req_done(req);
1299 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1301 return tevent_req_simple_recv_ntstatus(req);
1305 perform a continued bind (and auth3)
1307 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1308 TALLOC_CTX *mem_ctx)
1310 struct ncacn_packet pkt;
1311 NTSTATUS status;
1312 DATA_BLOB blob;
1314 init_ncacn_hdr(p->conn, &pkt);
1316 pkt.ptype = DCERPC_PKT_AUTH3;
1317 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1318 pkt.call_id = next_call_id(p->conn);
1319 pkt.auth_length = 0;
1320 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1322 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1323 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1326 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1327 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1330 /* construct the NDR form of the packet */
1331 status = ncacn_push_auth(&blob, mem_ctx,
1332 &pkt,
1333 p->conn->security_state.auth_info);
1334 if (!NT_STATUS_IS_OK(status)) {
1335 return status;
1338 /* send it on its way */
1339 status = p->conn->transport.send_request(p->conn, &blob, false);
1340 if (!NT_STATUS_IS_OK(status)) {
1341 return status;
1344 return NT_STATUS_OK;
1349 process a fragment received from the transport layer during a
1350 request
1352 This function frees the data
1354 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1355 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1357 struct rpc_request *req;
1358 unsigned int length;
1359 NTSTATUS status = NT_STATUS_OK;
1362 if this is an authenticated connection then parse and check
1363 the auth info. We have to do this before finding the
1364 matching packet, as the request structure might have been
1365 removed due to a timeout, but if it has been we still need
1366 to run the auth routines so that we don't get the sign/seal
1367 info out of step with the server
1369 if (c->security_state.auth_info && c->security_state.generic_state &&
1370 pkt->ptype == DCERPC_PKT_RESPONSE) {
1371 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1374 /* find the matching request */
1375 for (req=c->pending;req;req=req->next) {
1376 if (pkt->call_id == req->call_id) break;
1379 #if 0
1380 /* useful for testing certain vendors RPC servers */
1381 if (req == NULL && c->pending && pkt->call_id == 0) {
1382 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1383 req = c->pending;
1385 #endif
1387 if (req == NULL) {
1388 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1389 data_blob_free(raw_packet);
1390 return;
1393 talloc_steal(req, raw_packet->data);
1395 if (req->recv_handler != NULL) {
1396 dcerpc_req_dequeue(req);
1397 req->state = RPC_REQUEST_DONE;
1398 req->recv_handler(req, raw_packet, pkt);
1399 return;
1402 if (pkt->ptype == DCERPC_PKT_FAULT) {
1403 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1404 req->fault_code = pkt->u.fault.status;
1405 req->status = NT_STATUS_NET_WRITE_FAULT;
1406 goto req_done;
1409 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1410 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1411 (int)pkt->ptype));
1412 req->fault_code = DCERPC_FAULT_OTHER;
1413 req->status = NT_STATUS_NET_WRITE_FAULT;
1414 goto req_done;
1417 /* now check the status from the auth routines, and if it failed then fail
1418 this request accordingly */
1419 if (!NT_STATUS_IS_OK(status)) {
1420 req->status = status;
1421 goto req_done;
1424 length = pkt->u.response.stub_and_verifier.length;
1426 if (length > 0) {
1427 req->payload.data = talloc_realloc(req,
1428 req->payload.data,
1429 uint8_t,
1430 req->payload.length + length);
1431 if (!req->payload.data) {
1432 req->status = NT_STATUS_NO_MEMORY;
1433 goto req_done;
1435 memcpy(req->payload.data+req->payload.length,
1436 pkt->u.response.stub_and_verifier.data, length);
1437 req->payload.length += length;
1440 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1441 c->transport.send_read(c);
1442 return;
1445 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1446 req->flags |= DCERPC_PULL_BIGENDIAN;
1447 } else {
1448 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1452 req_done:
1453 /* we've got the full payload */
1454 req->state = RPC_REQUEST_DONE;
1455 DLIST_REMOVE(c->pending, req);
1458 * We have to look at shipping further requests before calling
1459 * the async function, that one might close the pipe
1461 dcerpc_schedule_io_trigger(c);
1463 if (req->async.callback) {
1464 req->async.callback(req);
1469 perform the send side of a async dcerpc request
1471 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1472 struct dcerpc_pipe *p,
1473 const struct GUID *object,
1474 uint16_t opnum,
1475 DATA_BLOB *stub_data)
1477 struct rpc_request *req;
1479 p->conn->transport.recv_data = dcerpc_recv_data;
1481 req = talloc(mem_ctx, struct rpc_request);
1482 if (req == NULL) {
1483 return NULL;
1486 req->p = p;
1487 req->call_id = next_call_id(p->conn);
1488 req->status = NT_STATUS_OK;
1489 req->state = RPC_REQUEST_QUEUED;
1490 req->payload = data_blob(NULL, 0);
1491 req->flags = 0;
1492 req->fault_code = 0;
1493 req->ignore_timeout = false;
1494 req->async.callback = NULL;
1495 req->async.private_data = NULL;
1496 req->recv_handler = NULL;
1498 if (object != NULL) {
1499 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1500 if (req->object == NULL) {
1501 talloc_free(req);
1502 return NULL;
1504 } else {
1505 req->object = NULL;
1508 req->opnum = opnum;
1509 req->request_data.length = stub_data->length;
1510 req->request_data.data = stub_data->data;
1512 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1513 talloc_set_destructor(req, dcerpc_req_dequeue);
1515 dcerpc_schedule_io_trigger(p->conn);
1517 if (p->request_timeout) {
1518 tevent_add_timer(dcerpc_event_context(p), req,
1519 timeval_current_ofs(p->request_timeout, 0),
1520 dcerpc_timeout_handler, req);
1523 return req;
1527 Send a request using the transport
1530 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1532 struct rpc_request *req;
1533 struct dcerpc_pipe *p;
1534 DATA_BLOB *stub_data;
1535 struct ncacn_packet pkt;
1536 DATA_BLOB blob;
1537 uint32_t remaining, chunk_size;
1538 bool first_packet = true;
1539 size_t sig_size = 0;
1540 bool need_async = false;
1542 req = c->request_queue;
1543 if (req == NULL) {
1544 return;
1547 p = req->p;
1548 stub_data = &req->request_data;
1550 if (c->pending) {
1551 need_async = true;
1554 DLIST_REMOVE(c->request_queue, req);
1555 DLIST_ADD(c->pending, req);
1556 req->state = RPC_REQUEST_PENDING;
1558 init_ncacn_hdr(p->conn, &pkt);
1560 remaining = stub_data->length;
1562 /* we can write a full max_recv_frag size, minus the dcerpc
1563 request header size */
1564 chunk_size = p->conn->srv_max_recv_frag;
1565 chunk_size -= DCERPC_REQUEST_LENGTH;
1566 if (c->security_state.auth_info &&
1567 c->security_state.generic_state) {
1568 sig_size = gensec_sig_size(c->security_state.generic_state,
1569 p->conn->srv_max_recv_frag);
1570 if (sig_size) {
1571 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1572 chunk_size -= sig_size;
1575 chunk_size -= (chunk_size % 16);
1577 pkt.ptype = DCERPC_PKT_REQUEST;
1578 pkt.call_id = req->call_id;
1579 pkt.auth_length = 0;
1580 pkt.pfc_flags = 0;
1581 pkt.u.request.alloc_hint = remaining;
1582 pkt.u.request.context_id = p->context_id;
1583 pkt.u.request.opnum = req->opnum;
1585 if (req->object) {
1586 pkt.u.request.object.object = *req->object;
1587 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1588 chunk_size -= ndr_size_GUID(req->object,0);
1591 /* we send a series of pdus without waiting for a reply */
1592 while (remaining > 0 || first_packet) {
1593 uint32_t chunk = MIN(chunk_size, remaining);
1594 bool last_frag = false;
1595 bool do_trans = false;
1597 first_packet = false;
1598 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1600 if (remaining == stub_data->length) {
1601 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1603 if (chunk == remaining) {
1604 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1605 last_frag = true;
1608 pkt.u.request.stub_and_verifier.data = stub_data->data +
1609 (stub_data->length - remaining);
1610 pkt.u.request.stub_and_verifier.length = chunk;
1612 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1613 if (!NT_STATUS_IS_OK(req->status)) {
1614 req->state = RPC_REQUEST_DONE;
1615 DLIST_REMOVE(p->conn->pending, req);
1616 return;
1619 if (last_frag && !need_async) {
1620 do_trans = true;
1623 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1624 if (!NT_STATUS_IS_OK(req->status)) {
1625 req->state = RPC_REQUEST_DONE;
1626 DLIST_REMOVE(p->conn->pending, req);
1627 return;
1630 if (last_frag && !do_trans) {
1631 req->status = p->conn->transport.send_read(p->conn);
1632 if (!NT_STATUS_IS_OK(req->status)) {
1633 req->state = RPC_REQUEST_DONE;
1634 DLIST_REMOVE(p->conn->pending, req);
1635 return;
1639 remaining -= chunk;
1643 static void dcerpc_io_trigger(struct tevent_context *ctx,
1644 struct tevent_immediate *im,
1645 void *private_data)
1647 struct dcecli_connection *c =
1648 talloc_get_type_abort(private_data,
1649 struct dcecli_connection);
1651 c->io_trigger_pending = false;
1653 dcerpc_schedule_io_trigger(c);
1655 dcerpc_ship_next_request(c);
1658 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1660 if (c->dead) {
1661 return;
1664 if (c->request_queue == NULL) {
1665 return;
1668 if (c->io_trigger_pending) {
1669 return;
1672 c->io_trigger_pending = true;
1674 tevent_schedule_immediate(c->io_trigger,
1675 c->event_ctx,
1676 dcerpc_io_trigger,
1681 return the event context for a dcerpc pipe
1682 used by callers who wish to operate asynchronously
1684 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1686 return p->conn->event_ctx;
1692 perform the receive side of a async dcerpc request
1694 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1695 TALLOC_CTX *mem_ctx,
1696 DATA_BLOB *stub_data)
1698 NTSTATUS status;
1700 while (req->state != RPC_REQUEST_DONE) {
1701 struct tevent_context *ctx = dcerpc_event_context(req->p);
1702 if (tevent_loop_once(ctx) != 0) {
1703 return NT_STATUS_CONNECTION_DISCONNECTED;
1706 *stub_data = req->payload;
1707 status = req->status;
1708 if (stub_data->data) {
1709 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1711 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1712 req->p->last_fault_code = req->fault_code;
1714 talloc_unlink(talloc_parent(req), req);
1715 return status;
1719 this is a paranoid NDR validator. For every packet we push onto the wire
1720 we pull it back again, then push it again. Then we compare the raw NDR data
1721 for that to the NDR we initially generated. If they don't match then we know
1722 we must have a bug in either the pull or push side of our code
1724 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1725 TALLOC_CTX *mem_ctx,
1726 DATA_BLOB blob,
1727 size_t struct_size,
1728 ndr_push_flags_fn_t ndr_push,
1729 ndr_pull_flags_fn_t ndr_pull)
1731 void *st;
1732 struct ndr_pull *pull;
1733 struct ndr_push *push;
1734 DATA_BLOB blob2;
1735 enum ndr_err_code ndr_err;
1737 st = talloc_size(mem_ctx, struct_size);
1738 if (!st) {
1739 return NT_STATUS_NO_MEMORY;
1742 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1743 if (!pull) {
1744 return NT_STATUS_NO_MEMORY;
1746 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1748 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1749 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1752 if (c->flags & DCERPC_NDR64) {
1753 pull->flags |= LIBNDR_FLAG_NDR64;
1756 ndr_err = ndr_pull(pull, NDR_IN, st);
1757 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1758 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1759 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1760 "failed input validation pull - %s",
1761 nt_errstr(status));
1762 return ndr_map_error2ntstatus(ndr_err);
1765 push = ndr_push_init_ctx(mem_ctx);
1766 if (!push) {
1767 return NT_STATUS_NO_MEMORY;
1770 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1771 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1774 if (c->flags & DCERPC_NDR64) {
1775 push->flags |= LIBNDR_FLAG_NDR64;
1778 ndr_err = ndr_push(push, NDR_IN, st);
1779 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1780 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1781 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1782 "failed input validation push - %s",
1783 nt_errstr(status));
1784 return ndr_map_error2ntstatus(ndr_err);
1787 blob2 = ndr_push_blob(push);
1789 if (data_blob_cmp(&blob, &blob2) != 0) {
1790 DEBUG(3,("original:\n"));
1791 dump_data(3, blob.data, blob.length);
1792 DEBUG(3,("secondary:\n"));
1793 dump_data(3, blob2.data, blob2.length);
1794 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1795 "failed input validation blobs doesn't match");
1796 return ndr_map_error2ntstatus(ndr_err);
1799 return NT_STATUS_OK;
1803 this is a paranoid NDR input validator. For every packet we pull
1804 from the wire we push it back again then pull and push it
1805 again. Then we compare the raw NDR data for that to the NDR we
1806 initially generated. If they don't match then we know we must have a
1807 bug in either the pull or push side of our code
1809 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1810 struct ndr_pull *pull_in,
1811 void *struct_ptr,
1812 size_t struct_size,
1813 ndr_push_flags_fn_t ndr_push,
1814 ndr_pull_flags_fn_t ndr_pull,
1815 ndr_print_function_t ndr_print)
1817 void *st;
1818 struct ndr_pull *pull;
1819 struct ndr_push *push;
1820 DATA_BLOB blob, blob2;
1821 TALLOC_CTX *mem_ctx = pull_in;
1822 char *s1, *s2;
1823 enum ndr_err_code ndr_err;
1825 st = talloc_size(mem_ctx, struct_size);
1826 if (!st) {
1827 return NT_STATUS_NO_MEMORY;
1829 memcpy(st, struct_ptr, struct_size);
1831 push = ndr_push_init_ctx(mem_ctx);
1832 if (!push) {
1833 return NT_STATUS_NO_MEMORY;
1836 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1837 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1838 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1839 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1840 "failed output validation push - %s",
1841 nt_errstr(status));
1842 return ndr_map_error2ntstatus(ndr_err);
1845 blob = ndr_push_blob(push);
1847 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1848 if (!pull) {
1849 return NT_STATUS_NO_MEMORY;
1852 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1853 ndr_err = ndr_pull(pull, NDR_OUT, st);
1854 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1855 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1856 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1857 "failed output validation pull - %s",
1858 nt_errstr(status));
1859 return ndr_map_error2ntstatus(ndr_err);
1862 push = ndr_push_init_ctx(mem_ctx);
1863 if (!push) {
1864 return NT_STATUS_NO_MEMORY;
1867 ndr_err = ndr_push(push, NDR_OUT, st);
1868 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1869 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1870 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1871 "failed output validation push2 - %s",
1872 nt_errstr(status));
1873 return ndr_map_error2ntstatus(ndr_err);
1876 blob2 = ndr_push_blob(push);
1878 if (data_blob_cmp(&blob, &blob2) != 0) {
1879 DEBUG(3,("original:\n"));
1880 dump_data(3, blob.data, blob.length);
1881 DEBUG(3,("secondary:\n"));
1882 dump_data(3, blob2.data, blob2.length);
1883 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1884 "failed output validation blobs doesn't match");
1885 return ndr_map_error2ntstatus(ndr_err);
1888 /* this checks the printed forms of the two structures, which effectively
1889 tests all of the value() attributes */
1890 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1891 NDR_OUT, struct_ptr);
1892 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1893 NDR_OUT, st);
1894 if (strcmp(s1, s2) != 0) {
1895 #if 1
1896 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1897 #else
1898 /* this is sometimes useful */
1899 printf("VALIDATE ERROR\n");
1900 file_save("wire.dat", s1, strlen(s1));
1901 file_save("gen.dat", s2, strlen(s2));
1902 system("diff -u wire.dat gen.dat");
1903 #endif
1904 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1905 "failed output validation strings doesn't match");
1906 return ndr_map_error2ntstatus(ndr_err);
1909 return NT_STATUS_OK;
1913 a useful function for retrieving the server name we connected to
1915 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1917 if (!p->conn->transport.target_hostname) {
1918 if (!p->conn->transport.peer_name) {
1919 return "";
1921 return p->conn->transport.peer_name(p->conn);
1923 return p->conn->transport.target_hostname(p->conn);
1928 get the dcerpc auth_level for a open connection
1930 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1932 uint8_t auth_level;
1934 if (c->flags & DCERPC_SEAL) {
1935 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1936 } else if (c->flags & DCERPC_SIGN) {
1937 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1938 } else if (c->flags & DCERPC_CONNECT) {
1939 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1940 } else {
1941 auth_level = DCERPC_AUTH_LEVEL_NONE;
1943 return auth_level;
1946 struct dcerpc_alter_context_state {
1947 struct tevent_context *ev;
1948 struct dcerpc_pipe *p;
1951 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
1952 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
1953 DATA_BLOB *raw_packet,
1954 struct ncacn_packet *pkt);
1956 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
1957 struct tevent_context *ev,
1958 struct dcerpc_pipe *p,
1959 const struct ndr_syntax_id *syntax,
1960 const struct ndr_syntax_id *transfer_syntax)
1962 struct tevent_req *req;
1963 struct dcerpc_alter_context_state *state;
1964 struct ncacn_packet pkt;
1965 DATA_BLOB blob;
1966 NTSTATUS status;
1967 struct rpc_request *subreq;
1969 req = tevent_req_create(mem_ctx, &state,
1970 struct dcerpc_alter_context_state);
1971 if (req == NULL) {
1972 return NULL;
1975 state->ev = ev;
1976 state->p = p;
1978 p->syntax = *syntax;
1979 p->transfer_syntax = *transfer_syntax;
1981 init_ncacn_hdr(p->conn, &pkt);
1983 pkt.ptype = DCERPC_PKT_ALTER;
1984 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1985 pkt.call_id = p->conn->call_id;
1986 pkt.auth_length = 0;
1988 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1989 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1992 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1993 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1996 pkt.u.alter.max_xmit_frag = 5840;
1997 pkt.u.alter.max_recv_frag = 5840;
1998 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1999 pkt.u.alter.num_contexts = 1;
2000 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2001 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2002 return tevent_req_post(req, ev);
2004 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2005 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2006 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2007 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2008 pkt.u.alter.auth_info = data_blob(NULL, 0);
2010 /* construct the NDR form of the packet */
2011 status = ncacn_push_auth(&blob, state, &pkt,
2012 p->conn->security_state.auth_info);
2013 if (tevent_req_nterror(req, status)) {
2014 return tevent_req_post(req, ev);
2017 p->conn->transport.recv_data = dcerpc_recv_data;
2020 * we allocate a dcerpc_request so we can be in the same
2021 * request queue as normal requests
2023 subreq = talloc_zero(state, struct rpc_request);
2024 if (tevent_req_nomem(subreq, req)) {
2025 return tevent_req_post(req, ev);
2028 subreq->state = RPC_REQUEST_PENDING;
2029 subreq->call_id = pkt.call_id;
2030 subreq->async.private_data = req;
2031 subreq->async.callback = dcerpc_alter_context_fail_handler;
2032 subreq->p = p;
2033 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2034 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2035 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2037 status = p->conn->transport.send_request(p->conn, &blob, true);
2038 if (tevent_req_nterror(req, status)) {
2039 return tevent_req_post(req, ev);
2042 tevent_add_timer(ev, subreq,
2043 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2044 dcerpc_timeout_handler, subreq);
2046 return req;
2049 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2051 struct tevent_req *req =
2052 talloc_get_type_abort(subreq->async.private_data,
2053 struct tevent_req);
2054 struct dcerpc_alter_context_state *state =
2055 tevent_req_data(req,
2056 struct dcerpc_alter_context_state);
2057 NTSTATUS status = subreq->status;
2059 TALLOC_FREE(subreq);
2062 * We trigger the callback in the next event run
2063 * because the code in this file might trigger
2064 * multiple request callbacks from within a single
2065 * while loop.
2067 * In order to avoid segfaults from within
2068 * dcerpc_connection_dead() we call
2069 * tevent_req_defer_callback().
2071 tevent_req_defer_callback(req, state->ev);
2073 tevent_req_nterror(req, status);
2076 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2077 DATA_BLOB *raw_packet,
2078 struct ncacn_packet *pkt)
2080 struct tevent_req *req =
2081 talloc_get_type_abort(subreq->async.private_data,
2082 struct tevent_req);
2083 struct dcerpc_alter_context_state *state =
2084 tevent_req_data(req,
2085 struct dcerpc_alter_context_state);
2086 struct dcecli_connection *conn = state->p->conn;
2087 NTSTATUS status;
2090 * Note that pkt is allocated under raw_packet->data,
2091 * while raw_packet->data is a child of subreq.
2093 talloc_steal(state, raw_packet->data);
2094 TALLOC_FREE(subreq);
2097 * We trigger the callback in the next event run
2098 * because the code in this file might trigger
2099 * multiple request callbacks from within a single
2100 * while loop.
2102 * In order to avoid segfaults from within
2103 * dcerpc_connection_dead() we call
2104 * tevent_req_defer_callback().
2106 tevent_req_defer_callback(req, state->ev);
2108 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2109 pkt->u.alter_resp.num_results == 1 &&
2110 pkt->u.alter_resp.ctx_list[0].result != 0) {
2111 status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason);
2112 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2113 pkt->u.alter_resp.ctx_list[0].reason,
2114 nt_errstr(status)));
2115 tevent_req_nterror(req, status);
2116 return;
2119 if (pkt->ptype == DCERPC_PKT_FAULT) {
2120 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2121 dcerpc_errstr(state, pkt->u.fault.status)));
2122 state->p->last_fault_code = pkt->u.fault.status;
2123 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2124 return;
2127 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2128 pkt->u.alter_resp.num_results == 0 ||
2129 pkt->u.alter_resp.ctx_list[0].result != 0) {
2130 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2131 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2132 return;
2135 /* the alter_resp might contain a reply set of credentials */
2136 if (conn->security_state.auth_info &&
2137 pkt->u.alter_resp.auth_info.length) {
2138 uint32_t auth_length;
2140 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2141 conn->security_state.auth_info, &auth_length, true);
2142 if (tevent_req_nterror(req, status)) {
2143 return;
2147 tevent_req_done(req);
2150 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2152 return tevent_req_simple_recv_ntstatus(req);
2156 send a dcerpc alter_context request
2158 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2159 TALLOC_CTX *mem_ctx,
2160 const struct ndr_syntax_id *syntax,
2161 const struct ndr_syntax_id *transfer_syntax)
2163 struct tevent_req *subreq;
2164 struct tevent_context *ev = p->conn->event_ctx;
2165 bool ok;
2167 /* TODO: create a new event context here */
2169 subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx,
2170 p, syntax, transfer_syntax);
2171 if (subreq == NULL) {
2172 return NT_STATUS_NO_MEMORY;
2175 ok = tevent_req_poll(subreq, ev);
2176 if (!ok) {
2177 NTSTATUS status;
2178 status = map_nt_error_from_unix_common(errno);
2179 return status;
2182 return dcerpc_alter_context_recv(subreq);