s4:librpc/rpc: let dcerpc_ship_next_request() use DCERPC_AUTH_PAD_ALIGNMENT define
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blobcd33dc040879c7a03c265e87082531643345f34f
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 if (pkt->frag_length != blob->length) {
697 return NT_STATUS_RPC_PROTOCOL_ERROR;
700 return NT_STATUS_OK;
704 parse the authentication information on a dcerpc response packet
706 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
707 DATA_BLOB *raw_packet,
708 struct ncacn_packet *pkt)
710 NTSTATUS status;
711 struct dcerpc_auth auth;
712 uint32_t auth_length;
714 if (!c->security_state.auth_info ||
715 !c->security_state.generic_state) {
716 return NT_STATUS_OK;
719 switch (c->security_state.auth_info->auth_level) {
720 case DCERPC_AUTH_LEVEL_PRIVACY:
721 case DCERPC_AUTH_LEVEL_INTEGRITY:
722 break;
724 case DCERPC_AUTH_LEVEL_CONNECT:
725 if (pkt->auth_length != 0) {
726 break;
728 return NT_STATUS_OK;
729 case DCERPC_AUTH_LEVEL_NONE:
730 if (pkt->auth_length != 0) {
731 return NT_STATUS_INVALID_NETWORK_RESPONSE;
733 return NT_STATUS_OK;
735 default:
736 return NT_STATUS_INVALID_LEVEL;
739 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
740 &pkt->u.response.stub_and_verifier,
741 &auth, &auth_length, false);
742 NT_STATUS_NOT_OK_RETURN(status);
744 pkt->u.response.stub_and_verifier.length -= auth_length;
746 /* check signature or unseal the packet */
747 switch (c->security_state.auth_info->auth_level) {
748 case DCERPC_AUTH_LEVEL_PRIVACY:
749 status = gensec_unseal_packet(c->security_state.generic_state,
750 raw_packet->data + DCERPC_REQUEST_LENGTH,
751 pkt->u.response.stub_and_verifier.length,
752 raw_packet->data,
753 raw_packet->length - auth.credentials.length,
754 &auth.credentials);
755 memcpy(pkt->u.response.stub_and_verifier.data,
756 raw_packet->data + DCERPC_REQUEST_LENGTH,
757 pkt->u.response.stub_and_verifier.length);
758 break;
760 case DCERPC_AUTH_LEVEL_INTEGRITY:
761 status = gensec_check_packet(c->security_state.generic_state,
762 pkt->u.response.stub_and_verifier.data,
763 pkt->u.response.stub_and_verifier.length,
764 raw_packet->data,
765 raw_packet->length - auth.credentials.length,
766 &auth.credentials);
767 break;
769 case DCERPC_AUTH_LEVEL_CONNECT:
770 /* for now we ignore possible signatures here */
771 status = NT_STATUS_OK;
772 break;
774 default:
775 status = NT_STATUS_INVALID_LEVEL;
776 break;
779 /* remove the indicated amount of padding */
780 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
781 return NT_STATUS_INFO_LENGTH_MISMATCH;
783 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
785 return status;
790 push a dcerpc request packet into a blob, possibly signing it.
792 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
793 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
794 size_t sig_size,
795 struct ncacn_packet *pkt)
797 NTSTATUS status;
798 struct ndr_push *ndr;
799 DATA_BLOB creds2;
800 size_t payload_length;
801 enum ndr_err_code ndr_err;
802 size_t hdr_size = DCERPC_REQUEST_LENGTH;
804 /* non-signed packets are simpler */
805 if (sig_size == 0) {
806 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
809 switch (c->security_state.auth_info->auth_level) {
810 case DCERPC_AUTH_LEVEL_PRIVACY:
811 case DCERPC_AUTH_LEVEL_INTEGRITY:
812 break;
814 case DCERPC_AUTH_LEVEL_CONNECT:
815 /* TODO: let the gensec mech decide if it wants to generate a signature */
816 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
818 case DCERPC_AUTH_LEVEL_NONE:
819 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
821 default:
822 return NT_STATUS_INVALID_LEVEL;
825 ndr = ndr_push_init_ctx(mem_ctx);
826 if (!ndr) {
827 return NT_STATUS_NO_MEMORY;
830 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
831 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
834 if (c->flags & DCERPC_NDR64) {
835 ndr->flags |= LIBNDR_FLAG_NDR64;
838 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
839 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
840 hdr_size += 16;
843 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
844 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
845 return ndr_map_error2ntstatus(ndr_err);
848 /* pad to 16 byte multiple in the payload portion of the
849 packet. This matches what w2k3 does. Note that we can't use
850 ndr_push_align() as that is relative to the start of the
851 whole packet, whereas w2k8 wants it relative to the start
852 of the stub */
853 c->security_state.auth_info->auth_pad_length =
854 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
855 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
856 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
857 return ndr_map_error2ntstatus(ndr_err);
860 payload_length = pkt->u.request.stub_and_verifier.length +
861 c->security_state.auth_info->auth_pad_length;
863 /* we start without signature, it will appended later */
864 c->security_state.auth_info->credentials = data_blob(NULL,0);
866 /* add the auth verifier */
867 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
868 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
869 return ndr_map_error2ntstatus(ndr_err);
872 /* extract the whole packet as a blob */
873 *blob = ndr_push_blob(ndr);
876 * Setup the frag and auth length in the packet buffer.
877 * This is needed if the GENSEC mech does AEAD signing
878 * of the packet headers. The signature itself will be
879 * appended later.
881 dcerpc_set_frag_length(blob, blob->length + sig_size);
882 dcerpc_set_auth_length(blob, sig_size);
884 /* sign or seal the packet */
885 switch (c->security_state.auth_info->auth_level) {
886 case DCERPC_AUTH_LEVEL_PRIVACY:
887 status = gensec_seal_packet(c->security_state.generic_state,
888 mem_ctx,
889 blob->data + hdr_size,
890 payload_length,
891 blob->data,
892 blob->length,
893 &creds2);
894 if (!NT_STATUS_IS_OK(status)) {
895 return status;
897 break;
899 case DCERPC_AUTH_LEVEL_INTEGRITY:
900 status = gensec_sign_packet(c->security_state.generic_state,
901 mem_ctx,
902 blob->data + hdr_size,
903 payload_length,
904 blob->data,
905 blob->length,
906 &creds2);
907 if (!NT_STATUS_IS_OK(status)) {
908 return status;
910 break;
912 default:
913 status = NT_STATUS_INVALID_LEVEL;
914 break;
917 if (creds2.length != sig_size) {
918 /* this means the sig_size estimate for the signature
919 was incorrect. We have to correct the packet
920 sizes. That means we could go over the max fragment
921 length */
922 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
923 (unsigned) creds2.length,
924 (unsigned) sig_size,
925 (unsigned) c->security_state.auth_info->auth_pad_length,
926 (unsigned) pkt->u.request.stub_and_verifier.length));
927 dcerpc_set_frag_length(blob, blob->length + creds2.length);
928 dcerpc_set_auth_length(blob, creds2.length);
931 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
932 return NT_STATUS_NO_MEMORY;
935 return NT_STATUS_OK;
940 fill in the fixed values in a dcerpc header
942 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
944 pkt->rpc_vers = 5;
945 pkt->rpc_vers_minor = 0;
946 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
947 pkt->drep[0] = 0;
948 } else {
949 pkt->drep[0] = DCERPC_DREP_LE;
951 pkt->drep[1] = 0;
952 pkt->drep[2] = 0;
953 pkt->drep[3] = 0;
957 map a bind nak reason to a NTSTATUS
959 static NTSTATUS dcerpc_map_reason(uint16_t reason)
961 switch (reason) {
962 case DCERPC_BIND_REASON_ASYNTAX:
963 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
964 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
965 return NT_STATUS_INVALID_PARAMETER;
967 return NT_STATUS_UNSUCCESSFUL;
971 remove requests from the pending or queued queues
973 static int dcerpc_req_dequeue(struct rpc_request *req)
975 switch (req->state) {
976 case RPC_REQUEST_QUEUED:
977 DLIST_REMOVE(req->p->conn->request_queue, req);
978 break;
979 case RPC_REQUEST_PENDING:
980 DLIST_REMOVE(req->p->conn->pending, req);
981 break;
982 case RPC_REQUEST_DONE:
983 break;
985 return 0;
990 mark the dcerpc connection dead. All outstanding requests get an error
992 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
994 if (conn->dead) return;
996 conn->dead = true;
998 TALLOC_FREE(conn->io_trigger);
999 conn->io_trigger_pending = false;
1001 conn->transport.recv_data = NULL;
1003 if (conn->transport.shutdown_pipe) {
1004 conn->transport.shutdown_pipe(conn, status);
1007 /* all pending requests get the error */
1008 while (conn->pending) {
1009 struct rpc_request *req = conn->pending;
1010 dcerpc_req_dequeue(req);
1011 req->state = RPC_REQUEST_DONE;
1012 req->status = status;
1013 if (req->async.callback) {
1014 req->async.callback(req);
1018 /* all requests, which are not shipped */
1019 while (conn->request_queue) {
1020 struct rpc_request *req = conn->request_queue;
1021 dcerpc_req_dequeue(req);
1022 req->state = RPC_REQUEST_DONE;
1023 req->status = status;
1024 if (req->async.callback) {
1025 req->async.callback(req);
1029 talloc_set_destructor(conn, NULL);
1030 if (conn->free_skipped) {
1031 talloc_free(conn);
1036 forward declarations of the recv_data handlers for the types of
1037 packets we need to handle
1039 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1040 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1043 receive a dcerpc reply from the transport. Here we work out what
1044 type of reply it is (normal request, bind or alter context) and
1045 dispatch to the appropriate handler
1047 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1049 struct ncacn_packet pkt;
1051 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1052 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1055 /* the transport may be telling us of a severe error, such as
1056 a dropped socket */
1057 if (!NT_STATUS_IS_OK(status)) {
1058 data_blob_free(blob);
1059 dcerpc_connection_dead(conn, status);
1060 return;
1063 /* parse the basic packet to work out what type of response this is */
1064 status = ncacn_pull(conn, blob, blob->data, &pkt);
1065 if (!NT_STATUS_IS_OK(status)) {
1066 data_blob_free(blob);
1067 dcerpc_connection_dead(conn, status);
1068 return;
1071 dcerpc_request_recv_data(conn, blob, &pkt);
1075 handle timeouts of individual dcerpc requests
1077 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1078 struct timeval t, void *private_data)
1080 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1082 if (req->ignore_timeout) {
1083 dcerpc_req_dequeue(req);
1084 req->state = RPC_REQUEST_DONE;
1085 req->status = NT_STATUS_IO_TIMEOUT;
1086 if (req->async.callback) {
1087 req->async.callback(req);
1089 return;
1092 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1095 struct dcerpc_bind_state {
1096 struct tevent_context *ev;
1097 struct dcerpc_pipe *p;
1100 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1101 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1102 DATA_BLOB *raw_packet,
1103 struct ncacn_packet *pkt);
1105 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1106 struct tevent_context *ev,
1107 struct dcerpc_pipe *p,
1108 const struct ndr_syntax_id *syntax,
1109 const struct ndr_syntax_id *transfer_syntax)
1111 struct tevent_req *req;
1112 struct dcerpc_bind_state *state;
1113 struct ncacn_packet pkt;
1114 DATA_BLOB blob;
1115 NTSTATUS status;
1116 struct rpc_request *subreq;
1118 req = tevent_req_create(mem_ctx, &state,
1119 struct dcerpc_bind_state);
1120 if (req == NULL) {
1121 return NULL;
1124 state->ev = ev;
1125 state->p = p;
1127 p->syntax = *syntax;
1128 p->transfer_syntax = *transfer_syntax;
1130 init_ncacn_hdr(p->conn, &pkt);
1132 pkt.ptype = DCERPC_PKT_BIND;
1133 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1134 pkt.call_id = p->conn->call_id;
1135 pkt.auth_length = 0;
1137 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1138 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1141 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1142 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1145 pkt.u.bind.max_xmit_frag = 5840;
1146 pkt.u.bind.max_recv_frag = 5840;
1147 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1148 pkt.u.bind.num_contexts = 1;
1149 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1150 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1151 return tevent_req_post(req, ev);
1153 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1154 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1155 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1156 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1157 pkt.u.bind.auth_info = data_blob(NULL, 0);
1159 /* construct the NDR form of the packet */
1160 status = ncacn_push_auth(&blob, state, &pkt,
1161 p->conn->security_state.auth_info);
1162 if (tevent_req_nterror(req, status)) {
1163 return tevent_req_post(req, ev);
1166 p->conn->transport.recv_data = dcerpc_recv_data;
1169 * we allocate a dcerpc_request so we can be in the same
1170 * request queue as normal requests
1172 subreq = talloc_zero(state, struct rpc_request);
1173 if (tevent_req_nomem(subreq, req)) {
1174 return tevent_req_post(req, ev);
1177 subreq->state = RPC_REQUEST_PENDING;
1178 subreq->call_id = pkt.call_id;
1179 subreq->async.private_data = req;
1180 subreq->async.callback = dcerpc_bind_fail_handler;
1181 subreq->p = p;
1182 subreq->recv_handler = dcerpc_bind_recv_handler;
1183 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1184 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1186 status = p->conn->transport.send_request(p->conn, &blob, true);
1187 if (tevent_req_nterror(req, status)) {
1188 return tevent_req_post(req, ev);
1191 tevent_add_timer(ev, subreq,
1192 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1193 dcerpc_timeout_handler, subreq);
1195 return req;
1198 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1200 struct tevent_req *req =
1201 talloc_get_type_abort(subreq->async.private_data,
1202 struct tevent_req);
1203 struct dcerpc_bind_state *state =
1204 tevent_req_data(req,
1205 struct dcerpc_bind_state);
1206 NTSTATUS status = subreq->status;
1208 TALLOC_FREE(subreq);
1211 * We trigger the callback in the next event run
1212 * because the code in this file might trigger
1213 * multiple request callbacks from within a single
1214 * while loop.
1216 * In order to avoid segfaults from within
1217 * dcerpc_connection_dead() we call
1218 * tevent_req_defer_callback().
1220 tevent_req_defer_callback(req, state->ev);
1222 tevent_req_nterror(req, status);
1225 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1226 DATA_BLOB *raw_packet,
1227 struct ncacn_packet *pkt)
1229 struct tevent_req *req =
1230 talloc_get_type_abort(subreq->async.private_data,
1231 struct tevent_req);
1232 struct dcerpc_bind_state *state =
1233 tevent_req_data(req,
1234 struct dcerpc_bind_state);
1235 struct dcecli_connection *conn = state->p->conn;
1236 NTSTATUS status;
1239 * Note that pkt is allocated under raw_packet->data,
1240 * while raw_packet->data is a child of subreq.
1242 talloc_steal(state, raw_packet->data);
1243 TALLOC_FREE(subreq);
1246 * We trigger the callback in the next event run
1247 * because the code in this file might trigger
1248 * multiple request callbacks from within a single
1249 * while loop.
1251 * In order to avoid segfaults from within
1252 * dcerpc_connection_dead() we call
1253 * tevent_req_defer_callback().
1255 tevent_req_defer_callback(req, state->ev);
1257 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1258 status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason);
1260 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1261 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1263 tevent_req_nterror(req, status);
1264 return;
1267 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1268 (pkt->u.bind_ack.num_results == 0) ||
1269 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1270 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1271 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1272 return;
1275 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1276 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1278 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1279 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1280 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1283 if ((state->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1284 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1285 conn->flags |= DCERPC_HEADER_SIGNING;
1288 /* the bind_ack might contain a reply set of credentials */
1289 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1290 uint32_t auth_length;
1292 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1293 conn->security_state.auth_info, &auth_length, true);
1294 if (tevent_req_nterror(req, status)) {
1295 return;
1299 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1301 tevent_req_done(req);
1304 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1306 return tevent_req_simple_recv_ntstatus(req);
1310 perform a continued bind (and auth3)
1312 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1313 TALLOC_CTX *mem_ctx)
1315 struct ncacn_packet pkt;
1316 NTSTATUS status;
1317 DATA_BLOB blob;
1319 init_ncacn_hdr(p->conn, &pkt);
1321 pkt.ptype = DCERPC_PKT_AUTH3;
1322 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1323 pkt.call_id = next_call_id(p->conn);
1324 pkt.auth_length = 0;
1325 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1327 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1328 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1331 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1332 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1335 /* construct the NDR form of the packet */
1336 status = ncacn_push_auth(&blob, mem_ctx,
1337 &pkt,
1338 p->conn->security_state.auth_info);
1339 if (!NT_STATUS_IS_OK(status)) {
1340 return status;
1343 /* send it on its way */
1344 status = p->conn->transport.send_request(p->conn, &blob, false);
1345 if (!NT_STATUS_IS_OK(status)) {
1346 return status;
1349 return NT_STATUS_OK;
1354 process a fragment received from the transport layer during a
1355 request
1357 This function frees the data
1359 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1360 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1362 struct rpc_request *req;
1363 unsigned int length;
1364 NTSTATUS status = NT_STATUS_OK;
1367 if this is an authenticated connection then parse and check
1368 the auth info. We have to do this before finding the
1369 matching packet, as the request structure might have been
1370 removed due to a timeout, but if it has been we still need
1371 to run the auth routines so that we don't get the sign/seal
1372 info out of step with the server
1374 if (c->security_state.auth_info && c->security_state.generic_state &&
1375 pkt->ptype == DCERPC_PKT_RESPONSE) {
1376 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1379 /* find the matching request */
1380 for (req=c->pending;req;req=req->next) {
1381 if (pkt->call_id == req->call_id) break;
1384 #if 0
1385 /* useful for testing certain vendors RPC servers */
1386 if (req == NULL && c->pending && pkt->call_id == 0) {
1387 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1388 req = c->pending;
1390 #endif
1392 if (req == NULL) {
1393 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1394 data_blob_free(raw_packet);
1395 return;
1398 talloc_steal(req, raw_packet->data);
1400 if (req->recv_handler != NULL) {
1401 dcerpc_req_dequeue(req);
1402 req->state = RPC_REQUEST_DONE;
1405 * We have to look at shipping further requests before calling
1406 * the async function, that one might close the pipe
1408 dcerpc_schedule_io_trigger(c);
1410 req->recv_handler(req, raw_packet, pkt);
1411 return;
1414 if (pkt->ptype == DCERPC_PKT_FAULT) {
1415 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1416 req->fault_code = pkt->u.fault.status;
1417 req->status = NT_STATUS_NET_WRITE_FAULT;
1418 goto req_done;
1421 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1422 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1423 (int)pkt->ptype));
1424 req->fault_code = DCERPC_FAULT_OTHER;
1425 req->status = NT_STATUS_NET_WRITE_FAULT;
1426 goto req_done;
1429 /* now check the status from the auth routines, and if it failed then fail
1430 this request accordingly */
1431 if (!NT_STATUS_IS_OK(status)) {
1432 req->status = status;
1433 goto req_done;
1436 length = pkt->u.response.stub_and_verifier.length;
1438 if (length > 0) {
1439 req->payload.data = talloc_realloc(req,
1440 req->payload.data,
1441 uint8_t,
1442 req->payload.length + length);
1443 if (!req->payload.data) {
1444 req->status = NT_STATUS_NO_MEMORY;
1445 goto req_done;
1447 memcpy(req->payload.data+req->payload.length,
1448 pkt->u.response.stub_and_verifier.data, length);
1449 req->payload.length += length;
1452 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1453 c->transport.send_read(c);
1454 return;
1457 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1458 req->flags |= DCERPC_PULL_BIGENDIAN;
1459 } else {
1460 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1464 req_done:
1465 /* we've got the full payload */
1466 dcerpc_req_dequeue(req);
1467 req->state = RPC_REQUEST_DONE;
1470 * We have to look at shipping further requests before calling
1471 * the async function, that one might close the pipe
1473 dcerpc_schedule_io_trigger(c);
1475 if (req->async.callback) {
1476 req->async.callback(req);
1481 perform the send side of a async dcerpc request
1483 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1484 struct dcerpc_pipe *p,
1485 const struct GUID *object,
1486 uint16_t opnum,
1487 DATA_BLOB *stub_data)
1489 struct rpc_request *req;
1491 p->conn->transport.recv_data = dcerpc_recv_data;
1493 req = talloc_zero(mem_ctx, struct rpc_request);
1494 if (req == NULL) {
1495 return NULL;
1498 req->p = p;
1499 req->call_id = next_call_id(p->conn);
1500 req->state = RPC_REQUEST_QUEUED;
1502 if (object != NULL) {
1503 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1504 if (req->object == NULL) {
1505 talloc_free(req);
1506 return NULL;
1510 req->opnum = opnum;
1511 req->request_data.length = stub_data->length;
1512 req->request_data.data = stub_data->data;
1514 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1515 talloc_set_destructor(req, dcerpc_req_dequeue);
1517 dcerpc_schedule_io_trigger(p->conn);
1519 if (p->request_timeout) {
1520 tevent_add_timer(dcerpc_event_context(p), req,
1521 timeval_current_ofs(p->request_timeout, 0),
1522 dcerpc_timeout_handler, req);
1525 return req;
1529 Send a request using the transport
1532 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1534 struct rpc_request *req;
1535 struct dcerpc_pipe *p;
1536 DATA_BLOB *stub_data;
1537 struct ncacn_packet pkt;
1538 DATA_BLOB blob;
1539 uint32_t remaining, chunk_size;
1540 bool first_packet = true;
1541 size_t sig_size = 0;
1542 bool need_async = false;
1543 bool can_async = true;
1545 req = c->request_queue;
1546 if (req == NULL) {
1547 return;
1550 p = req->p;
1551 stub_data = &req->request_data;
1553 if (c->pending) {
1554 need_async = true;
1557 if (c->security_state.auth_info &&
1558 c->security_state.generic_state)
1560 struct gensec_security *gensec = c->security_state.generic_state;
1562 switch (c->security_state.auth_info->auth_level) {
1563 case DCERPC_AUTH_LEVEL_PRIVACY:
1564 case DCERPC_AUTH_LEVEL_INTEGRITY:
1565 can_async = gensec_have_feature(gensec,
1566 GENSEC_FEATURE_ASYNC_REPLIES);
1567 break;
1568 case DCERPC_AUTH_LEVEL_CONNECT:
1569 case DCERPC_AUTH_LEVEL_NONE:
1570 can_async = true;
1571 break;
1572 default:
1573 can_async = false;
1574 break;
1578 if (need_async && !can_async) {
1579 req->wait_for_sync = true;
1580 return;
1583 DLIST_REMOVE(c->request_queue, req);
1584 DLIST_ADD(c->pending, req);
1585 req->state = RPC_REQUEST_PENDING;
1587 init_ncacn_hdr(p->conn, &pkt);
1589 remaining = stub_data->length;
1591 /* we can write a full max_recv_frag size, minus the dcerpc
1592 request header size */
1593 chunk_size = p->conn->srv_max_recv_frag;
1594 chunk_size -= DCERPC_REQUEST_LENGTH;
1595 if (c->security_state.auth_info &&
1596 c->security_state.generic_state) {
1597 sig_size = gensec_sig_size(c->security_state.generic_state,
1598 p->conn->srv_max_recv_frag);
1599 if (sig_size) {
1600 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1601 chunk_size -= sig_size;
1604 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1606 pkt.ptype = DCERPC_PKT_REQUEST;
1607 pkt.call_id = req->call_id;
1608 pkt.auth_length = 0;
1609 pkt.pfc_flags = 0;
1610 pkt.u.request.alloc_hint = remaining;
1611 pkt.u.request.context_id = p->context_id;
1612 pkt.u.request.opnum = req->opnum;
1614 if (req->object) {
1615 pkt.u.request.object.object = *req->object;
1616 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1617 chunk_size -= ndr_size_GUID(req->object,0);
1620 /* we send a series of pdus without waiting for a reply */
1621 while (remaining > 0 || first_packet) {
1622 uint32_t chunk = MIN(chunk_size, remaining);
1623 bool last_frag = false;
1624 bool do_trans = false;
1626 first_packet = false;
1627 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1629 if (remaining == stub_data->length) {
1630 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1632 if (chunk == remaining) {
1633 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1634 last_frag = true;
1637 pkt.u.request.stub_and_verifier.data = stub_data->data +
1638 (stub_data->length - remaining);
1639 pkt.u.request.stub_and_verifier.length = chunk;
1641 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1642 if (!NT_STATUS_IS_OK(req->status)) {
1643 req->state = RPC_REQUEST_DONE;
1644 DLIST_REMOVE(p->conn->pending, req);
1645 return;
1648 if (last_frag && !need_async) {
1649 do_trans = true;
1652 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1653 if (!NT_STATUS_IS_OK(req->status)) {
1654 req->state = RPC_REQUEST_DONE;
1655 DLIST_REMOVE(p->conn->pending, req);
1656 return;
1659 if (last_frag && !do_trans) {
1660 req->status = p->conn->transport.send_read(p->conn);
1661 if (!NT_STATUS_IS_OK(req->status)) {
1662 req->state = RPC_REQUEST_DONE;
1663 DLIST_REMOVE(p->conn->pending, req);
1664 return;
1668 remaining -= chunk;
1672 static void dcerpc_io_trigger(struct tevent_context *ctx,
1673 struct tevent_immediate *im,
1674 void *private_data)
1676 struct dcecli_connection *c =
1677 talloc_get_type_abort(private_data,
1678 struct dcecli_connection);
1680 c->io_trigger_pending = false;
1682 dcerpc_schedule_io_trigger(c);
1684 dcerpc_ship_next_request(c);
1687 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1689 if (c->dead) {
1690 return;
1693 if (c->request_queue == NULL) {
1694 return;
1697 if (c->request_queue->wait_for_sync && c->pending) {
1698 return;
1701 if (c->io_trigger_pending) {
1702 return;
1705 c->io_trigger_pending = true;
1707 tevent_schedule_immediate(c->io_trigger,
1708 c->event_ctx,
1709 dcerpc_io_trigger,
1714 return the event context for a dcerpc pipe
1715 used by callers who wish to operate asynchronously
1717 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1719 return p->conn->event_ctx;
1725 perform the receive side of a async dcerpc request
1727 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1728 TALLOC_CTX *mem_ctx,
1729 DATA_BLOB *stub_data)
1731 NTSTATUS status;
1733 while (req->state != RPC_REQUEST_DONE) {
1734 struct tevent_context *ctx = dcerpc_event_context(req->p);
1735 if (tevent_loop_once(ctx) != 0) {
1736 return NT_STATUS_CONNECTION_DISCONNECTED;
1739 *stub_data = req->payload;
1740 status = req->status;
1741 if (stub_data->data) {
1742 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1744 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1745 req->p->last_fault_code = req->fault_code;
1747 talloc_unlink(talloc_parent(req), req);
1748 return status;
1752 this is a paranoid NDR validator. For every packet we push onto the wire
1753 we pull it back again, then push it again. Then we compare the raw NDR data
1754 for that to the NDR we initially generated. If they don't match then we know
1755 we must have a bug in either the pull or push side of our code
1757 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1758 TALLOC_CTX *mem_ctx,
1759 DATA_BLOB blob,
1760 size_t struct_size,
1761 ndr_push_flags_fn_t ndr_push,
1762 ndr_pull_flags_fn_t ndr_pull)
1764 void *st;
1765 struct ndr_pull *pull;
1766 struct ndr_push *push;
1767 DATA_BLOB blob2;
1768 enum ndr_err_code ndr_err;
1770 st = talloc_size(mem_ctx, struct_size);
1771 if (!st) {
1772 return NT_STATUS_NO_MEMORY;
1775 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1776 if (!pull) {
1777 return NT_STATUS_NO_MEMORY;
1779 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1781 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1782 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1785 if (c->flags & DCERPC_NDR64) {
1786 pull->flags |= LIBNDR_FLAG_NDR64;
1789 ndr_err = ndr_pull(pull, NDR_IN, st);
1790 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1791 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1792 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1793 "failed input validation pull - %s",
1794 nt_errstr(status));
1795 return ndr_map_error2ntstatus(ndr_err);
1798 push = ndr_push_init_ctx(mem_ctx);
1799 if (!push) {
1800 return NT_STATUS_NO_MEMORY;
1803 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1804 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1807 if (c->flags & DCERPC_NDR64) {
1808 push->flags |= LIBNDR_FLAG_NDR64;
1811 ndr_err = ndr_push(push, NDR_IN, st);
1812 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1813 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1814 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1815 "failed input validation push - %s",
1816 nt_errstr(status));
1817 return ndr_map_error2ntstatus(ndr_err);
1820 blob2 = ndr_push_blob(push);
1822 if (data_blob_cmp(&blob, &blob2) != 0) {
1823 DEBUG(3,("original:\n"));
1824 dump_data(3, blob.data, blob.length);
1825 DEBUG(3,("secondary:\n"));
1826 dump_data(3, blob2.data, blob2.length);
1827 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1828 "failed input validation blobs doesn't match");
1829 return ndr_map_error2ntstatus(ndr_err);
1832 return NT_STATUS_OK;
1836 this is a paranoid NDR input validator. For every packet we pull
1837 from the wire we push it back again then pull and push it
1838 again. Then we compare the raw NDR data for that to the NDR we
1839 initially generated. If they don't match then we know we must have a
1840 bug in either the pull or push side of our code
1842 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1843 struct ndr_pull *pull_in,
1844 void *struct_ptr,
1845 size_t struct_size,
1846 ndr_push_flags_fn_t ndr_push,
1847 ndr_pull_flags_fn_t ndr_pull,
1848 ndr_print_function_t ndr_print)
1850 void *st;
1851 struct ndr_pull *pull;
1852 struct ndr_push *push;
1853 DATA_BLOB blob, blob2;
1854 TALLOC_CTX *mem_ctx = pull_in;
1855 char *s1, *s2;
1856 enum ndr_err_code ndr_err;
1858 st = talloc_size(mem_ctx, struct_size);
1859 if (!st) {
1860 return NT_STATUS_NO_MEMORY;
1862 memcpy(st, struct_ptr, struct_size);
1864 push = ndr_push_init_ctx(mem_ctx);
1865 if (!push) {
1866 return NT_STATUS_NO_MEMORY;
1869 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1870 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1871 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1872 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1873 "failed output validation push - %s",
1874 nt_errstr(status));
1875 return ndr_map_error2ntstatus(ndr_err);
1878 blob = ndr_push_blob(push);
1880 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1881 if (!pull) {
1882 return NT_STATUS_NO_MEMORY;
1885 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1886 ndr_err = ndr_pull(pull, NDR_OUT, st);
1887 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1888 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1889 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1890 "failed output validation pull - %s",
1891 nt_errstr(status));
1892 return ndr_map_error2ntstatus(ndr_err);
1895 push = ndr_push_init_ctx(mem_ctx);
1896 if (!push) {
1897 return NT_STATUS_NO_MEMORY;
1900 ndr_err = ndr_push(push, NDR_OUT, st);
1901 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1902 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1903 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1904 "failed output validation push2 - %s",
1905 nt_errstr(status));
1906 return ndr_map_error2ntstatus(ndr_err);
1909 blob2 = ndr_push_blob(push);
1911 if (data_blob_cmp(&blob, &blob2) != 0) {
1912 DEBUG(3,("original:\n"));
1913 dump_data(3, blob.data, blob.length);
1914 DEBUG(3,("secondary:\n"));
1915 dump_data(3, blob2.data, blob2.length);
1916 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1917 "failed output validation blobs doesn't match");
1918 return ndr_map_error2ntstatus(ndr_err);
1921 /* this checks the printed forms of the two structures, which effectively
1922 tests all of the value() attributes */
1923 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1924 NDR_OUT, struct_ptr);
1925 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1926 NDR_OUT, st);
1927 if (strcmp(s1, s2) != 0) {
1928 #if 1
1929 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1930 #else
1931 /* this is sometimes useful */
1932 printf("VALIDATE ERROR\n");
1933 file_save("wire.dat", s1, strlen(s1));
1934 file_save("gen.dat", s2, strlen(s2));
1935 system("diff -u wire.dat gen.dat");
1936 #endif
1937 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1938 "failed output validation strings doesn't match");
1939 return ndr_map_error2ntstatus(ndr_err);
1942 return NT_STATUS_OK;
1946 a useful function for retrieving the server name we connected to
1948 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1950 if (!p->conn->transport.target_hostname) {
1951 if (!p->conn->transport.peer_name) {
1952 return "";
1954 return p->conn->transport.peer_name(p->conn);
1956 return p->conn->transport.target_hostname(p->conn);
1961 get the dcerpc auth_level for a open connection
1963 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1965 uint8_t auth_level;
1967 if (c->flags & DCERPC_SEAL) {
1968 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1969 } else if (c->flags & DCERPC_SIGN) {
1970 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1971 } else if (c->flags & DCERPC_CONNECT) {
1972 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1973 } else {
1974 auth_level = DCERPC_AUTH_LEVEL_NONE;
1976 return auth_level;
1979 struct dcerpc_alter_context_state {
1980 struct tevent_context *ev;
1981 struct dcerpc_pipe *p;
1984 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
1985 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
1986 DATA_BLOB *raw_packet,
1987 struct ncacn_packet *pkt);
1989 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
1990 struct tevent_context *ev,
1991 struct dcerpc_pipe *p,
1992 const struct ndr_syntax_id *syntax,
1993 const struct ndr_syntax_id *transfer_syntax)
1995 struct tevent_req *req;
1996 struct dcerpc_alter_context_state *state;
1997 struct ncacn_packet pkt;
1998 DATA_BLOB blob;
1999 NTSTATUS status;
2000 struct rpc_request *subreq;
2002 req = tevent_req_create(mem_ctx, &state,
2003 struct dcerpc_alter_context_state);
2004 if (req == NULL) {
2005 return NULL;
2008 state->ev = ev;
2009 state->p = p;
2011 p->syntax = *syntax;
2012 p->transfer_syntax = *transfer_syntax;
2014 init_ncacn_hdr(p->conn, &pkt);
2016 pkt.ptype = DCERPC_PKT_ALTER;
2017 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2018 pkt.call_id = p->conn->call_id;
2019 pkt.auth_length = 0;
2021 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
2022 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2025 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
2026 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
2029 pkt.u.alter.max_xmit_frag = 5840;
2030 pkt.u.alter.max_recv_frag = 5840;
2031 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
2032 pkt.u.alter.num_contexts = 1;
2033 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2034 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2035 return tevent_req_post(req, ev);
2037 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2038 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2039 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2040 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2041 pkt.u.alter.auth_info = data_blob(NULL, 0);
2043 /* construct the NDR form of the packet */
2044 status = ncacn_push_auth(&blob, state, &pkt,
2045 p->conn->security_state.auth_info);
2046 if (tevent_req_nterror(req, status)) {
2047 return tevent_req_post(req, ev);
2050 p->conn->transport.recv_data = dcerpc_recv_data;
2053 * we allocate a dcerpc_request so we can be in the same
2054 * request queue as normal requests
2056 subreq = talloc_zero(state, struct rpc_request);
2057 if (tevent_req_nomem(subreq, req)) {
2058 return tevent_req_post(req, ev);
2061 subreq->state = RPC_REQUEST_PENDING;
2062 subreq->call_id = pkt.call_id;
2063 subreq->async.private_data = req;
2064 subreq->async.callback = dcerpc_alter_context_fail_handler;
2065 subreq->p = p;
2066 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2067 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2068 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2070 status = p->conn->transport.send_request(p->conn, &blob, true);
2071 if (tevent_req_nterror(req, status)) {
2072 return tevent_req_post(req, ev);
2075 tevent_add_timer(ev, subreq,
2076 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2077 dcerpc_timeout_handler, subreq);
2079 return req;
2082 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2084 struct tevent_req *req =
2085 talloc_get_type_abort(subreq->async.private_data,
2086 struct tevent_req);
2087 struct dcerpc_alter_context_state *state =
2088 tevent_req_data(req,
2089 struct dcerpc_alter_context_state);
2090 NTSTATUS status = subreq->status;
2092 TALLOC_FREE(subreq);
2095 * We trigger the callback in the next event run
2096 * because the code in this file might trigger
2097 * multiple request callbacks from within a single
2098 * while loop.
2100 * In order to avoid segfaults from within
2101 * dcerpc_connection_dead() we call
2102 * tevent_req_defer_callback().
2104 tevent_req_defer_callback(req, state->ev);
2106 tevent_req_nterror(req, status);
2109 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2110 DATA_BLOB *raw_packet,
2111 struct ncacn_packet *pkt)
2113 struct tevent_req *req =
2114 talloc_get_type_abort(subreq->async.private_data,
2115 struct tevent_req);
2116 struct dcerpc_alter_context_state *state =
2117 tevent_req_data(req,
2118 struct dcerpc_alter_context_state);
2119 struct dcecli_connection *conn = state->p->conn;
2120 NTSTATUS status;
2123 * Note that pkt is allocated under raw_packet->data,
2124 * while raw_packet->data is a child of subreq.
2126 talloc_steal(state, raw_packet->data);
2127 TALLOC_FREE(subreq);
2130 * We trigger the callback in the next event run
2131 * because the code in this file might trigger
2132 * multiple request callbacks from within a single
2133 * while loop.
2135 * In order to avoid segfaults from within
2136 * dcerpc_connection_dead() we call
2137 * tevent_req_defer_callback().
2139 tevent_req_defer_callback(req, state->ev);
2141 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2142 pkt->u.alter_resp.num_results == 1 &&
2143 pkt->u.alter_resp.ctx_list[0].result != 0) {
2144 status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason);
2145 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2146 pkt->u.alter_resp.ctx_list[0].reason,
2147 nt_errstr(status)));
2148 tevent_req_nterror(req, status);
2149 return;
2152 if (pkt->ptype == DCERPC_PKT_FAULT) {
2153 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2154 dcerpc_errstr(state, pkt->u.fault.status)));
2155 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2156 state->p->last_fault_code = pkt->u.fault.status;
2157 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2158 } else {
2159 state->p->last_fault_code = pkt->u.fault.status;
2160 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2162 return;
2165 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2166 pkt->u.alter_resp.num_results == 0 ||
2167 pkt->u.alter_resp.ctx_list[0].result != 0) {
2168 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2169 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2170 return;
2173 /* the alter_resp might contain a reply set of credentials */
2174 if (conn->security_state.auth_info &&
2175 pkt->u.alter_resp.auth_info.length) {
2176 uint32_t auth_length;
2178 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2179 conn->security_state.auth_info, &auth_length, true);
2180 if (tevent_req_nterror(req, status)) {
2181 return;
2185 tevent_req_done(req);
2188 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2190 return tevent_req_simple_recv_ntstatus(req);
2194 send a dcerpc alter_context request
2196 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2197 TALLOC_CTX *mem_ctx,
2198 const struct ndr_syntax_id *syntax,
2199 const struct ndr_syntax_id *transfer_syntax)
2201 struct tevent_req *subreq;
2202 struct tevent_context *ev = p->conn->event_ctx;
2203 bool ok;
2205 /* TODO: create a new event context here */
2207 subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx,
2208 p, syntax, transfer_syntax);
2209 if (subreq == NULL) {
2210 return NT_STATUS_NO_MEMORY;
2213 ok = tevent_req_poll(subreq, ev);
2214 if (!ok) {
2215 NTSTATUS status;
2216 status = map_nt_error_from_unix_common(errno);
2217 return status;
2220 return dcerpc_alter_context_recv(subreq);