s3: Pass down smb_filename to smbacl4_fill_ace4
[Samba/gebeck_regimport.git] / source4 / librpc / rpc / dcerpc.c
blob4440395e94ecf6e95759b1eb087e80695f156294
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;
63 bool wait_for_sync;
65 /* use by the ndr level async recv call */
66 struct {
67 const struct ndr_interface_table *table;
68 uint32_t opnum;
69 void *struct_ptr;
70 TALLOC_CTX *mem_ctx;
71 } ndr;
73 struct {
74 void (*callback)(struct rpc_request *);
75 void *private_data;
76 } async;
79 _PUBLIC_ NTSTATUS dcerpc_init(void)
81 return gensec_init();
84 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
85 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
87 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
88 struct dcerpc_pipe *p,
89 const struct GUID *object,
90 uint16_t opnum,
91 DATA_BLOB *stub_data);
92 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
93 TALLOC_CTX *mem_ctx,
94 DATA_BLOB *stub_data);
95 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
96 TALLOC_CTX *mem_ctx,
97 DATA_BLOB blob,
98 size_t struct_size,
99 ndr_push_flags_fn_t ndr_push,
100 ndr_pull_flags_fn_t ndr_pull);
101 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
102 struct ndr_pull *pull_in,
103 void *struct_ptr,
104 size_t struct_size,
105 ndr_push_flags_fn_t ndr_push,
106 ndr_pull_flags_fn_t ndr_pull,
107 ndr_print_function_t ndr_print);
109 /* destroy a dcerpc connection */
110 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
112 if (conn->dead) {
113 conn->free_skipped = true;
114 return -1;
116 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
117 return 0;
121 /* initialise a dcerpc connection.
122 the event context is optional
124 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
125 struct tevent_context *ev)
127 struct dcecli_connection *c;
129 c = talloc_zero(mem_ctx, struct dcecli_connection);
130 if (!c) {
131 return NULL;
134 c->event_ctx = ev;
136 if (c->event_ctx == NULL) {
137 talloc_free(c);
138 return NULL;
141 c->call_id = 1;
142 c->security_state.auth_info = NULL;
143 c->security_state.session_key = dcerpc_generic_session_key;
144 c->security_state.generic_state = NULL;
145 c->binding_string = NULL;
146 c->flags = 0;
147 c->srv_max_xmit_frag = 0;
148 c->srv_max_recv_frag = 0;
149 c->pending = NULL;
151 c->io_trigger = tevent_create_immediate(c);
152 if (c->io_trigger == NULL) {
153 talloc_free(c);
154 return NULL;
157 talloc_set_destructor(c, dcerpc_connection_destructor);
159 return c;
162 struct dcerpc_bh_state {
163 struct dcerpc_pipe *p;
166 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
168 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
169 struct dcerpc_bh_state);
171 if (!hs->p) {
172 return false;
175 if (!hs->p->conn) {
176 return false;
179 if (hs->p->conn->dead) {
180 return false;
183 return true;
186 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
187 uint32_t timeout)
189 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
190 struct dcerpc_bh_state);
191 uint32_t old;
193 if (!hs->p) {
194 return DCERPC_REQUEST_TIMEOUT;
197 old = hs->p->request_timeout;
198 hs->p->request_timeout = timeout;
200 return old;
203 struct dcerpc_bh_raw_call_state {
204 struct tevent_context *ev;
205 struct dcerpc_binding_handle *h;
206 DATA_BLOB in_data;
207 DATA_BLOB out_data;
208 uint32_t out_flags;
211 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
213 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
214 struct tevent_context *ev,
215 struct dcerpc_binding_handle *h,
216 const struct GUID *object,
217 uint32_t opnum,
218 uint32_t in_flags,
219 const uint8_t *in_data,
220 size_t in_length)
222 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
223 struct dcerpc_bh_state);
224 struct tevent_req *req;
225 struct dcerpc_bh_raw_call_state *state;
226 bool ok;
227 struct rpc_request *subreq;
229 req = tevent_req_create(mem_ctx, &state,
230 struct dcerpc_bh_raw_call_state);
231 if (req == NULL) {
232 return NULL;
234 state->ev = ev;
235 state->h = h;
236 state->in_data.data = discard_const_p(uint8_t, in_data);
237 state->in_data.length = in_length;
239 ok = dcerpc_bh_is_connected(h);
240 if (!ok) {
241 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
242 return tevent_req_post(req, ev);
245 subreq = dcerpc_request_send(state,
246 hs->p,
247 object,
248 opnum,
249 &state->in_data);
250 if (tevent_req_nomem(subreq, req)) {
251 return tevent_req_post(req, ev);
253 subreq->async.callback = dcerpc_bh_raw_call_done;
254 subreq->async.private_data = req;
256 return req;
259 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
261 struct tevent_req *req =
262 talloc_get_type_abort(subreq->async.private_data,
263 struct tevent_req);
264 struct dcerpc_bh_raw_call_state *state =
265 tevent_req_data(req,
266 struct dcerpc_bh_raw_call_state);
267 NTSTATUS status;
268 uint32_t fault_code;
270 state->out_flags = 0;
271 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
272 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
275 fault_code = subreq->fault_code;
277 status = dcerpc_request_recv(subreq, state, &state->out_data);
278 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
279 status = dcerpc_fault_to_nt_status(fault_code);
283 * We trigger the callback in the next event run
284 * because the code in this file might trigger
285 * multiple request callbacks from within a single
286 * while loop.
288 * In order to avoid segfaults from within
289 * dcerpc_connection_dead() we call
290 * tevent_req_defer_callback().
292 tevent_req_defer_callback(req, state->ev);
294 if (!NT_STATUS_IS_OK(status)) {
295 tevent_req_nterror(req, status);
296 return;
299 tevent_req_done(req);
302 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
303 TALLOC_CTX *mem_ctx,
304 uint8_t **out_data,
305 size_t *out_length,
306 uint32_t *out_flags)
308 struct dcerpc_bh_raw_call_state *state =
309 tevent_req_data(req,
310 struct dcerpc_bh_raw_call_state);
311 NTSTATUS status;
313 if (tevent_req_is_nterror(req, &status)) {
314 tevent_req_received(req);
315 return status;
318 *out_data = talloc_move(mem_ctx, &state->out_data.data);
319 *out_length = state->out_data.length;
320 *out_flags = state->out_flags;
321 tevent_req_received(req);
322 return NT_STATUS_OK;
325 struct dcerpc_bh_disconnect_state {
326 uint8_t _dummy;
329 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
330 struct tevent_context *ev,
331 struct dcerpc_binding_handle *h)
333 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
334 struct dcerpc_bh_state);
335 struct tevent_req *req;
336 struct dcerpc_bh_disconnect_state *state;
337 bool ok;
339 req = tevent_req_create(mem_ctx, &state,
340 struct dcerpc_bh_disconnect_state);
341 if (req == NULL) {
342 return NULL;
345 ok = dcerpc_bh_is_connected(h);
346 if (!ok) {
347 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
348 return tevent_req_post(req, ev);
351 /* TODO: do a real disconnect ... */
352 hs->p = NULL;
354 tevent_req_done(req);
355 return tevent_req_post(req, ev);
358 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
360 NTSTATUS status;
362 if (tevent_req_is_nterror(req, &status)) {
363 tevent_req_received(req);
364 return status;
367 tevent_req_received(req);
368 return NT_STATUS_OK;
371 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
373 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
374 struct dcerpc_bh_state);
376 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
377 return true;
380 return false;
383 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
385 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
386 struct dcerpc_bh_state);
388 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
389 return true;
392 return false;
395 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
397 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
398 struct dcerpc_bh_state);
400 if (hs->p->conn->flags & DCERPC_NDR64) {
401 return true;
404 return false;
407 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
408 int ndr_flags,
409 const void *_struct_ptr,
410 const struct ndr_interface_call *call)
412 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
413 struct dcerpc_bh_state);
414 void *struct_ptr = discard_const(_struct_ptr);
416 if (ndr_flags & NDR_IN) {
417 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
418 ndr_print_function_debug(call->ndr_print,
419 call->name,
420 ndr_flags,
421 struct_ptr);
424 if (ndr_flags & NDR_OUT) {
425 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
426 ndr_print_function_debug(call->ndr_print,
427 call->name,
428 ndr_flags,
429 struct_ptr);
434 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
435 NTSTATUS error,
436 const void *struct_ptr,
437 const struct ndr_interface_call *call)
439 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
440 call->name, nt_errstr(error)));
443 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
444 NTSTATUS error,
445 const DATA_BLOB *blob,
446 const struct ndr_interface_call *call)
448 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
449 struct dcerpc_bh_state);
450 const uint32_t num_examples = 20;
451 uint32_t i;
453 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
454 call->name, nt_errstr(error)));
456 if (hs->p->conn->packet_log_dir == NULL) return;
458 for (i=0;i<num_examples;i++) {
459 char *name=NULL;
460 asprintf(&name, "%s/rpclog/%s-out.%d",
461 hs->p->conn->packet_log_dir,
462 call->name, i);
463 if (name == NULL) {
464 return;
466 if (!file_exist(name)) {
467 if (file_save(name, blob->data, blob->length)) {
468 DEBUG(10,("Logged rpc packet to %s\n", name));
470 free(name);
471 break;
473 free(name);
477 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
478 TALLOC_CTX *mem_ctx,
479 const DATA_BLOB *blob,
480 const struct ndr_interface_call *call)
482 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
483 struct dcerpc_bh_state);
485 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
486 NTSTATUS status;
488 status = dcerpc_ndr_validate_in(hs->p->conn,
489 mem_ctx,
490 *blob,
491 call->struct_size,
492 call->ndr_push,
493 call->ndr_pull);
494 if (!NT_STATUS_IS_OK(status)) {
495 DEBUG(0,("Validation [in] failed for %s - %s\n",
496 call->name, nt_errstr(status)));
497 return status;
501 DEBUG(10,("rpc request data:\n"));
502 dump_data(10, blob->data, blob->length);
504 return NT_STATUS_OK;
507 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
508 struct ndr_pull *pull_in,
509 const void *_struct_ptr,
510 const struct ndr_interface_call *call)
512 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
513 struct dcerpc_bh_state);
514 void *struct_ptr = discard_const(_struct_ptr);
516 DEBUG(10,("rpc reply data:\n"));
517 dump_data(10, pull_in->data, pull_in->data_size);
519 if (pull_in->offset != pull_in->data_size) {
520 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
521 pull_in->data_size - pull_in->offset,
522 pull_in->offset, pull_in->offset,
523 call->name));
524 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
525 but it turns out that early versions of NT
526 (specifically NT3.1) add junk onto the end of rpc
527 packets, so if we want to interoperate at all with
528 those versions then we need to ignore this error */
531 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
532 NTSTATUS status;
534 status = dcerpc_ndr_validate_out(hs->p->conn,
535 pull_in,
536 struct_ptr,
537 call->struct_size,
538 call->ndr_push,
539 call->ndr_pull,
540 call->ndr_print);
541 if (!NT_STATUS_IS_OK(status)) {
542 DEBUG(2,("Validation [out] failed for %s - %s\n",
543 call->name, nt_errstr(status)));
544 return status;
548 return NT_STATUS_OK;
551 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
552 .name = "dcerpc",
553 .is_connected = dcerpc_bh_is_connected,
554 .set_timeout = dcerpc_bh_set_timeout,
555 .raw_call_send = dcerpc_bh_raw_call_send,
556 .raw_call_recv = dcerpc_bh_raw_call_recv,
557 .disconnect_send = dcerpc_bh_disconnect_send,
558 .disconnect_recv = dcerpc_bh_disconnect_recv,
560 .push_bigendian = dcerpc_bh_push_bigendian,
561 .ref_alloc = dcerpc_bh_ref_alloc,
562 .use_ndr64 = dcerpc_bh_use_ndr64,
563 .do_ndr_print = dcerpc_bh_do_ndr_print,
564 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
565 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
566 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
567 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
570 /* initialise a dcerpc pipe. */
571 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
573 struct dcerpc_binding_handle *h;
574 struct dcerpc_bh_state *hs;
576 h = dcerpc_binding_handle_create(p,
577 &dcerpc_bh_ops,
578 NULL,
579 NULL, /* TODO */
580 &hs,
581 struct dcerpc_bh_state,
582 __location__);
583 if (h == NULL) {
584 return NULL;
586 hs->p = p;
588 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
590 return h;
593 /* initialise a dcerpc pipe. */
594 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
596 struct dcerpc_pipe *p;
598 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
599 if (!p) {
600 return NULL;
603 p->conn = dcerpc_connection_init(p, ev);
604 if (p->conn == NULL) {
605 talloc_free(p);
606 return NULL;
609 p->last_fault_code = 0;
610 p->context_id = 0;
611 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
612 p->binding = NULL;
614 ZERO_STRUCT(p->syntax);
615 ZERO_STRUCT(p->transfer_syntax);
617 if (DEBUGLVL(100)) {
618 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
621 p->binding_handle = dcerpc_pipe_binding_handle(p);
622 if (p->binding_handle == NULL) {
623 talloc_free(p);
624 return NULL;
627 return p;
632 choose the next call id to use
634 static uint32_t next_call_id(struct dcecli_connection *c)
636 c->call_id++;
637 if (c->call_id == 0) {
638 c->call_id++;
640 return c->call_id;
644 setup for a ndr pull, also setting up any flags from the binding string
646 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
647 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
649 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
651 if (ndr == NULL) return ndr;
653 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
654 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
657 if (c->flags & DCERPC_NDR_REF_ALLOC) {
658 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
661 if (c->flags & DCERPC_NDR64) {
662 ndr->flags |= LIBNDR_FLAG_NDR64;
665 return ndr;
669 parse a data blob into a ncacn_packet structure. This handles both
670 input and output packets
672 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
673 struct ncacn_packet *pkt)
675 struct ndr_pull *ndr;
676 enum ndr_err_code ndr_err;
678 ndr = ndr_pull_init_blob(blob, mem_ctx);
679 if (!ndr) {
680 return NT_STATUS_NO_MEMORY;
683 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
684 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
687 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
688 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
691 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
692 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
693 return ndr_map_error2ntstatus(ndr_err);
696 return NT_STATUS_OK;
700 parse the authentication information on a dcerpc response packet
702 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
703 DATA_BLOB *raw_packet,
704 struct ncacn_packet *pkt)
706 NTSTATUS status;
707 struct dcerpc_auth auth;
708 uint32_t auth_length;
710 if (!c->security_state.auth_info ||
711 !c->security_state.generic_state) {
712 return NT_STATUS_OK;
715 switch (c->security_state.auth_info->auth_level) {
716 case DCERPC_AUTH_LEVEL_PRIVACY:
717 case DCERPC_AUTH_LEVEL_INTEGRITY:
718 break;
720 case DCERPC_AUTH_LEVEL_CONNECT:
721 if (pkt->auth_length != 0) {
722 break;
724 return NT_STATUS_OK;
725 case DCERPC_AUTH_LEVEL_NONE:
726 if (pkt->auth_length != 0) {
727 return NT_STATUS_INVALID_NETWORK_RESPONSE;
729 return NT_STATUS_OK;
731 default:
732 return NT_STATUS_INVALID_LEVEL;
735 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
736 &pkt->u.response.stub_and_verifier,
737 &auth, &auth_length, false);
738 NT_STATUS_NOT_OK_RETURN(status);
740 pkt->u.response.stub_and_verifier.length -= auth_length;
742 /* check signature or unseal the packet */
743 switch (c->security_state.auth_info->auth_level) {
744 case DCERPC_AUTH_LEVEL_PRIVACY:
745 status = gensec_unseal_packet(c->security_state.generic_state,
746 raw_packet->data + DCERPC_REQUEST_LENGTH,
747 pkt->u.response.stub_and_verifier.length,
748 raw_packet->data,
749 raw_packet->length - auth.credentials.length,
750 &auth.credentials);
751 memcpy(pkt->u.response.stub_and_verifier.data,
752 raw_packet->data + DCERPC_REQUEST_LENGTH,
753 pkt->u.response.stub_and_verifier.length);
754 break;
756 case DCERPC_AUTH_LEVEL_INTEGRITY:
757 status = gensec_check_packet(c->security_state.generic_state,
758 pkt->u.response.stub_and_verifier.data,
759 pkt->u.response.stub_and_verifier.length,
760 raw_packet->data,
761 raw_packet->length - auth.credentials.length,
762 &auth.credentials);
763 break;
765 case DCERPC_AUTH_LEVEL_CONNECT:
766 /* for now we ignore possible signatures here */
767 status = NT_STATUS_OK;
768 break;
770 default:
771 status = NT_STATUS_INVALID_LEVEL;
772 break;
775 /* remove the indicated amount of padding */
776 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
777 return NT_STATUS_INFO_LENGTH_MISMATCH;
779 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
781 return status;
786 push a dcerpc request packet into a blob, possibly signing it.
788 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
789 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
790 size_t sig_size,
791 struct ncacn_packet *pkt)
793 NTSTATUS status;
794 struct ndr_push *ndr;
795 DATA_BLOB creds2;
796 size_t payload_length;
797 enum ndr_err_code ndr_err;
798 size_t hdr_size = DCERPC_REQUEST_LENGTH;
800 /* non-signed packets are simpler */
801 if (sig_size == 0) {
802 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
805 switch (c->security_state.auth_info->auth_level) {
806 case DCERPC_AUTH_LEVEL_PRIVACY:
807 case DCERPC_AUTH_LEVEL_INTEGRITY:
808 break;
810 case DCERPC_AUTH_LEVEL_CONNECT:
811 /* TODO: let the gensec mech decide if it wants to generate a signature */
812 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
814 case DCERPC_AUTH_LEVEL_NONE:
815 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
817 default:
818 return NT_STATUS_INVALID_LEVEL;
821 ndr = ndr_push_init_ctx(mem_ctx);
822 if (!ndr) {
823 return NT_STATUS_NO_MEMORY;
826 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
827 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
830 if (c->flags & DCERPC_NDR64) {
831 ndr->flags |= LIBNDR_FLAG_NDR64;
834 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
835 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
836 hdr_size += 16;
839 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
840 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
841 return ndr_map_error2ntstatus(ndr_err);
844 /* pad to 16 byte multiple in the payload portion of the
845 packet. This matches what w2k3 does. Note that we can't use
846 ndr_push_align() as that is relative to the start of the
847 whole packet, whereas w2k8 wants it relative to the start
848 of the stub */
849 c->security_state.auth_info->auth_pad_length =
850 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
851 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
852 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
853 return ndr_map_error2ntstatus(ndr_err);
856 payload_length = pkt->u.request.stub_and_verifier.length +
857 c->security_state.auth_info->auth_pad_length;
859 /* we start without signature, it will appended later */
860 c->security_state.auth_info->credentials = data_blob(NULL,0);
862 /* add the auth verifier */
863 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
864 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
865 return ndr_map_error2ntstatus(ndr_err);
868 /* extract the whole packet as a blob */
869 *blob = ndr_push_blob(ndr);
872 * Setup the frag and auth length in the packet buffer.
873 * This is needed if the GENSEC mech does AEAD signing
874 * of the packet headers. The signature itself will be
875 * appended later.
877 dcerpc_set_frag_length(blob, blob->length + sig_size);
878 dcerpc_set_auth_length(blob, sig_size);
880 /* sign or seal the packet */
881 switch (c->security_state.auth_info->auth_level) {
882 case DCERPC_AUTH_LEVEL_PRIVACY:
883 status = gensec_seal_packet(c->security_state.generic_state,
884 mem_ctx,
885 blob->data + hdr_size,
886 payload_length,
887 blob->data,
888 blob->length,
889 &creds2);
890 if (!NT_STATUS_IS_OK(status)) {
891 return status;
893 break;
895 case DCERPC_AUTH_LEVEL_INTEGRITY:
896 status = gensec_sign_packet(c->security_state.generic_state,
897 mem_ctx,
898 blob->data + hdr_size,
899 payload_length,
900 blob->data,
901 blob->length,
902 &creds2);
903 if (!NT_STATUS_IS_OK(status)) {
904 return status;
906 break;
908 default:
909 status = NT_STATUS_INVALID_LEVEL;
910 break;
913 if (creds2.length != sig_size) {
914 /* this means the sig_size estimate for the signature
915 was incorrect. We have to correct the packet
916 sizes. That means we could go over the max fragment
917 length */
918 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
919 (unsigned) creds2.length,
920 (unsigned) sig_size,
921 (unsigned) c->security_state.auth_info->auth_pad_length,
922 (unsigned) pkt->u.request.stub_and_verifier.length));
923 dcerpc_set_frag_length(blob, blob->length + creds2.length);
924 dcerpc_set_auth_length(blob, creds2.length);
927 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
928 return NT_STATUS_NO_MEMORY;
931 return NT_STATUS_OK;
936 fill in the fixed values in a dcerpc header
938 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
940 pkt->rpc_vers = 5;
941 pkt->rpc_vers_minor = 0;
942 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
943 pkt->drep[0] = 0;
944 } else {
945 pkt->drep[0] = DCERPC_DREP_LE;
947 pkt->drep[1] = 0;
948 pkt->drep[2] = 0;
949 pkt->drep[3] = 0;
953 map a bind nak reason to a NTSTATUS
955 static NTSTATUS dcerpc_map_reason(uint16_t reason)
957 switch (reason) {
958 case DCERPC_BIND_REASON_ASYNTAX:
959 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
960 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
961 return NT_STATUS_INVALID_PARAMETER;
963 return NT_STATUS_UNSUCCESSFUL;
967 remove requests from the pending or queued queues
969 static int dcerpc_req_dequeue(struct rpc_request *req)
971 switch (req->state) {
972 case RPC_REQUEST_QUEUED:
973 DLIST_REMOVE(req->p->conn->request_queue, req);
974 break;
975 case RPC_REQUEST_PENDING:
976 DLIST_REMOVE(req->p->conn->pending, req);
977 break;
978 case RPC_REQUEST_DONE:
979 break;
981 return 0;
986 mark the dcerpc connection dead. All outstanding requests get an error
988 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
990 if (conn->dead) return;
992 conn->dead = true;
994 TALLOC_FREE(conn->io_trigger);
995 conn->io_trigger_pending = false;
997 conn->transport.recv_data = NULL;
999 if (conn->transport.shutdown_pipe) {
1000 conn->transport.shutdown_pipe(conn, status);
1003 /* all pending requests get the error */
1004 while (conn->pending) {
1005 struct rpc_request *req = conn->pending;
1006 dcerpc_req_dequeue(req);
1007 req->state = RPC_REQUEST_DONE;
1008 req->status = status;
1009 if (req->async.callback) {
1010 req->async.callback(req);
1014 /* all requests, which are not shipped */
1015 while (conn->request_queue) {
1016 struct rpc_request *req = conn->request_queue;
1017 dcerpc_req_dequeue(req);
1018 req->state = RPC_REQUEST_DONE;
1019 req->status = status;
1020 if (req->async.callback) {
1021 req->async.callback(req);
1025 talloc_set_destructor(conn, NULL);
1026 if (conn->free_skipped) {
1027 talloc_free(conn);
1032 forward declarations of the recv_data handlers for the types of
1033 packets we need to handle
1035 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1036 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1039 receive a dcerpc reply from the transport. Here we work out what
1040 type of reply it is (normal request, bind or alter context) and
1041 dispatch to the appropriate handler
1043 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1045 struct ncacn_packet pkt;
1047 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1048 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1051 /* the transport may be telling us of a severe error, such as
1052 a dropped socket */
1053 if (!NT_STATUS_IS_OK(status)) {
1054 data_blob_free(blob);
1055 dcerpc_connection_dead(conn, status);
1056 return;
1059 /* parse the basic packet to work out what type of response this is */
1060 status = ncacn_pull(conn, blob, blob->data, &pkt);
1061 if (!NT_STATUS_IS_OK(status)) {
1062 data_blob_free(blob);
1063 dcerpc_connection_dead(conn, status);
1064 return;
1067 dcerpc_request_recv_data(conn, blob, &pkt);
1071 handle timeouts of individual dcerpc requests
1073 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1074 struct timeval t, void *private_data)
1076 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1078 if (req->ignore_timeout) {
1079 dcerpc_req_dequeue(req);
1080 req->state = RPC_REQUEST_DONE;
1081 req->status = NT_STATUS_IO_TIMEOUT;
1082 if (req->async.callback) {
1083 req->async.callback(req);
1085 return;
1088 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1091 struct dcerpc_bind_state {
1092 struct tevent_context *ev;
1093 struct dcerpc_pipe *p;
1096 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1097 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1098 DATA_BLOB *raw_packet,
1099 struct ncacn_packet *pkt);
1101 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1102 struct tevent_context *ev,
1103 struct dcerpc_pipe *p,
1104 const struct ndr_syntax_id *syntax,
1105 const struct ndr_syntax_id *transfer_syntax)
1107 struct tevent_req *req;
1108 struct dcerpc_bind_state *state;
1109 struct ncacn_packet pkt;
1110 DATA_BLOB blob;
1111 NTSTATUS status;
1112 struct rpc_request *subreq;
1114 req = tevent_req_create(mem_ctx, &state,
1115 struct dcerpc_bind_state);
1116 if (req == NULL) {
1117 return NULL;
1120 state->ev = ev;
1121 state->p = p;
1123 p->syntax = *syntax;
1124 p->transfer_syntax = *transfer_syntax;
1126 init_ncacn_hdr(p->conn, &pkt);
1128 pkt.ptype = DCERPC_PKT_BIND;
1129 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1130 pkt.call_id = p->conn->call_id;
1131 pkt.auth_length = 0;
1133 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1134 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1137 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1138 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1141 pkt.u.bind.max_xmit_frag = 5840;
1142 pkt.u.bind.max_recv_frag = 5840;
1143 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1144 pkt.u.bind.num_contexts = 1;
1145 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1146 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1147 return tevent_req_post(req, ev);
1149 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1150 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1151 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1152 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1153 pkt.u.bind.auth_info = data_blob(NULL, 0);
1155 /* construct the NDR form of the packet */
1156 status = ncacn_push_auth(&blob, state, &pkt,
1157 p->conn->security_state.auth_info);
1158 if (tevent_req_nterror(req, status)) {
1159 return tevent_req_post(req, ev);
1162 p->conn->transport.recv_data = dcerpc_recv_data;
1165 * we allocate a dcerpc_request so we can be in the same
1166 * request queue as normal requests
1168 subreq = talloc_zero(state, struct rpc_request);
1169 if (tevent_req_nomem(subreq, req)) {
1170 return tevent_req_post(req, ev);
1173 subreq->state = RPC_REQUEST_PENDING;
1174 subreq->call_id = pkt.call_id;
1175 subreq->async.private_data = req;
1176 subreq->async.callback = dcerpc_bind_fail_handler;
1177 subreq->p = p;
1178 subreq->recv_handler = dcerpc_bind_recv_handler;
1179 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1180 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1182 status = p->conn->transport.send_request(p->conn, &blob, true);
1183 if (tevent_req_nterror(req, status)) {
1184 return tevent_req_post(req, ev);
1187 tevent_add_timer(ev, subreq,
1188 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1189 dcerpc_timeout_handler, subreq);
1191 return req;
1194 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1196 struct tevent_req *req =
1197 talloc_get_type_abort(subreq->async.private_data,
1198 struct tevent_req);
1199 struct dcerpc_bind_state *state =
1200 tevent_req_data(req,
1201 struct dcerpc_bind_state);
1202 NTSTATUS status = subreq->status;
1204 TALLOC_FREE(subreq);
1207 * We trigger the callback in the next event run
1208 * because the code in this file might trigger
1209 * multiple request callbacks from within a single
1210 * while loop.
1212 * In order to avoid segfaults from within
1213 * dcerpc_connection_dead() we call
1214 * tevent_req_defer_callback().
1216 tevent_req_defer_callback(req, state->ev);
1218 tevent_req_nterror(req, status);
1221 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1222 DATA_BLOB *raw_packet,
1223 struct ncacn_packet *pkt)
1225 struct tevent_req *req =
1226 talloc_get_type_abort(subreq->async.private_data,
1227 struct tevent_req);
1228 struct dcerpc_bind_state *state =
1229 tevent_req_data(req,
1230 struct dcerpc_bind_state);
1231 struct dcecli_connection *conn = state->p->conn;
1232 NTSTATUS status;
1235 * Note that pkt is allocated under raw_packet->data,
1236 * while raw_packet->data is a child of subreq.
1238 talloc_steal(state, raw_packet->data);
1239 TALLOC_FREE(subreq);
1242 * We trigger the callback in the next event run
1243 * because the code in this file might trigger
1244 * multiple request callbacks from within a single
1245 * while loop.
1247 * In order to avoid segfaults from within
1248 * dcerpc_connection_dead() we call
1249 * tevent_req_defer_callback().
1251 tevent_req_defer_callback(req, state->ev);
1253 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1254 status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason);
1256 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1257 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1259 tevent_req_nterror(req, status);
1260 return;
1263 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1264 (pkt->u.bind_ack.num_results == 0) ||
1265 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1266 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1267 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1268 return;
1271 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1272 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1274 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1275 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1276 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1279 if ((state->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1280 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1281 conn->flags |= DCERPC_HEADER_SIGNING;
1284 /* the bind_ack might contain a reply set of credentials */
1285 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1286 uint32_t auth_length;
1288 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1289 conn->security_state.auth_info, &auth_length, true);
1290 if (tevent_req_nterror(req, status)) {
1291 return;
1295 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1297 tevent_req_done(req);
1300 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1302 return tevent_req_simple_recv_ntstatus(req);
1306 perform a continued bind (and auth3)
1308 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1309 TALLOC_CTX *mem_ctx)
1311 struct ncacn_packet pkt;
1312 NTSTATUS status;
1313 DATA_BLOB blob;
1315 init_ncacn_hdr(p->conn, &pkt);
1317 pkt.ptype = DCERPC_PKT_AUTH3;
1318 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1319 pkt.call_id = next_call_id(p->conn);
1320 pkt.auth_length = 0;
1321 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1323 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1324 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1327 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1328 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1331 /* construct the NDR form of the packet */
1332 status = ncacn_push_auth(&blob, mem_ctx,
1333 &pkt,
1334 p->conn->security_state.auth_info);
1335 if (!NT_STATUS_IS_OK(status)) {
1336 return status;
1339 /* send it on its way */
1340 status = p->conn->transport.send_request(p->conn, &blob, false);
1341 if (!NT_STATUS_IS_OK(status)) {
1342 return status;
1345 return NT_STATUS_OK;
1350 process a fragment received from the transport layer during a
1351 request
1353 This function frees the data
1355 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1356 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1358 struct rpc_request *req;
1359 unsigned int length;
1360 NTSTATUS status = NT_STATUS_OK;
1363 if this is an authenticated connection then parse and check
1364 the auth info. We have to do this before finding the
1365 matching packet, as the request structure might have been
1366 removed due to a timeout, but if it has been we still need
1367 to run the auth routines so that we don't get the sign/seal
1368 info out of step with the server
1370 if (c->security_state.auth_info && c->security_state.generic_state &&
1371 pkt->ptype == DCERPC_PKT_RESPONSE) {
1372 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1375 /* find the matching request */
1376 for (req=c->pending;req;req=req->next) {
1377 if (pkt->call_id == req->call_id) break;
1380 #if 0
1381 /* useful for testing certain vendors RPC servers */
1382 if (req == NULL && c->pending && pkt->call_id == 0) {
1383 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1384 req = c->pending;
1386 #endif
1388 if (req == NULL) {
1389 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1390 data_blob_free(raw_packet);
1391 return;
1394 talloc_steal(req, raw_packet->data);
1396 if (req->recv_handler != NULL) {
1397 dcerpc_req_dequeue(req);
1398 req->state = RPC_REQUEST_DONE;
1401 * We have to look at shipping further requests before calling
1402 * the async function, that one might close the pipe
1404 dcerpc_schedule_io_trigger(c);
1406 req->recv_handler(req, raw_packet, pkt);
1407 return;
1410 if (pkt->ptype == DCERPC_PKT_FAULT) {
1411 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1412 req->fault_code = pkt->u.fault.status;
1413 req->status = NT_STATUS_NET_WRITE_FAULT;
1414 goto req_done;
1417 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1418 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1419 (int)pkt->ptype));
1420 req->fault_code = DCERPC_FAULT_OTHER;
1421 req->status = NT_STATUS_NET_WRITE_FAULT;
1422 goto req_done;
1425 /* now check the status from the auth routines, and if it failed then fail
1426 this request accordingly */
1427 if (!NT_STATUS_IS_OK(status)) {
1428 req->status = status;
1429 goto req_done;
1432 length = pkt->u.response.stub_and_verifier.length;
1434 if (length > 0) {
1435 req->payload.data = talloc_realloc(req,
1436 req->payload.data,
1437 uint8_t,
1438 req->payload.length + length);
1439 if (!req->payload.data) {
1440 req->status = NT_STATUS_NO_MEMORY;
1441 goto req_done;
1443 memcpy(req->payload.data+req->payload.length,
1444 pkt->u.response.stub_and_verifier.data, length);
1445 req->payload.length += length;
1448 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1449 c->transport.send_read(c);
1450 return;
1453 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1454 req->flags |= DCERPC_PULL_BIGENDIAN;
1455 } else {
1456 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1460 req_done:
1461 /* we've got the full payload */
1462 dcerpc_req_dequeue(req);
1463 req->state = RPC_REQUEST_DONE;
1466 * We have to look at shipping further requests before calling
1467 * the async function, that one might close the pipe
1469 dcerpc_schedule_io_trigger(c);
1471 if (req->async.callback) {
1472 req->async.callback(req);
1477 perform the send side of a async dcerpc request
1479 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1480 struct dcerpc_pipe *p,
1481 const struct GUID *object,
1482 uint16_t opnum,
1483 DATA_BLOB *stub_data)
1485 struct rpc_request *req;
1487 p->conn->transport.recv_data = dcerpc_recv_data;
1489 req = talloc_zero(mem_ctx, struct rpc_request);
1490 if (req == NULL) {
1491 return NULL;
1494 req->p = p;
1495 req->call_id = next_call_id(p->conn);
1496 req->state = RPC_REQUEST_QUEUED;
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;
1506 req->opnum = opnum;
1507 req->request_data.length = stub_data->length;
1508 req->request_data.data = stub_data->data;
1510 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1511 talloc_set_destructor(req, dcerpc_req_dequeue);
1513 dcerpc_schedule_io_trigger(p->conn);
1515 if (p->request_timeout) {
1516 tevent_add_timer(dcerpc_event_context(p), req,
1517 timeval_current_ofs(p->request_timeout, 0),
1518 dcerpc_timeout_handler, req);
1521 return req;
1525 Send a request using the transport
1528 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1530 struct rpc_request *req;
1531 struct dcerpc_pipe *p;
1532 DATA_BLOB *stub_data;
1533 struct ncacn_packet pkt;
1534 DATA_BLOB blob;
1535 uint32_t remaining, chunk_size;
1536 bool first_packet = true;
1537 size_t sig_size = 0;
1538 bool need_async = false;
1539 bool can_async = true;
1541 req = c->request_queue;
1542 if (req == NULL) {
1543 return;
1546 p = req->p;
1547 stub_data = &req->request_data;
1549 if (c->pending) {
1550 need_async = true;
1553 if (c->security_state.auth_info &&
1554 c->security_state.generic_state)
1556 struct gensec_security *gensec = c->security_state.generic_state;
1558 switch (c->security_state.auth_info->auth_level) {
1559 case DCERPC_AUTH_LEVEL_PRIVACY:
1560 case DCERPC_AUTH_LEVEL_INTEGRITY:
1561 can_async = gensec_have_feature(gensec,
1562 GENSEC_FEATURE_ASYNC_REPLIES);
1563 break;
1564 case DCERPC_AUTH_LEVEL_CONNECT:
1565 case DCERPC_AUTH_LEVEL_NONE:
1566 can_async = true;
1567 break;
1568 default:
1569 can_async = false;
1570 break;
1574 if (need_async && !can_async) {
1575 req->wait_for_sync = true;
1576 return;
1579 DLIST_REMOVE(c->request_queue, req);
1580 DLIST_ADD(c->pending, req);
1581 req->state = RPC_REQUEST_PENDING;
1583 init_ncacn_hdr(p->conn, &pkt);
1585 remaining = stub_data->length;
1587 /* we can write a full max_recv_frag size, minus the dcerpc
1588 request header size */
1589 chunk_size = p->conn->srv_max_recv_frag;
1590 chunk_size -= DCERPC_REQUEST_LENGTH;
1591 if (c->security_state.auth_info &&
1592 c->security_state.generic_state) {
1593 sig_size = gensec_sig_size(c->security_state.generic_state,
1594 p->conn->srv_max_recv_frag);
1595 if (sig_size) {
1596 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1597 chunk_size -= sig_size;
1600 chunk_size -= (chunk_size % 16);
1602 pkt.ptype = DCERPC_PKT_REQUEST;
1603 pkt.call_id = req->call_id;
1604 pkt.auth_length = 0;
1605 pkt.pfc_flags = 0;
1606 pkt.u.request.alloc_hint = remaining;
1607 pkt.u.request.context_id = p->context_id;
1608 pkt.u.request.opnum = req->opnum;
1610 if (req->object) {
1611 pkt.u.request.object.object = *req->object;
1612 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1613 chunk_size -= ndr_size_GUID(req->object,0);
1616 /* we send a series of pdus without waiting for a reply */
1617 while (remaining > 0 || first_packet) {
1618 uint32_t chunk = MIN(chunk_size, remaining);
1619 bool last_frag = false;
1620 bool do_trans = false;
1622 first_packet = false;
1623 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1625 if (remaining == stub_data->length) {
1626 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1628 if (chunk == remaining) {
1629 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1630 last_frag = true;
1633 pkt.u.request.stub_and_verifier.data = stub_data->data +
1634 (stub_data->length - remaining);
1635 pkt.u.request.stub_and_verifier.length = chunk;
1637 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1638 if (!NT_STATUS_IS_OK(req->status)) {
1639 req->state = RPC_REQUEST_DONE;
1640 DLIST_REMOVE(p->conn->pending, req);
1641 return;
1644 if (last_frag && !need_async) {
1645 do_trans = true;
1648 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1649 if (!NT_STATUS_IS_OK(req->status)) {
1650 req->state = RPC_REQUEST_DONE;
1651 DLIST_REMOVE(p->conn->pending, req);
1652 return;
1655 if (last_frag && !do_trans) {
1656 req->status = p->conn->transport.send_read(p->conn);
1657 if (!NT_STATUS_IS_OK(req->status)) {
1658 req->state = RPC_REQUEST_DONE;
1659 DLIST_REMOVE(p->conn->pending, req);
1660 return;
1664 remaining -= chunk;
1668 static void dcerpc_io_trigger(struct tevent_context *ctx,
1669 struct tevent_immediate *im,
1670 void *private_data)
1672 struct dcecli_connection *c =
1673 talloc_get_type_abort(private_data,
1674 struct dcecli_connection);
1676 c->io_trigger_pending = false;
1678 dcerpc_schedule_io_trigger(c);
1680 dcerpc_ship_next_request(c);
1683 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1685 if (c->dead) {
1686 return;
1689 if (c->request_queue == NULL) {
1690 return;
1693 if (c->request_queue->wait_for_sync && c->pending) {
1694 return;
1697 if (c->io_trigger_pending) {
1698 return;
1701 c->io_trigger_pending = true;
1703 tevent_schedule_immediate(c->io_trigger,
1704 c->event_ctx,
1705 dcerpc_io_trigger,
1710 return the event context for a dcerpc pipe
1711 used by callers who wish to operate asynchronously
1713 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1715 return p->conn->event_ctx;
1721 perform the receive side of a async dcerpc request
1723 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1724 TALLOC_CTX *mem_ctx,
1725 DATA_BLOB *stub_data)
1727 NTSTATUS status;
1729 while (req->state != RPC_REQUEST_DONE) {
1730 struct tevent_context *ctx = dcerpc_event_context(req->p);
1731 if (tevent_loop_once(ctx) != 0) {
1732 return NT_STATUS_CONNECTION_DISCONNECTED;
1735 *stub_data = req->payload;
1736 status = req->status;
1737 if (stub_data->data) {
1738 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1740 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1741 req->p->last_fault_code = req->fault_code;
1743 talloc_unlink(talloc_parent(req), req);
1744 return status;
1748 this is a paranoid NDR validator. For every packet we push onto the wire
1749 we pull it back again, then push it again. Then we compare the raw NDR data
1750 for that to the NDR we initially generated. If they don't match then we know
1751 we must have a bug in either the pull or push side of our code
1753 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1754 TALLOC_CTX *mem_ctx,
1755 DATA_BLOB blob,
1756 size_t struct_size,
1757 ndr_push_flags_fn_t ndr_push,
1758 ndr_pull_flags_fn_t ndr_pull)
1760 void *st;
1761 struct ndr_pull *pull;
1762 struct ndr_push *push;
1763 DATA_BLOB blob2;
1764 enum ndr_err_code ndr_err;
1766 st = talloc_size(mem_ctx, struct_size);
1767 if (!st) {
1768 return NT_STATUS_NO_MEMORY;
1771 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1772 if (!pull) {
1773 return NT_STATUS_NO_MEMORY;
1775 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1777 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1778 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1781 if (c->flags & DCERPC_NDR64) {
1782 pull->flags |= LIBNDR_FLAG_NDR64;
1785 ndr_err = ndr_pull(pull, NDR_IN, st);
1786 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1787 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1788 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1789 "failed input validation pull - %s",
1790 nt_errstr(status));
1791 return ndr_map_error2ntstatus(ndr_err);
1794 push = ndr_push_init_ctx(mem_ctx);
1795 if (!push) {
1796 return NT_STATUS_NO_MEMORY;
1799 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1800 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1803 if (c->flags & DCERPC_NDR64) {
1804 push->flags |= LIBNDR_FLAG_NDR64;
1807 ndr_err = ndr_push(push, NDR_IN, st);
1808 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1809 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1810 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1811 "failed input validation push - %s",
1812 nt_errstr(status));
1813 return ndr_map_error2ntstatus(ndr_err);
1816 blob2 = ndr_push_blob(push);
1818 if (data_blob_cmp(&blob, &blob2) != 0) {
1819 DEBUG(3,("original:\n"));
1820 dump_data(3, blob.data, blob.length);
1821 DEBUG(3,("secondary:\n"));
1822 dump_data(3, blob2.data, blob2.length);
1823 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1824 "failed input validation blobs doesn't match");
1825 return ndr_map_error2ntstatus(ndr_err);
1828 return NT_STATUS_OK;
1832 this is a paranoid NDR input validator. For every packet we pull
1833 from the wire we push it back again then pull and push it
1834 again. Then we compare the raw NDR data for that to the NDR we
1835 initially generated. If they don't match then we know we must have a
1836 bug in either the pull or push side of our code
1838 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1839 struct ndr_pull *pull_in,
1840 void *struct_ptr,
1841 size_t struct_size,
1842 ndr_push_flags_fn_t ndr_push,
1843 ndr_pull_flags_fn_t ndr_pull,
1844 ndr_print_function_t ndr_print)
1846 void *st;
1847 struct ndr_pull *pull;
1848 struct ndr_push *push;
1849 DATA_BLOB blob, blob2;
1850 TALLOC_CTX *mem_ctx = pull_in;
1851 char *s1, *s2;
1852 enum ndr_err_code ndr_err;
1854 st = talloc_size(mem_ctx, struct_size);
1855 if (!st) {
1856 return NT_STATUS_NO_MEMORY;
1858 memcpy(st, struct_ptr, struct_size);
1860 push = ndr_push_init_ctx(mem_ctx);
1861 if (!push) {
1862 return NT_STATUS_NO_MEMORY;
1865 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1866 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1867 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1868 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1869 "failed output validation push - %s",
1870 nt_errstr(status));
1871 return ndr_map_error2ntstatus(ndr_err);
1874 blob = ndr_push_blob(push);
1876 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1877 if (!pull) {
1878 return NT_STATUS_NO_MEMORY;
1881 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1882 ndr_err = ndr_pull(pull, NDR_OUT, st);
1883 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1884 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1885 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1886 "failed output validation pull - %s",
1887 nt_errstr(status));
1888 return ndr_map_error2ntstatus(ndr_err);
1891 push = ndr_push_init_ctx(mem_ctx);
1892 if (!push) {
1893 return NT_STATUS_NO_MEMORY;
1896 ndr_err = ndr_push(push, NDR_OUT, st);
1897 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1898 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1899 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1900 "failed output validation push2 - %s",
1901 nt_errstr(status));
1902 return ndr_map_error2ntstatus(ndr_err);
1905 blob2 = ndr_push_blob(push);
1907 if (data_blob_cmp(&blob, &blob2) != 0) {
1908 DEBUG(3,("original:\n"));
1909 dump_data(3, blob.data, blob.length);
1910 DEBUG(3,("secondary:\n"));
1911 dump_data(3, blob2.data, blob2.length);
1912 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1913 "failed output validation blobs doesn't match");
1914 return ndr_map_error2ntstatus(ndr_err);
1917 /* this checks the printed forms of the two structures, which effectively
1918 tests all of the value() attributes */
1919 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1920 NDR_OUT, struct_ptr);
1921 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1922 NDR_OUT, st);
1923 if (strcmp(s1, s2) != 0) {
1924 #if 1
1925 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1926 #else
1927 /* this is sometimes useful */
1928 printf("VALIDATE ERROR\n");
1929 file_save("wire.dat", s1, strlen(s1));
1930 file_save("gen.dat", s2, strlen(s2));
1931 system("diff -u wire.dat gen.dat");
1932 #endif
1933 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1934 "failed output validation strings doesn't match");
1935 return ndr_map_error2ntstatus(ndr_err);
1938 return NT_STATUS_OK;
1942 a useful function for retrieving the server name we connected to
1944 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1946 if (!p->conn->transport.target_hostname) {
1947 if (!p->conn->transport.peer_name) {
1948 return "";
1950 return p->conn->transport.peer_name(p->conn);
1952 return p->conn->transport.target_hostname(p->conn);
1957 get the dcerpc auth_level for a open connection
1959 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1961 uint8_t auth_level;
1963 if (c->flags & DCERPC_SEAL) {
1964 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1965 } else if (c->flags & DCERPC_SIGN) {
1966 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1967 } else if (c->flags & DCERPC_CONNECT) {
1968 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1969 } else {
1970 auth_level = DCERPC_AUTH_LEVEL_NONE;
1972 return auth_level;
1975 struct dcerpc_alter_context_state {
1976 struct tevent_context *ev;
1977 struct dcerpc_pipe *p;
1980 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
1981 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
1982 DATA_BLOB *raw_packet,
1983 struct ncacn_packet *pkt);
1985 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
1986 struct tevent_context *ev,
1987 struct dcerpc_pipe *p,
1988 const struct ndr_syntax_id *syntax,
1989 const struct ndr_syntax_id *transfer_syntax)
1991 struct tevent_req *req;
1992 struct dcerpc_alter_context_state *state;
1993 struct ncacn_packet pkt;
1994 DATA_BLOB blob;
1995 NTSTATUS status;
1996 struct rpc_request *subreq;
1998 req = tevent_req_create(mem_ctx, &state,
1999 struct dcerpc_alter_context_state);
2000 if (req == NULL) {
2001 return NULL;
2004 state->ev = ev;
2005 state->p = p;
2007 p->syntax = *syntax;
2008 p->transfer_syntax = *transfer_syntax;
2010 init_ncacn_hdr(p->conn, &pkt);
2012 pkt.ptype = DCERPC_PKT_ALTER;
2013 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2014 pkt.call_id = p->conn->call_id;
2015 pkt.auth_length = 0;
2017 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
2018 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2021 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
2022 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
2025 pkt.u.alter.max_xmit_frag = 5840;
2026 pkt.u.alter.max_recv_frag = 5840;
2027 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
2028 pkt.u.alter.num_contexts = 1;
2029 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2030 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2031 return tevent_req_post(req, ev);
2033 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2034 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2035 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2036 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2037 pkt.u.alter.auth_info = data_blob(NULL, 0);
2039 /* construct the NDR form of the packet */
2040 status = ncacn_push_auth(&blob, state, &pkt,
2041 p->conn->security_state.auth_info);
2042 if (tevent_req_nterror(req, status)) {
2043 return tevent_req_post(req, ev);
2046 p->conn->transport.recv_data = dcerpc_recv_data;
2049 * we allocate a dcerpc_request so we can be in the same
2050 * request queue as normal requests
2052 subreq = talloc_zero(state, struct rpc_request);
2053 if (tevent_req_nomem(subreq, req)) {
2054 return tevent_req_post(req, ev);
2057 subreq->state = RPC_REQUEST_PENDING;
2058 subreq->call_id = pkt.call_id;
2059 subreq->async.private_data = req;
2060 subreq->async.callback = dcerpc_alter_context_fail_handler;
2061 subreq->p = p;
2062 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2063 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2064 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2066 status = p->conn->transport.send_request(p->conn, &blob, true);
2067 if (tevent_req_nterror(req, status)) {
2068 return tevent_req_post(req, ev);
2071 tevent_add_timer(ev, subreq,
2072 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2073 dcerpc_timeout_handler, subreq);
2075 return req;
2078 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
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 NTSTATUS status = subreq->status;
2088 TALLOC_FREE(subreq);
2091 * We trigger the callback in the next event run
2092 * because the code in this file might trigger
2093 * multiple request callbacks from within a single
2094 * while loop.
2096 * In order to avoid segfaults from within
2097 * dcerpc_connection_dead() we call
2098 * tevent_req_defer_callback().
2100 tevent_req_defer_callback(req, state->ev);
2102 tevent_req_nterror(req, status);
2105 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2106 DATA_BLOB *raw_packet,
2107 struct ncacn_packet *pkt)
2109 struct tevent_req *req =
2110 talloc_get_type_abort(subreq->async.private_data,
2111 struct tevent_req);
2112 struct dcerpc_alter_context_state *state =
2113 tevent_req_data(req,
2114 struct dcerpc_alter_context_state);
2115 struct dcecli_connection *conn = state->p->conn;
2116 NTSTATUS status;
2119 * Note that pkt is allocated under raw_packet->data,
2120 * while raw_packet->data is a child of subreq.
2122 talloc_steal(state, raw_packet->data);
2123 TALLOC_FREE(subreq);
2126 * We trigger the callback in the next event run
2127 * because the code in this file might trigger
2128 * multiple request callbacks from within a single
2129 * while loop.
2131 * In order to avoid segfaults from within
2132 * dcerpc_connection_dead() we call
2133 * tevent_req_defer_callback().
2135 tevent_req_defer_callback(req, state->ev);
2137 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2138 pkt->u.alter_resp.num_results == 1 &&
2139 pkt->u.alter_resp.ctx_list[0].result != 0) {
2140 status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason);
2141 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2142 pkt->u.alter_resp.ctx_list[0].reason,
2143 nt_errstr(status)));
2144 tevent_req_nterror(req, status);
2145 return;
2148 if (pkt->ptype == DCERPC_PKT_FAULT) {
2149 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2150 dcerpc_errstr(state, pkt->u.fault.status)));
2151 state->p->last_fault_code = pkt->u.fault.status;
2152 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2153 return;
2156 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2157 pkt->u.alter_resp.num_results == 0 ||
2158 pkt->u.alter_resp.ctx_list[0].result != 0) {
2159 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2160 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2161 return;
2164 /* the alter_resp might contain a reply set of credentials */
2165 if (conn->security_state.auth_info &&
2166 pkt->u.alter_resp.auth_info.length) {
2167 uint32_t auth_length;
2169 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2170 conn->security_state.auth_info, &auth_length, true);
2171 if (tevent_req_nterror(req, status)) {
2172 return;
2176 tevent_req_done(req);
2179 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2181 return tevent_req_simple_recv_ntstatus(req);
2185 send a dcerpc alter_context request
2187 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2188 TALLOC_CTX *mem_ctx,
2189 const struct ndr_syntax_id *syntax,
2190 const struct ndr_syntax_id *transfer_syntax)
2192 struct tevent_req *subreq;
2193 struct tevent_context *ev = p->conn->event_ctx;
2194 bool ok;
2196 /* TODO: create a new event context here */
2198 subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx,
2199 p, syntax, transfer_syntax);
2200 if (subreq == NULL) {
2201 return NT_STATUS_NO_MEMORY;
2204 ok = tevent_req_poll(subreq, ev);
2205 if (!ok) {
2206 NTSTATUS status;
2207 status = map_nt_error_from_unix_common(errno);
2208 return status;
2211 return dcerpc_alter_context_recv(subreq);