CVE-2013-4408:s4:dcerpc: check for invalid frag_len in ncacn_pull()
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blob56b821ecce09c23dc0bbae330ffa8ed424221e48
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 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
204 enum dcerpc_AuthType *auth_type,
205 enum dcerpc_AuthLevel *auth_level)
207 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
208 struct dcerpc_bh_state);
210 if (hs->p == NULL) {
211 return;
214 if (hs->p->conn == NULL) {
215 return;
218 if (hs->p->conn->security_state.auth_info == NULL) {
219 return;
222 *auth_type = hs->p->conn->security_state.auth_info->auth_type;
223 *auth_level = hs->p->conn->security_state.auth_info->auth_level;
226 struct dcerpc_bh_raw_call_state {
227 struct tevent_context *ev;
228 struct dcerpc_binding_handle *h;
229 DATA_BLOB in_data;
230 DATA_BLOB out_data;
231 uint32_t out_flags;
234 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
236 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
237 struct tevent_context *ev,
238 struct dcerpc_binding_handle *h,
239 const struct GUID *object,
240 uint32_t opnum,
241 uint32_t in_flags,
242 const uint8_t *in_data,
243 size_t in_length)
245 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
246 struct dcerpc_bh_state);
247 struct tevent_req *req;
248 struct dcerpc_bh_raw_call_state *state;
249 bool ok;
250 struct rpc_request *subreq;
252 req = tevent_req_create(mem_ctx, &state,
253 struct dcerpc_bh_raw_call_state);
254 if (req == NULL) {
255 return NULL;
257 state->ev = ev;
258 state->h = h;
259 state->in_data.data = discard_const_p(uint8_t, in_data);
260 state->in_data.length = in_length;
262 ok = dcerpc_bh_is_connected(h);
263 if (!ok) {
264 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
265 return tevent_req_post(req, ev);
268 subreq = dcerpc_request_send(state,
269 hs->p,
270 object,
271 opnum,
272 &state->in_data);
273 if (tevent_req_nomem(subreq, req)) {
274 return tevent_req_post(req, ev);
276 subreq->async.callback = dcerpc_bh_raw_call_done;
277 subreq->async.private_data = req;
279 return req;
282 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
284 struct tevent_req *req =
285 talloc_get_type_abort(subreq->async.private_data,
286 struct tevent_req);
287 struct dcerpc_bh_raw_call_state *state =
288 tevent_req_data(req,
289 struct dcerpc_bh_raw_call_state);
290 NTSTATUS status;
291 uint32_t fault_code;
293 state->out_flags = 0;
294 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
295 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
298 fault_code = subreq->fault_code;
300 status = dcerpc_request_recv(subreq, state, &state->out_data);
301 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
302 status = dcerpc_fault_to_nt_status(fault_code);
306 * We trigger the callback in the next event run
307 * because the code in this file might trigger
308 * multiple request callbacks from within a single
309 * while loop.
311 * In order to avoid segfaults from within
312 * dcerpc_connection_dead() we call
313 * tevent_req_defer_callback().
315 tevent_req_defer_callback(req, state->ev);
317 if (!NT_STATUS_IS_OK(status)) {
318 tevent_req_nterror(req, status);
319 return;
322 tevent_req_done(req);
325 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
326 TALLOC_CTX *mem_ctx,
327 uint8_t **out_data,
328 size_t *out_length,
329 uint32_t *out_flags)
331 struct dcerpc_bh_raw_call_state *state =
332 tevent_req_data(req,
333 struct dcerpc_bh_raw_call_state);
334 NTSTATUS status;
336 if (tevent_req_is_nterror(req, &status)) {
337 tevent_req_received(req);
338 return status;
341 *out_data = talloc_move(mem_ctx, &state->out_data.data);
342 *out_length = state->out_data.length;
343 *out_flags = state->out_flags;
344 tevent_req_received(req);
345 return NT_STATUS_OK;
348 struct dcerpc_bh_disconnect_state {
349 uint8_t _dummy;
352 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
353 struct tevent_context *ev,
354 struct dcerpc_binding_handle *h)
356 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
357 struct dcerpc_bh_state);
358 struct tevent_req *req;
359 struct dcerpc_bh_disconnect_state *state;
360 bool ok;
362 req = tevent_req_create(mem_ctx, &state,
363 struct dcerpc_bh_disconnect_state);
364 if (req == NULL) {
365 return NULL;
368 ok = dcerpc_bh_is_connected(h);
369 if (!ok) {
370 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
371 return tevent_req_post(req, ev);
374 /* TODO: do a real disconnect ... */
375 hs->p = NULL;
377 tevent_req_done(req);
378 return tevent_req_post(req, ev);
381 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
383 NTSTATUS status;
385 if (tevent_req_is_nterror(req, &status)) {
386 tevent_req_received(req);
387 return status;
390 tevent_req_received(req);
391 return NT_STATUS_OK;
394 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
396 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
397 struct dcerpc_bh_state);
399 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
400 return true;
403 return false;
406 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
408 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
409 struct dcerpc_bh_state);
411 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
412 return true;
415 return false;
418 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
420 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
421 struct dcerpc_bh_state);
423 if (hs->p->conn->flags & DCERPC_NDR64) {
424 return true;
427 return false;
430 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
431 int ndr_flags,
432 const void *_struct_ptr,
433 const struct ndr_interface_call *call)
435 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
436 struct dcerpc_bh_state);
437 void *struct_ptr = discard_const(_struct_ptr);
439 if (ndr_flags & NDR_IN) {
440 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
441 ndr_print_function_debug(call->ndr_print,
442 call->name,
443 ndr_flags,
444 struct_ptr);
447 if (ndr_flags & NDR_OUT) {
448 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
449 ndr_print_function_debug(call->ndr_print,
450 call->name,
451 ndr_flags,
452 struct_ptr);
457 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
458 NTSTATUS error,
459 const void *struct_ptr,
460 const struct ndr_interface_call *call)
462 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
463 call->name, nt_errstr(error)));
466 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
467 NTSTATUS error,
468 const DATA_BLOB *blob,
469 const struct ndr_interface_call *call)
471 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
472 struct dcerpc_bh_state);
473 const uint32_t num_examples = 20;
474 uint32_t i;
476 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
477 call->name, nt_errstr(error)));
479 if (hs->p->conn->packet_log_dir == NULL) return;
481 for (i=0;i<num_examples;i++) {
482 char *name=NULL;
483 asprintf(&name, "%s/rpclog/%s-out.%d",
484 hs->p->conn->packet_log_dir,
485 call->name, i);
486 if (name == NULL) {
487 return;
489 if (!file_exist(name)) {
490 if (file_save(name, blob->data, blob->length)) {
491 DEBUG(10,("Logged rpc packet to %s\n", name));
493 free(name);
494 break;
496 free(name);
500 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
501 TALLOC_CTX *mem_ctx,
502 const DATA_BLOB *blob,
503 const struct ndr_interface_call *call)
505 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
506 struct dcerpc_bh_state);
508 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
509 NTSTATUS status;
511 status = dcerpc_ndr_validate_in(hs->p->conn,
512 mem_ctx,
513 *blob,
514 call->struct_size,
515 call->ndr_push,
516 call->ndr_pull);
517 if (!NT_STATUS_IS_OK(status)) {
518 DEBUG(0,("Validation [in] failed for %s - %s\n",
519 call->name, nt_errstr(status)));
520 return status;
524 DEBUG(10,("rpc request data:\n"));
525 dump_data(10, blob->data, blob->length);
527 return NT_STATUS_OK;
530 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
531 struct ndr_pull *pull_in,
532 const void *_struct_ptr,
533 const struct ndr_interface_call *call)
535 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
536 struct dcerpc_bh_state);
537 void *struct_ptr = discard_const(_struct_ptr);
539 DEBUG(10,("rpc reply data:\n"));
540 dump_data(10, pull_in->data, pull_in->data_size);
542 if (pull_in->offset != pull_in->data_size) {
543 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
544 pull_in->data_size - pull_in->offset,
545 pull_in->offset, pull_in->offset,
546 call->name));
547 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
548 but it turns out that early versions of NT
549 (specifically NT3.1) add junk onto the end of rpc
550 packets, so if we want to interoperate at all with
551 those versions then we need to ignore this error */
554 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
555 NTSTATUS status;
557 status = dcerpc_ndr_validate_out(hs->p->conn,
558 pull_in,
559 struct_ptr,
560 call->struct_size,
561 call->ndr_push,
562 call->ndr_pull,
563 call->ndr_print);
564 if (!NT_STATUS_IS_OK(status)) {
565 DEBUG(2,("Validation [out] failed for %s - %s\n",
566 call->name, nt_errstr(status)));
567 return status;
571 return NT_STATUS_OK;
574 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
575 .name = "dcerpc",
576 .is_connected = dcerpc_bh_is_connected,
577 .set_timeout = dcerpc_bh_set_timeout,
578 .auth_info = dcerpc_bh_auth_info,
579 .raw_call_send = dcerpc_bh_raw_call_send,
580 .raw_call_recv = dcerpc_bh_raw_call_recv,
581 .disconnect_send = dcerpc_bh_disconnect_send,
582 .disconnect_recv = dcerpc_bh_disconnect_recv,
584 .push_bigendian = dcerpc_bh_push_bigendian,
585 .ref_alloc = dcerpc_bh_ref_alloc,
586 .use_ndr64 = dcerpc_bh_use_ndr64,
587 .do_ndr_print = dcerpc_bh_do_ndr_print,
588 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
589 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
590 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
591 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
594 /* initialise a dcerpc pipe. */
595 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
597 struct dcerpc_binding_handle *h;
598 struct dcerpc_bh_state *hs;
600 h = dcerpc_binding_handle_create(p,
601 &dcerpc_bh_ops,
602 NULL,
603 NULL, /* TODO */
604 &hs,
605 struct dcerpc_bh_state,
606 __location__);
607 if (h == NULL) {
608 return NULL;
610 hs->p = p;
612 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
614 return h;
617 /* initialise a dcerpc pipe. */
618 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
620 struct dcerpc_pipe *p;
622 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
623 if (!p) {
624 return NULL;
627 p->conn = dcerpc_connection_init(p, ev);
628 if (p->conn == NULL) {
629 talloc_free(p);
630 return NULL;
633 p->last_fault_code = 0;
634 p->context_id = 0;
635 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
636 p->binding = NULL;
638 ZERO_STRUCT(p->syntax);
639 ZERO_STRUCT(p->transfer_syntax);
641 if (DEBUGLVL(100)) {
642 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
645 p->binding_handle = dcerpc_pipe_binding_handle(p);
646 if (p->binding_handle == NULL) {
647 talloc_free(p);
648 return NULL;
651 return p;
656 choose the next call id to use
658 static uint32_t next_call_id(struct dcecli_connection *c)
660 c->call_id++;
661 if (c->call_id == 0) {
662 c->call_id++;
664 return c->call_id;
668 setup for a ndr pull, also setting up any flags from the binding string
670 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
671 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
673 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
675 if (ndr == NULL) return ndr;
677 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
678 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
681 if (c->flags & DCERPC_NDR_REF_ALLOC) {
682 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
685 if (c->flags & DCERPC_NDR64) {
686 ndr->flags |= LIBNDR_FLAG_NDR64;
689 return ndr;
693 parse a data blob into a ncacn_packet structure. This handles both
694 input and output packets
696 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
697 struct ncacn_packet *pkt)
699 struct ndr_pull *ndr;
700 enum ndr_err_code ndr_err;
702 ndr = ndr_pull_init_blob(blob, mem_ctx);
703 if (!ndr) {
704 return NT_STATUS_NO_MEMORY;
707 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
708 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
711 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
712 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
715 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
716 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
717 return ndr_map_error2ntstatus(ndr_err);
720 if (pkt->frag_length != blob->length) {
721 return NT_STATUS_RPC_PROTOCOL_ERROR;
724 return NT_STATUS_OK;
728 parse the authentication information on a dcerpc response packet
730 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
731 DATA_BLOB *raw_packet,
732 struct ncacn_packet *pkt)
734 NTSTATUS status;
735 struct dcerpc_auth auth;
736 uint32_t auth_length;
738 if (!c->security_state.auth_info ||
739 !c->security_state.generic_state) {
740 return NT_STATUS_OK;
743 switch (c->security_state.auth_info->auth_level) {
744 case DCERPC_AUTH_LEVEL_PRIVACY:
745 case DCERPC_AUTH_LEVEL_INTEGRITY:
746 break;
748 case DCERPC_AUTH_LEVEL_CONNECT:
749 if (pkt->auth_length != 0) {
750 break;
752 return NT_STATUS_OK;
753 case DCERPC_AUTH_LEVEL_NONE:
754 if (pkt->auth_length != 0) {
755 return NT_STATUS_INVALID_NETWORK_RESPONSE;
757 return NT_STATUS_OK;
759 default:
760 return NT_STATUS_INVALID_LEVEL;
763 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
764 &pkt->u.response.stub_and_verifier,
765 &auth, &auth_length, false);
766 NT_STATUS_NOT_OK_RETURN(status);
768 pkt->u.response.stub_and_verifier.length -= auth_length;
770 /* check signature or unseal the packet */
771 switch (c->security_state.auth_info->auth_level) {
772 case DCERPC_AUTH_LEVEL_PRIVACY:
773 status = gensec_unseal_packet(c->security_state.generic_state,
774 raw_packet->data + DCERPC_REQUEST_LENGTH,
775 pkt->u.response.stub_and_verifier.length,
776 raw_packet->data,
777 raw_packet->length - auth.credentials.length,
778 &auth.credentials);
779 memcpy(pkt->u.response.stub_and_verifier.data,
780 raw_packet->data + DCERPC_REQUEST_LENGTH,
781 pkt->u.response.stub_and_verifier.length);
782 break;
784 case DCERPC_AUTH_LEVEL_INTEGRITY:
785 status = gensec_check_packet(c->security_state.generic_state,
786 pkt->u.response.stub_and_verifier.data,
787 pkt->u.response.stub_and_verifier.length,
788 raw_packet->data,
789 raw_packet->length - auth.credentials.length,
790 &auth.credentials);
791 break;
793 case DCERPC_AUTH_LEVEL_CONNECT:
794 /* for now we ignore possible signatures here */
795 status = NT_STATUS_OK;
796 break;
798 default:
799 status = NT_STATUS_INVALID_LEVEL;
800 break;
803 /* remove the indicated amount of padding */
804 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
805 return NT_STATUS_INFO_LENGTH_MISMATCH;
807 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
809 return status;
814 push a dcerpc request packet into a blob, possibly signing it.
816 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
817 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
818 size_t sig_size,
819 struct ncacn_packet *pkt)
821 NTSTATUS status;
822 struct ndr_push *ndr;
823 DATA_BLOB creds2;
824 size_t payload_length;
825 enum ndr_err_code ndr_err;
826 size_t hdr_size = DCERPC_REQUEST_LENGTH;
828 /* non-signed packets are simpler */
829 if (sig_size == 0) {
830 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
833 switch (c->security_state.auth_info->auth_level) {
834 case DCERPC_AUTH_LEVEL_PRIVACY:
835 case DCERPC_AUTH_LEVEL_INTEGRITY:
836 break;
838 case DCERPC_AUTH_LEVEL_CONNECT:
839 /* TODO: let the gensec mech decide if it wants to generate a signature */
840 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
842 case DCERPC_AUTH_LEVEL_NONE:
843 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
845 default:
846 return NT_STATUS_INVALID_LEVEL;
849 ndr = ndr_push_init_ctx(mem_ctx);
850 if (!ndr) {
851 return NT_STATUS_NO_MEMORY;
854 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
855 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
858 if (c->flags & DCERPC_NDR64) {
859 ndr->flags |= LIBNDR_FLAG_NDR64;
862 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
863 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
864 hdr_size += 16;
867 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
868 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
869 return ndr_map_error2ntstatus(ndr_err);
872 /* pad to 16 byte multiple in the payload portion of the
873 packet. This matches what w2k3 does. Note that we can't use
874 ndr_push_align() as that is relative to the start of the
875 whole packet, whereas w2k8 wants it relative to the start
876 of the stub */
877 c->security_state.auth_info->auth_pad_length =
878 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
879 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
880 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
881 return ndr_map_error2ntstatus(ndr_err);
884 payload_length = pkt->u.request.stub_and_verifier.length +
885 c->security_state.auth_info->auth_pad_length;
887 /* we start without signature, it will appended later */
888 c->security_state.auth_info->credentials = data_blob(NULL,0);
890 /* add the auth verifier */
891 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
892 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
893 return ndr_map_error2ntstatus(ndr_err);
896 /* extract the whole packet as a blob */
897 *blob = ndr_push_blob(ndr);
900 * Setup the frag and auth length in the packet buffer.
901 * This is needed if the GENSEC mech does AEAD signing
902 * of the packet headers. The signature itself will be
903 * appended later.
905 dcerpc_set_frag_length(blob, blob->length + sig_size);
906 dcerpc_set_auth_length(blob, sig_size);
908 /* sign or seal the packet */
909 switch (c->security_state.auth_info->auth_level) {
910 case DCERPC_AUTH_LEVEL_PRIVACY:
911 status = gensec_seal_packet(c->security_state.generic_state,
912 mem_ctx,
913 blob->data + hdr_size,
914 payload_length,
915 blob->data,
916 blob->length,
917 &creds2);
918 if (!NT_STATUS_IS_OK(status)) {
919 return status;
921 break;
923 case DCERPC_AUTH_LEVEL_INTEGRITY:
924 status = gensec_sign_packet(c->security_state.generic_state,
925 mem_ctx,
926 blob->data + hdr_size,
927 payload_length,
928 blob->data,
929 blob->length,
930 &creds2);
931 if (!NT_STATUS_IS_OK(status)) {
932 return status;
934 break;
936 default:
937 status = NT_STATUS_INVALID_LEVEL;
938 break;
941 if (creds2.length != sig_size) {
942 /* this means the sig_size estimate for the signature
943 was incorrect. We have to correct the packet
944 sizes. That means we could go over the max fragment
945 length */
946 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
947 (unsigned) creds2.length,
948 (unsigned) sig_size,
949 (unsigned) c->security_state.auth_info->auth_pad_length,
950 (unsigned) pkt->u.request.stub_and_verifier.length));
951 dcerpc_set_frag_length(blob, blob->length + creds2.length);
952 dcerpc_set_auth_length(blob, creds2.length);
955 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
956 return NT_STATUS_NO_MEMORY;
959 return NT_STATUS_OK;
964 fill in the fixed values in a dcerpc header
966 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
968 pkt->rpc_vers = 5;
969 pkt->rpc_vers_minor = 0;
970 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
971 pkt->drep[0] = 0;
972 } else {
973 pkt->drep[0] = DCERPC_DREP_LE;
975 pkt->drep[1] = 0;
976 pkt->drep[2] = 0;
977 pkt->drep[3] = 0;
981 map a bind nak reason to a NTSTATUS
983 static NTSTATUS dcerpc_map_reason(uint16_t reason)
985 switch (reason) {
986 case DCERPC_BIND_REASON_ASYNTAX:
987 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
988 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
989 return NT_STATUS_INVALID_PARAMETER;
991 return NT_STATUS_UNSUCCESSFUL;
995 remove requests from the pending or queued queues
997 static int dcerpc_req_dequeue(struct rpc_request *req)
999 switch (req->state) {
1000 case RPC_REQUEST_QUEUED:
1001 DLIST_REMOVE(req->p->conn->request_queue, req);
1002 break;
1003 case RPC_REQUEST_PENDING:
1004 DLIST_REMOVE(req->p->conn->pending, req);
1005 break;
1006 case RPC_REQUEST_DONE:
1007 break;
1009 return 0;
1014 mark the dcerpc connection dead. All outstanding requests get an error
1016 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1018 if (conn->dead) return;
1020 conn->dead = true;
1022 TALLOC_FREE(conn->io_trigger);
1023 conn->io_trigger_pending = false;
1025 conn->transport.recv_data = NULL;
1027 if (conn->transport.shutdown_pipe) {
1028 conn->transport.shutdown_pipe(conn, status);
1031 /* all pending requests get the error */
1032 while (conn->pending) {
1033 struct rpc_request *req = conn->pending;
1034 dcerpc_req_dequeue(req);
1035 req->state = RPC_REQUEST_DONE;
1036 req->status = status;
1037 if (req->async.callback) {
1038 req->async.callback(req);
1042 /* all requests, which are not shipped */
1043 while (conn->request_queue) {
1044 struct rpc_request *req = conn->request_queue;
1045 dcerpc_req_dequeue(req);
1046 req->state = RPC_REQUEST_DONE;
1047 req->status = status;
1048 if (req->async.callback) {
1049 req->async.callback(req);
1053 talloc_set_destructor(conn, NULL);
1054 if (conn->free_skipped) {
1055 talloc_free(conn);
1060 forward declarations of the recv_data handlers for the types of
1061 packets we need to handle
1063 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1064 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1067 receive a dcerpc reply from the transport. Here we work out what
1068 type of reply it is (normal request, bind or alter context) and
1069 dispatch to the appropriate handler
1071 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1073 struct ncacn_packet pkt;
1075 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1076 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1079 /* the transport may be telling us of a severe error, such as
1080 a dropped socket */
1081 if (!NT_STATUS_IS_OK(status)) {
1082 data_blob_free(blob);
1083 dcerpc_connection_dead(conn, status);
1084 return;
1087 /* parse the basic packet to work out what type of response this is */
1088 status = ncacn_pull(conn, blob, blob->data, &pkt);
1089 if (!NT_STATUS_IS_OK(status)) {
1090 data_blob_free(blob);
1091 dcerpc_connection_dead(conn, status);
1092 return;
1095 dcerpc_request_recv_data(conn, blob, &pkt);
1099 handle timeouts of individual dcerpc requests
1101 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1102 struct timeval t, void *private_data)
1104 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1106 if (req->ignore_timeout) {
1107 dcerpc_req_dequeue(req);
1108 req->state = RPC_REQUEST_DONE;
1109 req->status = NT_STATUS_IO_TIMEOUT;
1110 if (req->async.callback) {
1111 req->async.callback(req);
1113 return;
1116 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1119 struct dcerpc_bind_state {
1120 struct tevent_context *ev;
1121 struct dcerpc_pipe *p;
1124 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1125 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1126 DATA_BLOB *raw_packet,
1127 struct ncacn_packet *pkt);
1129 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1130 struct tevent_context *ev,
1131 struct dcerpc_pipe *p,
1132 const struct ndr_syntax_id *syntax,
1133 const struct ndr_syntax_id *transfer_syntax)
1135 struct tevent_req *req;
1136 struct dcerpc_bind_state *state;
1137 struct ncacn_packet pkt;
1138 DATA_BLOB blob;
1139 NTSTATUS status;
1140 struct rpc_request *subreq;
1142 req = tevent_req_create(mem_ctx, &state,
1143 struct dcerpc_bind_state);
1144 if (req == NULL) {
1145 return NULL;
1148 state->ev = ev;
1149 state->p = p;
1151 p->syntax = *syntax;
1152 p->transfer_syntax = *transfer_syntax;
1154 init_ncacn_hdr(p->conn, &pkt);
1156 pkt.ptype = DCERPC_PKT_BIND;
1157 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1158 pkt.call_id = p->conn->call_id;
1159 pkt.auth_length = 0;
1161 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1162 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1165 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1166 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1169 pkt.u.bind.max_xmit_frag = 5840;
1170 pkt.u.bind.max_recv_frag = 5840;
1171 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1172 pkt.u.bind.num_contexts = 1;
1173 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1174 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1175 return tevent_req_post(req, ev);
1177 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1178 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1179 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1180 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1181 pkt.u.bind.auth_info = data_blob(NULL, 0);
1183 /* construct the NDR form of the packet */
1184 status = ncacn_push_auth(&blob, state, &pkt,
1185 p->conn->security_state.auth_info);
1186 if (tevent_req_nterror(req, status)) {
1187 return tevent_req_post(req, ev);
1190 p->conn->transport.recv_data = dcerpc_recv_data;
1193 * we allocate a dcerpc_request so we can be in the same
1194 * request queue as normal requests
1196 subreq = talloc_zero(state, struct rpc_request);
1197 if (tevent_req_nomem(subreq, req)) {
1198 return tevent_req_post(req, ev);
1201 subreq->state = RPC_REQUEST_PENDING;
1202 subreq->call_id = pkt.call_id;
1203 subreq->async.private_data = req;
1204 subreq->async.callback = dcerpc_bind_fail_handler;
1205 subreq->p = p;
1206 subreq->recv_handler = dcerpc_bind_recv_handler;
1207 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1208 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1210 status = p->conn->transport.send_request(p->conn, &blob, true);
1211 if (tevent_req_nterror(req, status)) {
1212 return tevent_req_post(req, ev);
1215 tevent_add_timer(ev, subreq,
1216 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1217 dcerpc_timeout_handler, subreq);
1219 return req;
1222 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1224 struct tevent_req *req =
1225 talloc_get_type_abort(subreq->async.private_data,
1226 struct tevent_req);
1227 struct dcerpc_bind_state *state =
1228 tevent_req_data(req,
1229 struct dcerpc_bind_state);
1230 NTSTATUS status = subreq->status;
1232 TALLOC_FREE(subreq);
1235 * We trigger the callback in the next event run
1236 * because the code in this file might trigger
1237 * multiple request callbacks from within a single
1238 * while loop.
1240 * In order to avoid segfaults from within
1241 * dcerpc_connection_dead() we call
1242 * tevent_req_defer_callback().
1244 tevent_req_defer_callback(req, state->ev);
1246 tevent_req_nterror(req, status);
1249 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1250 DATA_BLOB *raw_packet,
1251 struct ncacn_packet *pkt)
1253 struct tevent_req *req =
1254 talloc_get_type_abort(subreq->async.private_data,
1255 struct tevent_req);
1256 struct dcerpc_bind_state *state =
1257 tevent_req_data(req,
1258 struct dcerpc_bind_state);
1259 struct dcecli_connection *conn = state->p->conn;
1260 NTSTATUS status;
1263 * Note that pkt is allocated under raw_packet->data,
1264 * while raw_packet->data is a child of subreq.
1266 talloc_steal(state, raw_packet->data);
1267 TALLOC_FREE(subreq);
1270 * We trigger the callback in the next event run
1271 * because the code in this file might trigger
1272 * multiple request callbacks from within a single
1273 * while loop.
1275 * In order to avoid segfaults from within
1276 * dcerpc_connection_dead() we call
1277 * tevent_req_defer_callback().
1279 tevent_req_defer_callback(req, state->ev);
1281 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1282 status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason);
1284 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1285 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1287 tevent_req_nterror(req, status);
1288 return;
1291 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1292 (pkt->u.bind_ack.num_results == 0) ||
1293 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1294 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1295 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1296 return;
1299 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1300 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1302 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1303 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1304 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1307 if ((state->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1308 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1309 conn->flags |= DCERPC_HEADER_SIGNING;
1312 /* the bind_ack might contain a reply set of credentials */
1313 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1314 uint32_t auth_length;
1316 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1317 conn->security_state.auth_info, &auth_length, true);
1318 if (tevent_req_nterror(req, status)) {
1319 return;
1323 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1325 tevent_req_done(req);
1328 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1330 return tevent_req_simple_recv_ntstatus(req);
1334 perform a continued bind (and auth3)
1336 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1337 TALLOC_CTX *mem_ctx)
1339 struct ncacn_packet pkt;
1340 NTSTATUS status;
1341 DATA_BLOB blob;
1343 init_ncacn_hdr(p->conn, &pkt);
1345 pkt.ptype = DCERPC_PKT_AUTH3;
1346 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1347 pkt.call_id = next_call_id(p->conn);
1348 pkt.auth_length = 0;
1349 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1351 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1352 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1355 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1356 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1359 /* construct the NDR form of the packet */
1360 status = ncacn_push_auth(&blob, mem_ctx,
1361 &pkt,
1362 p->conn->security_state.auth_info);
1363 if (!NT_STATUS_IS_OK(status)) {
1364 return status;
1367 /* send it on its way */
1368 status = p->conn->transport.send_request(p->conn, &blob, false);
1369 if (!NT_STATUS_IS_OK(status)) {
1370 return status;
1373 return NT_STATUS_OK;
1378 process a fragment received from the transport layer during a
1379 request
1381 This function frees the data
1383 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1384 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1386 struct rpc_request *req;
1387 unsigned int length;
1388 NTSTATUS status = NT_STATUS_OK;
1391 if this is an authenticated connection then parse and check
1392 the auth info. We have to do this before finding the
1393 matching packet, as the request structure might have been
1394 removed due to a timeout, but if it has been we still need
1395 to run the auth routines so that we don't get the sign/seal
1396 info out of step with the server
1398 if (c->security_state.auth_info && c->security_state.generic_state &&
1399 pkt->ptype == DCERPC_PKT_RESPONSE) {
1400 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1403 /* find the matching request */
1404 for (req=c->pending;req;req=req->next) {
1405 if (pkt->call_id == req->call_id) break;
1408 #if 0
1409 /* useful for testing certain vendors RPC servers */
1410 if (req == NULL && c->pending && pkt->call_id == 0) {
1411 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1412 req = c->pending;
1414 #endif
1416 if (req == NULL) {
1417 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1418 data_blob_free(raw_packet);
1419 return;
1422 talloc_steal(req, raw_packet->data);
1424 if (req->recv_handler != NULL) {
1425 dcerpc_req_dequeue(req);
1426 req->state = RPC_REQUEST_DONE;
1429 * We have to look at shipping further requests before calling
1430 * the async function, that one might close the pipe
1432 dcerpc_schedule_io_trigger(c);
1434 req->recv_handler(req, raw_packet, pkt);
1435 return;
1438 if (pkt->ptype == DCERPC_PKT_FAULT) {
1439 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1440 req->fault_code = pkt->u.fault.status;
1441 req->status = NT_STATUS_NET_WRITE_FAULT;
1442 goto req_done;
1445 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1446 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1447 (int)pkt->ptype));
1448 req->fault_code = DCERPC_FAULT_OTHER;
1449 req->status = NT_STATUS_NET_WRITE_FAULT;
1450 goto req_done;
1453 /* now check the status from the auth routines, and if it failed then fail
1454 this request accordingly */
1455 if (!NT_STATUS_IS_OK(status)) {
1456 req->status = status;
1457 goto req_done;
1460 length = pkt->u.response.stub_and_verifier.length;
1462 if (length > 0) {
1463 req->payload.data = talloc_realloc(req,
1464 req->payload.data,
1465 uint8_t,
1466 req->payload.length + length);
1467 if (!req->payload.data) {
1468 req->status = NT_STATUS_NO_MEMORY;
1469 goto req_done;
1471 memcpy(req->payload.data+req->payload.length,
1472 pkt->u.response.stub_and_verifier.data, length);
1473 req->payload.length += length;
1476 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1477 c->transport.send_read(c);
1478 return;
1481 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1482 req->flags |= DCERPC_PULL_BIGENDIAN;
1483 } else {
1484 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1488 req_done:
1489 /* we've got the full payload */
1490 dcerpc_req_dequeue(req);
1491 req->state = RPC_REQUEST_DONE;
1494 * We have to look at shipping further requests before calling
1495 * the async function, that one might close the pipe
1497 dcerpc_schedule_io_trigger(c);
1499 if (req->async.callback) {
1500 req->async.callback(req);
1505 perform the send side of a async dcerpc request
1507 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1508 struct dcerpc_pipe *p,
1509 const struct GUID *object,
1510 uint16_t opnum,
1511 DATA_BLOB *stub_data)
1513 struct rpc_request *req;
1515 p->conn->transport.recv_data = dcerpc_recv_data;
1517 req = talloc_zero(mem_ctx, struct rpc_request);
1518 if (req == NULL) {
1519 return NULL;
1522 req->p = p;
1523 req->call_id = next_call_id(p->conn);
1524 req->state = RPC_REQUEST_QUEUED;
1526 if (object != NULL) {
1527 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1528 if (req->object == NULL) {
1529 talloc_free(req);
1530 return NULL;
1534 req->opnum = opnum;
1535 req->request_data.length = stub_data->length;
1536 req->request_data.data = stub_data->data;
1538 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1539 talloc_set_destructor(req, dcerpc_req_dequeue);
1541 dcerpc_schedule_io_trigger(p->conn);
1543 if (p->request_timeout) {
1544 tevent_add_timer(dcerpc_event_context(p), req,
1545 timeval_current_ofs(p->request_timeout, 0),
1546 dcerpc_timeout_handler, req);
1549 return req;
1553 Send a request using the transport
1556 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1558 struct rpc_request *req;
1559 struct dcerpc_pipe *p;
1560 DATA_BLOB *stub_data;
1561 struct ncacn_packet pkt;
1562 DATA_BLOB blob;
1563 uint32_t remaining, chunk_size;
1564 bool first_packet = true;
1565 size_t sig_size = 0;
1566 bool need_async = false;
1567 bool can_async = true;
1569 req = c->request_queue;
1570 if (req == NULL) {
1571 return;
1574 p = req->p;
1575 stub_data = &req->request_data;
1577 if (c->pending) {
1578 need_async = true;
1581 if (c->security_state.auth_info &&
1582 c->security_state.generic_state)
1584 struct gensec_security *gensec = c->security_state.generic_state;
1586 switch (c->security_state.auth_info->auth_level) {
1587 case DCERPC_AUTH_LEVEL_PRIVACY:
1588 case DCERPC_AUTH_LEVEL_INTEGRITY:
1589 can_async = gensec_have_feature(gensec,
1590 GENSEC_FEATURE_ASYNC_REPLIES);
1591 break;
1592 case DCERPC_AUTH_LEVEL_CONNECT:
1593 case DCERPC_AUTH_LEVEL_NONE:
1594 can_async = true;
1595 break;
1596 default:
1597 can_async = false;
1598 break;
1602 if (need_async && !can_async) {
1603 req->wait_for_sync = true;
1604 return;
1607 DLIST_REMOVE(c->request_queue, req);
1608 DLIST_ADD(c->pending, req);
1609 req->state = RPC_REQUEST_PENDING;
1611 init_ncacn_hdr(p->conn, &pkt);
1613 remaining = stub_data->length;
1615 /* we can write a full max_recv_frag size, minus the dcerpc
1616 request header size */
1617 chunk_size = p->conn->srv_max_recv_frag;
1618 chunk_size -= DCERPC_REQUEST_LENGTH;
1619 if (c->security_state.auth_info &&
1620 c->security_state.generic_state) {
1621 sig_size = gensec_sig_size(c->security_state.generic_state,
1622 p->conn->srv_max_recv_frag);
1623 if (sig_size) {
1624 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1625 chunk_size -= sig_size;
1628 chunk_size -= (chunk_size % 16);
1630 pkt.ptype = DCERPC_PKT_REQUEST;
1631 pkt.call_id = req->call_id;
1632 pkt.auth_length = 0;
1633 pkt.pfc_flags = 0;
1634 pkt.u.request.alloc_hint = remaining;
1635 pkt.u.request.context_id = p->context_id;
1636 pkt.u.request.opnum = req->opnum;
1638 if (req->object) {
1639 pkt.u.request.object.object = *req->object;
1640 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1641 chunk_size -= ndr_size_GUID(req->object,0);
1644 /* we send a series of pdus without waiting for a reply */
1645 while (remaining > 0 || first_packet) {
1646 uint32_t chunk = MIN(chunk_size, remaining);
1647 bool last_frag = false;
1648 bool do_trans = false;
1650 first_packet = false;
1651 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1653 if (remaining == stub_data->length) {
1654 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1656 if (chunk == remaining) {
1657 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1658 last_frag = true;
1661 pkt.u.request.stub_and_verifier.data = stub_data->data +
1662 (stub_data->length - remaining);
1663 pkt.u.request.stub_and_verifier.length = chunk;
1665 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1666 if (!NT_STATUS_IS_OK(req->status)) {
1667 req->state = RPC_REQUEST_DONE;
1668 DLIST_REMOVE(p->conn->pending, req);
1669 return;
1672 if (last_frag && !need_async) {
1673 do_trans = true;
1676 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1677 if (!NT_STATUS_IS_OK(req->status)) {
1678 req->state = RPC_REQUEST_DONE;
1679 DLIST_REMOVE(p->conn->pending, req);
1680 return;
1683 if (last_frag && !do_trans) {
1684 req->status = p->conn->transport.send_read(p->conn);
1685 if (!NT_STATUS_IS_OK(req->status)) {
1686 req->state = RPC_REQUEST_DONE;
1687 DLIST_REMOVE(p->conn->pending, req);
1688 return;
1692 remaining -= chunk;
1696 static void dcerpc_io_trigger(struct tevent_context *ctx,
1697 struct tevent_immediate *im,
1698 void *private_data)
1700 struct dcecli_connection *c =
1701 talloc_get_type_abort(private_data,
1702 struct dcecli_connection);
1704 c->io_trigger_pending = false;
1706 dcerpc_schedule_io_trigger(c);
1708 dcerpc_ship_next_request(c);
1711 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1713 if (c->dead) {
1714 return;
1717 if (c->request_queue == NULL) {
1718 return;
1721 if (c->request_queue->wait_for_sync && c->pending) {
1722 return;
1725 if (c->io_trigger_pending) {
1726 return;
1729 c->io_trigger_pending = true;
1731 tevent_schedule_immediate(c->io_trigger,
1732 c->event_ctx,
1733 dcerpc_io_trigger,
1738 return the event context for a dcerpc pipe
1739 used by callers who wish to operate asynchronously
1741 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1743 return p->conn->event_ctx;
1749 perform the receive side of a async dcerpc request
1751 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1752 TALLOC_CTX *mem_ctx,
1753 DATA_BLOB *stub_data)
1755 NTSTATUS status;
1757 while (req->state != RPC_REQUEST_DONE) {
1758 struct tevent_context *ctx = dcerpc_event_context(req->p);
1759 if (tevent_loop_once(ctx) != 0) {
1760 return NT_STATUS_CONNECTION_DISCONNECTED;
1763 *stub_data = req->payload;
1764 status = req->status;
1765 if (stub_data->data) {
1766 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1768 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1769 req->p->last_fault_code = req->fault_code;
1771 talloc_unlink(talloc_parent(req), req);
1772 return status;
1776 this is a paranoid NDR validator. For every packet we push onto the wire
1777 we pull it back again, then push it again. Then we compare the raw NDR data
1778 for that to the NDR we initially generated. If they don't match then we know
1779 we must have a bug in either the pull or push side of our code
1781 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1782 TALLOC_CTX *mem_ctx,
1783 DATA_BLOB blob,
1784 size_t struct_size,
1785 ndr_push_flags_fn_t ndr_push,
1786 ndr_pull_flags_fn_t ndr_pull)
1788 void *st;
1789 struct ndr_pull *pull;
1790 struct ndr_push *push;
1791 DATA_BLOB blob2;
1792 enum ndr_err_code ndr_err;
1794 st = talloc_size(mem_ctx, struct_size);
1795 if (!st) {
1796 return NT_STATUS_NO_MEMORY;
1799 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1800 if (!pull) {
1801 return NT_STATUS_NO_MEMORY;
1803 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1805 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1806 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1809 if (c->flags & DCERPC_NDR64) {
1810 pull->flags |= LIBNDR_FLAG_NDR64;
1813 ndr_err = ndr_pull(pull, NDR_IN, st);
1814 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1815 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1816 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1817 "failed input validation pull - %s",
1818 nt_errstr(status));
1819 return ndr_map_error2ntstatus(ndr_err);
1822 push = ndr_push_init_ctx(mem_ctx);
1823 if (!push) {
1824 return NT_STATUS_NO_MEMORY;
1827 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1828 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1831 if (c->flags & DCERPC_NDR64) {
1832 push->flags |= LIBNDR_FLAG_NDR64;
1835 ndr_err = ndr_push(push, NDR_IN, st);
1836 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1837 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1838 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1839 "failed input validation push - %s",
1840 nt_errstr(status));
1841 return ndr_map_error2ntstatus(ndr_err);
1844 blob2 = ndr_push_blob(push);
1846 if (data_blob_cmp(&blob, &blob2) != 0) {
1847 DEBUG(3,("original:\n"));
1848 dump_data(3, blob.data, blob.length);
1849 DEBUG(3,("secondary:\n"));
1850 dump_data(3, blob2.data, blob2.length);
1851 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1852 "failed input validation blobs doesn't match");
1853 return ndr_map_error2ntstatus(ndr_err);
1856 return NT_STATUS_OK;
1860 this is a paranoid NDR input validator. For every packet we pull
1861 from the wire we push it back again then pull and push it
1862 again. Then we compare the raw NDR data for that to the NDR we
1863 initially generated. If they don't match then we know we must have a
1864 bug in either the pull or push side of our code
1866 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1867 struct ndr_pull *pull_in,
1868 void *struct_ptr,
1869 size_t struct_size,
1870 ndr_push_flags_fn_t ndr_push,
1871 ndr_pull_flags_fn_t ndr_pull,
1872 ndr_print_function_t ndr_print)
1874 void *st;
1875 struct ndr_pull *pull;
1876 struct ndr_push *push;
1877 DATA_BLOB blob, blob2;
1878 TALLOC_CTX *mem_ctx = pull_in;
1879 char *s1, *s2;
1880 enum ndr_err_code ndr_err;
1882 st = talloc_size(mem_ctx, struct_size);
1883 if (!st) {
1884 return NT_STATUS_NO_MEMORY;
1886 memcpy(st, struct_ptr, struct_size);
1888 push = ndr_push_init_ctx(mem_ctx);
1889 if (!push) {
1890 return NT_STATUS_NO_MEMORY;
1893 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1894 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1895 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1896 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1897 "failed output validation push - %s",
1898 nt_errstr(status));
1899 return ndr_map_error2ntstatus(ndr_err);
1902 blob = ndr_push_blob(push);
1904 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1905 if (!pull) {
1906 return NT_STATUS_NO_MEMORY;
1909 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1910 ndr_err = ndr_pull(pull, NDR_OUT, st);
1911 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1912 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1913 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1914 "failed output validation pull - %s",
1915 nt_errstr(status));
1916 return ndr_map_error2ntstatus(ndr_err);
1919 push = ndr_push_init_ctx(mem_ctx);
1920 if (!push) {
1921 return NT_STATUS_NO_MEMORY;
1924 ndr_err = ndr_push(push, NDR_OUT, st);
1925 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1926 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1927 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1928 "failed output validation push2 - %s",
1929 nt_errstr(status));
1930 return ndr_map_error2ntstatus(ndr_err);
1933 blob2 = ndr_push_blob(push);
1935 if (data_blob_cmp(&blob, &blob2) != 0) {
1936 DEBUG(3,("original:\n"));
1937 dump_data(3, blob.data, blob.length);
1938 DEBUG(3,("secondary:\n"));
1939 dump_data(3, blob2.data, blob2.length);
1940 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1941 "failed output validation blobs doesn't match");
1942 return ndr_map_error2ntstatus(ndr_err);
1945 /* this checks the printed forms of the two structures, which effectively
1946 tests all of the value() attributes */
1947 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1948 NDR_OUT, struct_ptr);
1949 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1950 NDR_OUT, st);
1951 if (strcmp(s1, s2) != 0) {
1952 #if 1
1953 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1954 #else
1955 /* this is sometimes useful */
1956 printf("VALIDATE ERROR\n");
1957 file_save("wire.dat", s1, strlen(s1));
1958 file_save("gen.dat", s2, strlen(s2));
1959 system("diff -u wire.dat gen.dat");
1960 #endif
1961 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1962 "failed output validation strings doesn't match");
1963 return ndr_map_error2ntstatus(ndr_err);
1966 return NT_STATUS_OK;
1970 a useful function for retrieving the server name we connected to
1972 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1974 if (!p->conn->transport.target_hostname) {
1975 if (!p->conn->transport.peer_name) {
1976 return "";
1978 return p->conn->transport.peer_name(p->conn);
1980 return p->conn->transport.target_hostname(p->conn);
1985 get the dcerpc auth_level for a open connection
1987 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1989 uint8_t auth_level;
1991 if (c->flags & DCERPC_SEAL) {
1992 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1993 } else if (c->flags & DCERPC_SIGN) {
1994 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1995 } else if (c->flags & DCERPC_CONNECT) {
1996 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1997 } else {
1998 auth_level = DCERPC_AUTH_LEVEL_NONE;
2000 return auth_level;
2003 struct dcerpc_alter_context_state {
2004 struct tevent_context *ev;
2005 struct dcerpc_pipe *p;
2008 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2009 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2010 DATA_BLOB *raw_packet,
2011 struct ncacn_packet *pkt);
2013 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2014 struct tevent_context *ev,
2015 struct dcerpc_pipe *p,
2016 const struct ndr_syntax_id *syntax,
2017 const struct ndr_syntax_id *transfer_syntax)
2019 struct tevent_req *req;
2020 struct dcerpc_alter_context_state *state;
2021 struct ncacn_packet pkt;
2022 DATA_BLOB blob;
2023 NTSTATUS status;
2024 struct rpc_request *subreq;
2026 req = tevent_req_create(mem_ctx, &state,
2027 struct dcerpc_alter_context_state);
2028 if (req == NULL) {
2029 return NULL;
2032 state->ev = ev;
2033 state->p = p;
2035 p->syntax = *syntax;
2036 p->transfer_syntax = *transfer_syntax;
2038 init_ncacn_hdr(p->conn, &pkt);
2040 pkt.ptype = DCERPC_PKT_ALTER;
2041 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2042 pkt.call_id = p->conn->call_id;
2043 pkt.auth_length = 0;
2045 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
2046 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2049 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
2050 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
2053 pkt.u.alter.max_xmit_frag = 5840;
2054 pkt.u.alter.max_recv_frag = 5840;
2055 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
2056 pkt.u.alter.num_contexts = 1;
2057 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2058 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2059 return tevent_req_post(req, ev);
2061 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2062 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2063 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2064 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2065 pkt.u.alter.auth_info = data_blob(NULL, 0);
2067 /* construct the NDR form of the packet */
2068 status = ncacn_push_auth(&blob, state, &pkt,
2069 p->conn->security_state.auth_info);
2070 if (tevent_req_nterror(req, status)) {
2071 return tevent_req_post(req, ev);
2074 p->conn->transport.recv_data = dcerpc_recv_data;
2077 * we allocate a dcerpc_request so we can be in the same
2078 * request queue as normal requests
2080 subreq = talloc_zero(state, struct rpc_request);
2081 if (tevent_req_nomem(subreq, req)) {
2082 return tevent_req_post(req, ev);
2085 subreq->state = RPC_REQUEST_PENDING;
2086 subreq->call_id = pkt.call_id;
2087 subreq->async.private_data = req;
2088 subreq->async.callback = dcerpc_alter_context_fail_handler;
2089 subreq->p = p;
2090 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2091 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2092 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2094 status = p->conn->transport.send_request(p->conn, &blob, true);
2095 if (tevent_req_nterror(req, status)) {
2096 return tevent_req_post(req, ev);
2099 tevent_add_timer(ev, subreq,
2100 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2101 dcerpc_timeout_handler, subreq);
2103 return req;
2106 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2108 struct tevent_req *req =
2109 talloc_get_type_abort(subreq->async.private_data,
2110 struct tevent_req);
2111 struct dcerpc_alter_context_state *state =
2112 tevent_req_data(req,
2113 struct dcerpc_alter_context_state);
2114 NTSTATUS status = subreq->status;
2116 TALLOC_FREE(subreq);
2119 * We trigger the callback in the next event run
2120 * because the code in this file might trigger
2121 * multiple request callbacks from within a single
2122 * while loop.
2124 * In order to avoid segfaults from within
2125 * dcerpc_connection_dead() we call
2126 * tevent_req_defer_callback().
2128 tevent_req_defer_callback(req, state->ev);
2130 tevent_req_nterror(req, status);
2133 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2134 DATA_BLOB *raw_packet,
2135 struct ncacn_packet *pkt)
2137 struct tevent_req *req =
2138 talloc_get_type_abort(subreq->async.private_data,
2139 struct tevent_req);
2140 struct dcerpc_alter_context_state *state =
2141 tevent_req_data(req,
2142 struct dcerpc_alter_context_state);
2143 struct dcecli_connection *conn = state->p->conn;
2144 NTSTATUS status;
2147 * Note that pkt is allocated under raw_packet->data,
2148 * while raw_packet->data is a child of subreq.
2150 talloc_steal(state, raw_packet->data);
2151 TALLOC_FREE(subreq);
2154 * We trigger the callback in the next event run
2155 * because the code in this file might trigger
2156 * multiple request callbacks from within a single
2157 * while loop.
2159 * In order to avoid segfaults from within
2160 * dcerpc_connection_dead() we call
2161 * tevent_req_defer_callback().
2163 tevent_req_defer_callback(req, state->ev);
2165 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2166 pkt->u.alter_resp.num_results == 1 &&
2167 pkt->u.alter_resp.ctx_list[0].result != 0) {
2168 status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason);
2169 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2170 pkt->u.alter_resp.ctx_list[0].reason,
2171 nt_errstr(status)));
2172 tevent_req_nterror(req, status);
2173 return;
2176 if (pkt->ptype == DCERPC_PKT_FAULT) {
2177 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2178 dcerpc_errstr(state, pkt->u.fault.status)));
2179 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2180 state->p->last_fault_code = pkt->u.fault.status;
2181 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2182 } else {
2183 state->p->last_fault_code = pkt->u.fault.status;
2184 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2186 return;
2189 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2190 pkt->u.alter_resp.num_results == 0 ||
2191 pkt->u.alter_resp.ctx_list[0].result != 0) {
2192 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2193 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2194 return;
2197 /* the alter_resp might contain a reply set of credentials */
2198 if (conn->security_state.auth_info &&
2199 pkt->u.alter_resp.auth_info.length) {
2200 uint32_t auth_length;
2202 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2203 conn->security_state.auth_info, &auth_length, true);
2204 if (tevent_req_nterror(req, status)) {
2205 return;
2209 tevent_req_done(req);
2212 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2214 return tevent_req_simple_recv_ntstatus(req);
2218 send a dcerpc alter_context request
2220 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2221 TALLOC_CTX *mem_ctx,
2222 const struct ndr_syntax_id *syntax,
2223 const struct ndr_syntax_id *transfer_syntax)
2225 struct tevent_req *subreq;
2226 struct tevent_context *ev = p->conn->event_ctx;
2227 bool ok;
2229 /* TODO: create a new event context here */
2231 subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx,
2232 p, syntax, transfer_syntax);
2233 if (subreq == NULL) {
2234 return NT_STATUS_NO_MEMORY;
2237 ok = tevent_req_poll(subreq, ev);
2238 if (!ok) {
2239 NTSTATUS status;
2240 status = map_nt_error_from_unix_common(errno);
2241 return status;
2244 return dcerpc_alter_context_recv(subreq);