s4:librpc: factor out xxx_shutdown_pipe() to dcerpc_shutdown_pipe()
[Samba.git] / source4 / librpc / rpc / dcerpc.c
bloba55f3d646845dabbfdb1aff5ae619cd908a2f805
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"
34 #include "lib/tsocket/tsocket.h"
37 enum rpc_request_state {
38 RPC_REQUEST_QUEUED,
39 RPC_REQUEST_PENDING,
40 RPC_REQUEST_DONE
44 handle for an async dcerpc request
46 struct rpc_request {
47 struct rpc_request *next, *prev;
48 struct dcerpc_pipe *p;
49 NTSTATUS status;
50 uint32_t call_id;
51 enum rpc_request_state state;
52 DATA_BLOB payload;
53 uint32_t flags;
54 uint32_t fault_code;
56 /* this is used to distinguish bind and alter_context requests
57 from normal requests */
58 void (*recv_handler)(struct rpc_request *conn,
59 DATA_BLOB *blob, struct ncacn_packet *pkt);
61 const struct GUID *object;
62 uint16_t opnum;
63 DATA_BLOB request_data;
64 bool ignore_timeout;
65 bool wait_for_sync;
67 struct {
68 void (*callback)(struct rpc_request *);
69 void *private_data;
70 } async;
73 _PUBLIC_ NTSTATUS dcerpc_init(void)
75 return gensec_init();
78 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
79 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
81 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
82 struct dcerpc_pipe *p,
83 const struct GUID *object,
84 uint16_t opnum,
85 DATA_BLOB *stub_data);
86 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
87 TALLOC_CTX *mem_ctx,
88 DATA_BLOB *stub_data);
89 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
90 TALLOC_CTX *mem_ctx,
91 DATA_BLOB blob,
92 size_t struct_size,
93 ndr_push_flags_fn_t ndr_push,
94 ndr_pull_flags_fn_t ndr_pull);
95 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
96 struct ndr_pull *pull_in,
97 void *struct_ptr,
98 size_t struct_size,
99 ndr_push_flags_fn_t ndr_push,
100 ndr_pull_flags_fn_t ndr_pull,
101 ndr_print_function_t ndr_print);
103 /* destroy a dcerpc connection */
104 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
106 if (conn->dead) {
107 conn->free_skipped = true;
108 return -1;
110 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
111 return 0;
115 /* initialise a dcerpc connection.
116 the event context is optional
118 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
119 struct tevent_context *ev)
121 struct dcecli_connection *c;
123 c = talloc_zero(mem_ctx, struct dcecli_connection);
124 if (!c) {
125 return NULL;
128 c->event_ctx = ev;
130 if (c->event_ctx == NULL) {
131 talloc_free(c);
132 return NULL;
135 c->call_id = 1;
136 c->security_state.auth_info = NULL;
137 c->security_state.session_key = dcerpc_generic_session_key;
138 c->security_state.generic_state = NULL;
139 c->binding_string = NULL;
140 c->flags = 0;
142 * Windows uses 5840 for ncacn_ip_tcp,
143 * so we also use it (for every transport)
144 * by default. But we give the transport
145 * the chance to overwrite it.
147 c->srv_max_xmit_frag = 5840;
148 c->srv_max_recv_frag = 5840;
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 TALLOC_FREE(ndr);
717 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
718 return ndr_map_error2ntstatus(ndr_err);
721 if (pkt->frag_length != blob->length) {
722 return NT_STATUS_RPC_PROTOCOL_ERROR;
725 return NT_STATUS_OK;
729 parse the authentication information on a dcerpc response packet
731 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
732 DATA_BLOB *raw_packet,
733 struct ncacn_packet *pkt)
735 NTSTATUS status;
736 struct dcerpc_auth auth;
737 uint32_t auth_length;
739 if (!c->security_state.auth_info ||
740 !c->security_state.generic_state) {
741 return NT_STATUS_OK;
744 switch (c->security_state.auth_info->auth_level) {
745 case DCERPC_AUTH_LEVEL_PRIVACY:
746 case DCERPC_AUTH_LEVEL_INTEGRITY:
747 break;
749 case DCERPC_AUTH_LEVEL_CONNECT:
750 if (pkt->auth_length != 0) {
751 break;
753 return NT_STATUS_OK;
754 case DCERPC_AUTH_LEVEL_NONE:
755 if (pkt->auth_length != 0) {
756 return NT_STATUS_INVALID_NETWORK_RESPONSE;
758 return NT_STATUS_OK;
760 default:
761 return NT_STATUS_INVALID_LEVEL;
764 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
765 &pkt->u.response.stub_and_verifier,
766 &auth, &auth_length, false);
767 NT_STATUS_NOT_OK_RETURN(status);
769 pkt->u.response.stub_and_verifier.length -= auth_length;
771 /* check signature or unseal the packet */
772 switch (c->security_state.auth_info->auth_level) {
773 case DCERPC_AUTH_LEVEL_PRIVACY:
774 status = gensec_unseal_packet(c->security_state.generic_state,
775 raw_packet->data + DCERPC_REQUEST_LENGTH,
776 pkt->u.response.stub_and_verifier.length,
777 raw_packet->data,
778 raw_packet->length - auth.credentials.length,
779 &auth.credentials);
780 memcpy(pkt->u.response.stub_and_verifier.data,
781 raw_packet->data + DCERPC_REQUEST_LENGTH,
782 pkt->u.response.stub_and_verifier.length);
783 break;
785 case DCERPC_AUTH_LEVEL_INTEGRITY:
786 status = gensec_check_packet(c->security_state.generic_state,
787 pkt->u.response.stub_and_verifier.data,
788 pkt->u.response.stub_and_verifier.length,
789 raw_packet->data,
790 raw_packet->length - auth.credentials.length,
791 &auth.credentials);
792 break;
794 case DCERPC_AUTH_LEVEL_CONNECT:
795 /* for now we ignore possible signatures here */
796 status = NT_STATUS_OK;
797 break;
799 default:
800 status = NT_STATUS_INVALID_LEVEL;
801 break;
804 /* remove the indicated amount of padding */
805 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
806 return NT_STATUS_INFO_LENGTH_MISMATCH;
808 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
810 return status;
815 push a dcerpc request packet into a blob, possibly signing it.
817 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
818 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
819 size_t sig_size,
820 struct ncacn_packet *pkt)
822 NTSTATUS status;
823 struct ndr_push *ndr;
824 DATA_BLOB creds2;
825 size_t payload_length;
826 enum ndr_err_code ndr_err;
827 size_t hdr_size = DCERPC_REQUEST_LENGTH;
829 /* non-signed packets are simpler */
830 if (sig_size == 0) {
831 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
834 switch (c->security_state.auth_info->auth_level) {
835 case DCERPC_AUTH_LEVEL_PRIVACY:
836 case DCERPC_AUTH_LEVEL_INTEGRITY:
837 break;
839 case DCERPC_AUTH_LEVEL_CONNECT:
840 /* TODO: let the gensec mech decide if it wants to generate a signature */
841 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
843 case DCERPC_AUTH_LEVEL_NONE:
844 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
846 default:
847 return NT_STATUS_INVALID_LEVEL;
850 ndr = ndr_push_init_ctx(mem_ctx);
851 if (!ndr) {
852 return NT_STATUS_NO_MEMORY;
855 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
856 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
859 if (c->flags & DCERPC_NDR64) {
860 ndr->flags |= LIBNDR_FLAG_NDR64;
863 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
864 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
865 hdr_size += 16;
868 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
869 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
870 return ndr_map_error2ntstatus(ndr_err);
873 /* pad to 16 byte multiple in the payload portion of the
874 packet. This matches what w2k3 does. Note that we can't use
875 ndr_push_align() as that is relative to the start of the
876 whole packet, whereas w2k8 wants it relative to the start
877 of the stub */
878 c->security_state.auth_info->auth_pad_length =
879 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
880 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
881 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
882 return ndr_map_error2ntstatus(ndr_err);
885 payload_length = pkt->u.request.stub_and_verifier.length +
886 c->security_state.auth_info->auth_pad_length;
888 /* we start without signature, it will appended later */
889 c->security_state.auth_info->credentials = data_blob(NULL,0);
891 /* add the auth verifier */
892 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
893 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
894 return ndr_map_error2ntstatus(ndr_err);
897 /* extract the whole packet as a blob */
898 *blob = ndr_push_blob(ndr);
901 * Setup the frag and auth length in the packet buffer.
902 * This is needed if the GENSEC mech does AEAD signing
903 * of the packet headers. The signature itself will be
904 * appended later.
906 dcerpc_set_frag_length(blob, blob->length + sig_size);
907 dcerpc_set_auth_length(blob, sig_size);
909 /* sign or seal the packet */
910 switch (c->security_state.auth_info->auth_level) {
911 case DCERPC_AUTH_LEVEL_PRIVACY:
912 status = gensec_seal_packet(c->security_state.generic_state,
913 mem_ctx,
914 blob->data + hdr_size,
915 payload_length,
916 blob->data,
917 blob->length,
918 &creds2);
919 if (!NT_STATUS_IS_OK(status)) {
920 return status;
922 break;
924 case DCERPC_AUTH_LEVEL_INTEGRITY:
925 status = gensec_sign_packet(c->security_state.generic_state,
926 mem_ctx,
927 blob->data + hdr_size,
928 payload_length,
929 blob->data,
930 blob->length,
931 &creds2);
932 if (!NT_STATUS_IS_OK(status)) {
933 return status;
935 break;
937 default:
938 status = NT_STATUS_INVALID_LEVEL;
939 break;
942 if (creds2.length != sig_size) {
943 /* this means the sig_size estimate for the signature
944 was incorrect. We have to correct the packet
945 sizes. That means we could go over the max fragment
946 length */
947 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
948 (unsigned) creds2.length,
949 (unsigned) sig_size,
950 (unsigned) c->security_state.auth_info->auth_pad_length,
951 (unsigned) pkt->u.request.stub_and_verifier.length));
952 dcerpc_set_frag_length(blob, blob->length + creds2.length);
953 dcerpc_set_auth_length(blob, creds2.length);
956 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
957 return NT_STATUS_NO_MEMORY;
960 return NT_STATUS_OK;
965 fill in the fixed values in a dcerpc header
967 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
969 pkt->rpc_vers = 5;
970 pkt->rpc_vers_minor = 0;
971 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
972 pkt->drep[0] = 0;
973 } else {
974 pkt->drep[0] = DCERPC_DREP_LE;
976 pkt->drep[1] = 0;
977 pkt->drep[2] = 0;
978 pkt->drep[3] = 0;
982 map a bind nak reason to a NTSTATUS
984 static NTSTATUS dcerpc_map_reason(uint16_t reason)
986 switch (reason) {
987 case DCERPC_BIND_REASON_ASYNTAX:
988 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
989 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
990 return NT_STATUS_INVALID_PARAMETER;
992 return NT_STATUS_UNSUCCESSFUL;
996 remove requests from the pending or queued queues
998 static int dcerpc_req_dequeue(struct rpc_request *req)
1000 switch (req->state) {
1001 case RPC_REQUEST_QUEUED:
1002 DLIST_REMOVE(req->p->conn->request_queue, req);
1003 break;
1004 case RPC_REQUEST_PENDING:
1005 DLIST_REMOVE(req->p->conn->pending, req);
1006 break;
1007 case RPC_REQUEST_DONE:
1008 break;
1010 return 0;
1014 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
1016 mark the dcerpc connection dead. All outstanding requests get an error
1018 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1020 if (conn->dead) return;
1022 conn->dead = true;
1024 TALLOC_FREE(conn->io_trigger);
1025 conn->io_trigger_pending = false;
1027 conn->transport.recv_data = NULL;
1029 dcerpc_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->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1166 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1169 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1170 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
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;
1300 * DCE-RPC 1.1 (c706) specifies
1301 * CONST_MUST_RCV_FRAG_SIZE as 1432
1303 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1304 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1305 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1306 return;
1308 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1309 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1310 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1311 return;
1313 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1314 pkt->u.bind_ack.max_xmit_frag);
1315 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1316 pkt->u.bind_ack.max_recv_frag);
1318 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1319 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1320 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1323 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1324 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1325 conn->flags |= DCERPC_HEADER_SIGNING;
1328 /* the bind_ack might contain a reply set of credentials */
1329 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1330 uint32_t auth_length;
1332 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1333 conn->security_state.auth_info, &auth_length, true);
1334 if (tevent_req_nterror(req, status)) {
1335 return;
1339 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1341 tevent_req_done(req);
1344 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1346 return tevent_req_simple_recv_ntstatus(req);
1350 perform a continued bind (and auth3)
1352 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1353 TALLOC_CTX *mem_ctx)
1355 struct ncacn_packet pkt;
1356 NTSTATUS status;
1357 DATA_BLOB blob;
1359 init_ncacn_hdr(p->conn, &pkt);
1361 pkt.ptype = DCERPC_PKT_AUTH3;
1362 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1363 pkt.call_id = next_call_id(p->conn);
1364 pkt.auth_length = 0;
1365 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1367 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1368 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1371 /* construct the NDR form of the packet */
1372 status = ncacn_push_auth(&blob, mem_ctx,
1373 &pkt,
1374 p->conn->security_state.auth_info);
1375 if (!NT_STATUS_IS_OK(status)) {
1376 return status;
1379 /* send it on its way */
1380 status = p->conn->transport.send_request(p->conn, &blob, false);
1381 if (!NT_STATUS_IS_OK(status)) {
1382 return status;
1385 return NT_STATUS_OK;
1390 process a fragment received from the transport layer during a
1391 request
1393 This function frees the data
1395 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1396 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1398 struct rpc_request *req;
1399 unsigned int length;
1400 NTSTATUS status = NT_STATUS_OK;
1403 if this is an authenticated connection then parse and check
1404 the auth info. We have to do this before finding the
1405 matching packet, as the request structure might have been
1406 removed due to a timeout, but if it has been we still need
1407 to run the auth routines so that we don't get the sign/seal
1408 info out of step with the server
1410 if (c->security_state.auth_info && c->security_state.generic_state &&
1411 pkt->ptype == DCERPC_PKT_RESPONSE) {
1412 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1415 /* find the matching request */
1416 for (req=c->pending;req;req=req->next) {
1417 if (pkt->call_id == req->call_id) break;
1420 #if 0
1421 /* useful for testing certain vendors RPC servers */
1422 if (req == NULL && c->pending && pkt->call_id == 0) {
1423 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1424 req = c->pending;
1426 #endif
1428 if (req == NULL) {
1429 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1430 data_blob_free(raw_packet);
1431 return;
1434 talloc_steal(req, raw_packet->data);
1436 if (req->recv_handler != NULL) {
1437 dcerpc_req_dequeue(req);
1438 req->state = RPC_REQUEST_DONE;
1441 * We have to look at shipping further requests before calling
1442 * the async function, that one might close the pipe
1444 dcerpc_schedule_io_trigger(c);
1446 req->recv_handler(req, raw_packet, pkt);
1447 return;
1450 if (pkt->ptype == DCERPC_PKT_FAULT) {
1451 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1452 req->fault_code = pkt->u.fault.status;
1453 req->status = NT_STATUS_NET_WRITE_FAULT;
1454 goto req_done;
1457 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1458 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1459 (int)pkt->ptype));
1460 req->fault_code = DCERPC_FAULT_OTHER;
1461 req->status = NT_STATUS_NET_WRITE_FAULT;
1462 goto req_done;
1465 /* now check the status from the auth routines, and if it failed then fail
1466 this request accordingly */
1467 if (!NT_STATUS_IS_OK(status)) {
1468 req->status = status;
1469 goto req_done;
1472 length = pkt->u.response.stub_and_verifier.length;
1474 if (length > 0) {
1475 req->payload.data = talloc_realloc(req,
1476 req->payload.data,
1477 uint8_t,
1478 req->payload.length + length);
1479 if (!req->payload.data) {
1480 req->status = NT_STATUS_NO_MEMORY;
1481 goto req_done;
1483 memcpy(req->payload.data+req->payload.length,
1484 pkt->u.response.stub_and_verifier.data, length);
1485 req->payload.length += length;
1488 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1489 data_blob_free(raw_packet);
1490 c->transport.send_read(c);
1491 return;
1494 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1495 req->flags |= DCERPC_PULL_BIGENDIAN;
1496 } else {
1497 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1500 req_done:
1501 data_blob_free(raw_packet);
1503 /* we've got the full payload */
1504 dcerpc_req_dequeue(req);
1505 req->state = RPC_REQUEST_DONE;
1508 * We have to look at shipping further requests before calling
1509 * the async function, that one might close the pipe
1511 dcerpc_schedule_io_trigger(c);
1513 if (req->async.callback) {
1514 req->async.callback(req);
1519 perform the send side of a async dcerpc request
1521 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1522 struct dcerpc_pipe *p,
1523 const struct GUID *object,
1524 uint16_t opnum,
1525 DATA_BLOB *stub_data)
1527 struct rpc_request *req;
1529 p->conn->transport.recv_data = dcerpc_recv_data;
1531 req = talloc_zero(mem_ctx, struct rpc_request);
1532 if (req == NULL) {
1533 return NULL;
1536 req->p = p;
1537 req->call_id = next_call_id(p->conn);
1538 req->state = RPC_REQUEST_QUEUED;
1540 if (object != NULL) {
1541 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1542 if (req->object == NULL) {
1543 talloc_free(req);
1544 return NULL;
1548 req->opnum = opnum;
1549 req->request_data.length = stub_data->length;
1550 req->request_data.data = stub_data->data;
1552 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1553 talloc_set_destructor(req, dcerpc_req_dequeue);
1555 dcerpc_schedule_io_trigger(p->conn);
1557 if (p->request_timeout) {
1558 tevent_add_timer(dcerpc_event_context(p), req,
1559 timeval_current_ofs(p->request_timeout, 0),
1560 dcerpc_timeout_handler, req);
1563 return req;
1567 Send a request using the transport
1570 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1572 struct rpc_request *req;
1573 struct dcerpc_pipe *p;
1574 DATA_BLOB *stub_data;
1575 struct ncacn_packet pkt;
1576 DATA_BLOB blob;
1577 uint32_t remaining, chunk_size;
1578 bool first_packet = true;
1579 size_t sig_size = 0;
1580 bool need_async = false;
1581 bool can_async = true;
1583 req = c->request_queue;
1584 if (req == NULL) {
1585 return;
1588 p = req->p;
1589 stub_data = &req->request_data;
1591 if (c->pending) {
1592 need_async = true;
1595 if (c->security_state.auth_info &&
1596 c->security_state.generic_state)
1598 struct gensec_security *gensec = c->security_state.generic_state;
1600 switch (c->security_state.auth_info->auth_level) {
1601 case DCERPC_AUTH_LEVEL_PRIVACY:
1602 case DCERPC_AUTH_LEVEL_INTEGRITY:
1603 can_async = gensec_have_feature(gensec,
1604 GENSEC_FEATURE_ASYNC_REPLIES);
1605 break;
1606 case DCERPC_AUTH_LEVEL_CONNECT:
1607 case DCERPC_AUTH_LEVEL_NONE:
1608 can_async = true;
1609 break;
1610 default:
1611 can_async = false;
1612 break;
1616 if (need_async && !can_async) {
1617 req->wait_for_sync = true;
1618 return;
1621 DLIST_REMOVE(c->request_queue, req);
1622 DLIST_ADD(c->pending, req);
1623 req->state = RPC_REQUEST_PENDING;
1625 init_ncacn_hdr(p->conn, &pkt);
1627 remaining = stub_data->length;
1629 /* we can write a full max_recv_frag size, minus the dcerpc
1630 request header size */
1631 chunk_size = p->conn->srv_max_recv_frag;
1632 chunk_size -= DCERPC_REQUEST_LENGTH;
1633 if (c->security_state.auth_info &&
1634 c->security_state.generic_state) {
1635 sig_size = gensec_sig_size(c->security_state.generic_state,
1636 p->conn->srv_max_recv_frag);
1637 if (sig_size) {
1638 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1639 chunk_size -= sig_size;
1642 chunk_size -= (chunk_size % 16);
1644 pkt.ptype = DCERPC_PKT_REQUEST;
1645 pkt.call_id = req->call_id;
1646 pkt.auth_length = 0;
1647 pkt.pfc_flags = 0;
1648 pkt.u.request.context_id = p->context_id;
1649 pkt.u.request.opnum = req->opnum;
1651 if (req->object) {
1652 pkt.u.request.object.object = *req->object;
1653 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1654 chunk_size -= ndr_size_GUID(req->object,0);
1657 /* we send a series of pdus without waiting for a reply */
1658 while (remaining > 0 || first_packet) {
1659 uint32_t chunk = MIN(chunk_size, remaining);
1660 bool last_frag = false;
1661 bool do_trans = false;
1663 first_packet = false;
1664 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1666 if (remaining == stub_data->length) {
1667 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1669 if (chunk == remaining) {
1670 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1671 last_frag = true;
1674 pkt.u.request.alloc_hint = remaining;
1675 pkt.u.request.stub_and_verifier.data = stub_data->data +
1676 (stub_data->length - remaining);
1677 pkt.u.request.stub_and_verifier.length = chunk;
1679 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1680 if (!NT_STATUS_IS_OK(req->status)) {
1681 req->state = RPC_REQUEST_DONE;
1682 DLIST_REMOVE(p->conn->pending, req);
1683 return;
1686 if (last_frag && !need_async) {
1687 do_trans = true;
1690 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1691 if (!NT_STATUS_IS_OK(req->status)) {
1692 req->state = RPC_REQUEST_DONE;
1693 DLIST_REMOVE(p->conn->pending, req);
1694 return;
1697 if (last_frag && !do_trans) {
1698 req->status = p->conn->transport.send_read(p->conn);
1699 if (!NT_STATUS_IS_OK(req->status)) {
1700 req->state = RPC_REQUEST_DONE;
1701 DLIST_REMOVE(p->conn->pending, req);
1702 return;
1706 remaining -= chunk;
1710 static void dcerpc_io_trigger(struct tevent_context *ctx,
1711 struct tevent_immediate *im,
1712 void *private_data)
1714 struct dcecli_connection *c =
1715 talloc_get_type_abort(private_data,
1716 struct dcecli_connection);
1718 c->io_trigger_pending = false;
1720 dcerpc_schedule_io_trigger(c);
1722 dcerpc_ship_next_request(c);
1725 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1727 if (c->dead) {
1728 return;
1731 if (c->request_queue == NULL) {
1732 return;
1735 if (c->request_queue->wait_for_sync && c->pending) {
1736 return;
1739 if (c->io_trigger_pending) {
1740 return;
1743 c->io_trigger_pending = true;
1745 tevent_schedule_immediate(c->io_trigger,
1746 c->event_ctx,
1747 dcerpc_io_trigger,
1752 return the event context for a dcerpc pipe
1753 used by callers who wish to operate asynchronously
1755 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1757 return p->conn->event_ctx;
1763 perform the receive side of a async dcerpc request
1765 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1766 TALLOC_CTX *mem_ctx,
1767 DATA_BLOB *stub_data)
1769 NTSTATUS status;
1771 while (req->state != RPC_REQUEST_DONE) {
1772 struct tevent_context *ctx = dcerpc_event_context(req->p);
1773 if (tevent_loop_once(ctx) != 0) {
1774 return NT_STATUS_CONNECTION_DISCONNECTED;
1777 *stub_data = req->payload;
1778 status = req->status;
1779 if (stub_data->data) {
1780 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1782 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1783 req->p->last_fault_code = req->fault_code;
1785 talloc_unlink(talloc_parent(req), req);
1786 return status;
1790 this is a paranoid NDR validator. For every packet we push onto the wire
1791 we pull it back again, then push it again. Then we compare the raw NDR data
1792 for that to the NDR we initially generated. If they don't match then we know
1793 we must have a bug in either the pull or push side of our code
1795 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1796 TALLOC_CTX *mem_ctx,
1797 DATA_BLOB blob,
1798 size_t struct_size,
1799 ndr_push_flags_fn_t ndr_push,
1800 ndr_pull_flags_fn_t ndr_pull)
1802 void *st;
1803 struct ndr_pull *pull;
1804 struct ndr_push *push;
1805 DATA_BLOB blob2;
1806 enum ndr_err_code ndr_err;
1808 st = talloc_size(mem_ctx, struct_size);
1809 if (!st) {
1810 return NT_STATUS_NO_MEMORY;
1813 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1814 if (!pull) {
1815 return NT_STATUS_NO_MEMORY;
1817 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1819 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1820 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1823 if (c->flags & DCERPC_NDR64) {
1824 pull->flags |= LIBNDR_FLAG_NDR64;
1827 ndr_err = ndr_pull(pull, NDR_IN, st);
1828 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1829 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1830 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1831 "failed input validation pull - %s",
1832 nt_errstr(status));
1833 return ndr_map_error2ntstatus(ndr_err);
1836 push = ndr_push_init_ctx(mem_ctx);
1837 if (!push) {
1838 return NT_STATUS_NO_MEMORY;
1841 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1842 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1845 if (c->flags & DCERPC_NDR64) {
1846 push->flags |= LIBNDR_FLAG_NDR64;
1849 ndr_err = ndr_push(push, NDR_IN, st);
1850 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1851 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1852 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1853 "failed input validation push - %s",
1854 nt_errstr(status));
1855 return ndr_map_error2ntstatus(ndr_err);
1858 blob2 = ndr_push_blob(push);
1860 if (data_blob_cmp(&blob, &blob2) != 0) {
1861 DEBUG(3,("original:\n"));
1862 dump_data(3, blob.data, blob.length);
1863 DEBUG(3,("secondary:\n"));
1864 dump_data(3, blob2.data, blob2.length);
1865 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1866 "failed input validation blobs doesn't match");
1867 return ndr_map_error2ntstatus(ndr_err);
1870 return NT_STATUS_OK;
1874 this is a paranoid NDR input validator. For every packet we pull
1875 from the wire we push it back again then pull and push it
1876 again. Then we compare the raw NDR data for that to the NDR we
1877 initially generated. If they don't match then we know we must have a
1878 bug in either the pull or push side of our code
1880 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1881 struct ndr_pull *pull_in,
1882 void *struct_ptr,
1883 size_t struct_size,
1884 ndr_push_flags_fn_t ndr_push,
1885 ndr_pull_flags_fn_t ndr_pull,
1886 ndr_print_function_t ndr_print)
1888 void *st;
1889 struct ndr_pull *pull;
1890 struct ndr_push *push;
1891 DATA_BLOB blob, blob2;
1892 TALLOC_CTX *mem_ctx = pull_in;
1893 char *s1, *s2;
1894 enum ndr_err_code ndr_err;
1896 st = talloc_size(mem_ctx, struct_size);
1897 if (!st) {
1898 return NT_STATUS_NO_MEMORY;
1900 memcpy(st, struct_ptr, struct_size);
1902 push = ndr_push_init_ctx(mem_ctx);
1903 if (!push) {
1904 return NT_STATUS_NO_MEMORY;
1907 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1908 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1909 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1910 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1911 "failed output validation push - %s",
1912 nt_errstr(status));
1913 return ndr_map_error2ntstatus(ndr_err);
1916 blob = ndr_push_blob(push);
1918 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1919 if (!pull) {
1920 return NT_STATUS_NO_MEMORY;
1923 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1924 ndr_err = ndr_pull(pull, NDR_OUT, st);
1925 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1926 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1927 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1928 "failed output validation pull - %s",
1929 nt_errstr(status));
1930 return ndr_map_error2ntstatus(ndr_err);
1933 push = ndr_push_init_ctx(mem_ctx);
1934 if (!push) {
1935 return NT_STATUS_NO_MEMORY;
1938 ndr_err = ndr_push(push, NDR_OUT, st);
1939 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1940 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1941 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1942 "failed output validation push2 - %s",
1943 nt_errstr(status));
1944 return ndr_map_error2ntstatus(ndr_err);
1947 blob2 = ndr_push_blob(push);
1949 if (data_blob_cmp(&blob, &blob2) != 0) {
1950 DEBUG(3,("original:\n"));
1951 dump_data(3, blob.data, blob.length);
1952 DEBUG(3,("secondary:\n"));
1953 dump_data(3, blob2.data, blob2.length);
1954 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1955 "failed output validation blobs doesn't match");
1956 return ndr_map_error2ntstatus(ndr_err);
1959 /* this checks the printed forms of the two structures, which effectively
1960 tests all of the value() attributes */
1961 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1962 NDR_OUT, struct_ptr);
1963 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1964 NDR_OUT, st);
1965 if (strcmp(s1, s2) != 0) {
1966 #if 1
1967 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1968 #else
1969 /* this is sometimes useful */
1970 printf("VALIDATE ERROR\n");
1971 file_save("wire.dat", s1, strlen(s1));
1972 file_save("gen.dat", s2, strlen(s2));
1973 system("diff -u wire.dat gen.dat");
1974 #endif
1975 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1976 "failed output validation strings doesn't match");
1977 return ndr_map_error2ntstatus(ndr_err);
1980 return NT_STATUS_OK;
1984 a useful function for retrieving the server name we connected to
1986 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1988 return p->conn ? p->conn->server_name : NULL;
1993 get the dcerpc auth_level for a open connection
1995 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1997 uint8_t auth_level;
1999 if (c->flags & DCERPC_SEAL) {
2000 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2001 } else if (c->flags & DCERPC_SIGN) {
2002 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2003 } else if (c->flags & DCERPC_CONNECT) {
2004 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2005 } else {
2006 auth_level = DCERPC_AUTH_LEVEL_NONE;
2008 return auth_level;
2011 struct dcerpc_alter_context_state {
2012 struct tevent_context *ev;
2013 struct dcerpc_pipe *p;
2016 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2017 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2018 DATA_BLOB *raw_packet,
2019 struct ncacn_packet *pkt);
2021 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2022 struct tevent_context *ev,
2023 struct dcerpc_pipe *p,
2024 const struct ndr_syntax_id *syntax,
2025 const struct ndr_syntax_id *transfer_syntax)
2027 struct tevent_req *req;
2028 struct dcerpc_alter_context_state *state;
2029 struct ncacn_packet pkt;
2030 DATA_BLOB blob;
2031 NTSTATUS status;
2032 struct rpc_request *subreq;
2034 req = tevent_req_create(mem_ctx, &state,
2035 struct dcerpc_alter_context_state);
2036 if (req == NULL) {
2037 return NULL;
2040 state->ev = ev;
2041 state->p = p;
2043 p->syntax = *syntax;
2044 p->transfer_syntax = *transfer_syntax;
2046 init_ncacn_hdr(p->conn, &pkt);
2048 pkt.ptype = DCERPC_PKT_ALTER;
2049 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2050 pkt.call_id = p->conn->call_id;
2051 pkt.auth_length = 0;
2053 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
2054 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2057 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2058 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2059 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
2060 pkt.u.alter.num_contexts = 1;
2061 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2062 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2063 return tevent_req_post(req, ev);
2065 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2066 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2067 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2068 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2069 pkt.u.alter.auth_info = data_blob(NULL, 0);
2071 /* construct the NDR form of the packet */
2072 status = ncacn_push_auth(&blob, state, &pkt,
2073 p->conn->security_state.auth_info);
2074 if (tevent_req_nterror(req, status)) {
2075 return tevent_req_post(req, ev);
2078 p->conn->transport.recv_data = dcerpc_recv_data;
2081 * we allocate a dcerpc_request so we can be in the same
2082 * request queue as normal requests
2084 subreq = talloc_zero(state, struct rpc_request);
2085 if (tevent_req_nomem(subreq, req)) {
2086 return tevent_req_post(req, ev);
2089 subreq->state = RPC_REQUEST_PENDING;
2090 subreq->call_id = pkt.call_id;
2091 subreq->async.private_data = req;
2092 subreq->async.callback = dcerpc_alter_context_fail_handler;
2093 subreq->p = p;
2094 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2095 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2096 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2098 status = p->conn->transport.send_request(p->conn, &blob, true);
2099 if (tevent_req_nterror(req, status)) {
2100 return tevent_req_post(req, ev);
2103 tevent_add_timer(ev, subreq,
2104 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2105 dcerpc_timeout_handler, subreq);
2107 return req;
2110 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2112 struct tevent_req *req =
2113 talloc_get_type_abort(subreq->async.private_data,
2114 struct tevent_req);
2115 struct dcerpc_alter_context_state *state =
2116 tevent_req_data(req,
2117 struct dcerpc_alter_context_state);
2118 NTSTATUS status = subreq->status;
2120 TALLOC_FREE(subreq);
2123 * We trigger the callback in the next event run
2124 * because the code in this file might trigger
2125 * multiple request callbacks from within a single
2126 * while loop.
2128 * In order to avoid segfaults from within
2129 * dcerpc_connection_dead() we call
2130 * tevent_req_defer_callback().
2132 tevent_req_defer_callback(req, state->ev);
2134 tevent_req_nterror(req, status);
2137 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2138 DATA_BLOB *raw_packet,
2139 struct ncacn_packet *pkt)
2141 struct tevent_req *req =
2142 talloc_get_type_abort(subreq->async.private_data,
2143 struct tevent_req);
2144 struct dcerpc_alter_context_state *state =
2145 tevent_req_data(req,
2146 struct dcerpc_alter_context_state);
2147 struct dcecli_connection *conn = state->p->conn;
2148 NTSTATUS status;
2151 * Note that pkt is allocated under raw_packet->data,
2152 * while raw_packet->data is a child of subreq.
2154 talloc_steal(state, raw_packet->data);
2155 TALLOC_FREE(subreq);
2158 * We trigger the callback in the next event run
2159 * because the code in this file might trigger
2160 * multiple request callbacks from within a single
2161 * while loop.
2163 * In order to avoid segfaults from within
2164 * dcerpc_connection_dead() we call
2165 * tevent_req_defer_callback().
2167 tevent_req_defer_callback(req, state->ev);
2169 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2170 pkt->u.alter_resp.num_results == 1 &&
2171 pkt->u.alter_resp.ctx_list[0].result != 0) {
2172 status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason);
2173 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2174 pkt->u.alter_resp.ctx_list[0].reason,
2175 nt_errstr(status)));
2176 tevent_req_nterror(req, status);
2177 return;
2180 if (pkt->ptype == DCERPC_PKT_FAULT) {
2181 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2182 dcerpc_errstr(state, pkt->u.fault.status)));
2183 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2184 state->p->last_fault_code = pkt->u.fault.status;
2185 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2186 } else {
2187 state->p->last_fault_code = pkt->u.fault.status;
2188 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2190 return;
2193 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2194 pkt->u.alter_resp.num_results == 0 ||
2195 pkt->u.alter_resp.ctx_list[0].result != 0) {
2196 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2197 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2198 return;
2201 /* the alter_resp might contain a reply set of credentials */
2202 if (conn->security_state.auth_info &&
2203 pkt->u.alter_resp.auth_info.length) {
2204 uint32_t auth_length;
2206 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2207 conn->security_state.auth_info, &auth_length, true);
2208 if (tevent_req_nterror(req, status)) {
2209 return;
2213 tevent_req_done(req);
2216 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2218 return tevent_req_simple_recv_ntstatus(req);
2222 send a dcerpc alter_context request
2224 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2225 TALLOC_CTX *mem_ctx,
2226 const struct ndr_syntax_id *syntax,
2227 const struct ndr_syntax_id *transfer_syntax)
2229 struct tevent_req *subreq;
2230 struct tevent_context *ev = p->conn->event_ctx;
2231 bool ok;
2233 /* TODO: create a new event context here */
2235 subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx,
2236 p, syntax, transfer_syntax);
2237 if (subreq == NULL) {
2238 return NT_STATUS_NO_MEMORY;
2241 ok = tevent_req_poll(subreq, ev);
2242 if (!ok) {
2243 NTSTATUS status;
2244 status = map_nt_error_from_unix_common(errno);
2245 return status;
2248 return dcerpc_alter_context_recv(subreq);
2251 void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2253 if (c->transport.stream == NULL) {
2254 return;
2257 tevent_queue_stop(c->transport.write_queue);
2258 TALLOC_FREE(c->transport.read_subreq);
2259 TALLOC_FREE(c->transport.stream);
2261 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2262 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2265 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2266 status = NT_STATUS_END_OF_FILE;
2269 if (c->transport.recv_data) {
2270 c->transport.recv_data(c, NULL, status);
2276 shutdown SMB pipe connection
2278 struct dcerpc_shutdown_pipe_state {
2279 struct dcecli_connection *c;
2280 NTSTATUS status;
2283 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2285 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2287 struct dcerpc_shutdown_pipe_state *state;
2288 struct tevent_req *subreq;
2290 if (c->transport.stream == NULL) {
2291 return NT_STATUS_OK;
2294 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2295 if (state == NULL) {
2296 return NT_STATUS_NO_MEMORY;
2298 state->c = c;
2299 state->status = status;
2301 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2302 if (subreq == NULL) {
2303 return NT_STATUS_NO_MEMORY;
2305 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2307 return status;
2310 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2312 struct dcerpc_shutdown_pipe_state *state =
2313 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2314 struct dcecli_connection *c = state->c;
2315 NTSTATUS status = state->status;
2316 int error;
2319 * here we ignore the return values...
2321 tstream_disconnect_recv(subreq, &error);
2322 TALLOC_FREE(subreq);
2324 TALLOC_FREE(state);
2326 dcerpc_transport_dead(c, status);