s4:librpc: factor out xxx_send_request() to dcerpc_send_request()
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blob9e893d0d8989962d4fa84e7762c0663865ef3e28
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 "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
39 enum rpc_request_state {
40 RPC_REQUEST_QUEUED,
41 RPC_REQUEST_PENDING,
42 RPC_REQUEST_DONE
46 handle for an async dcerpc request
48 struct rpc_request {
49 struct rpc_request *next, *prev;
50 struct dcerpc_pipe *p;
51 NTSTATUS status;
52 uint32_t call_id;
53 enum rpc_request_state state;
54 DATA_BLOB payload;
55 uint32_t flags;
56 uint32_t fault_code;
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler)(struct rpc_request *conn,
61 DATA_BLOB *blob, struct ncacn_packet *pkt);
63 const struct GUID *object;
64 uint16_t opnum;
65 DATA_BLOB request_data;
66 bool ignore_timeout;
67 bool wait_for_sync;
69 struct {
70 void (*callback)(struct rpc_request *);
71 void *private_data;
72 } async;
75 _PUBLIC_ NTSTATUS dcerpc_init(void)
77 return gensec_init();
80 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
81 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
83 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
84 struct dcerpc_pipe *p,
85 const struct GUID *object,
86 uint16_t opnum,
87 DATA_BLOB *stub_data);
88 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
89 TALLOC_CTX *mem_ctx,
90 DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
92 TALLOC_CTX *mem_ctx,
93 DATA_BLOB blob,
94 size_t struct_size,
95 ndr_push_flags_fn_t ndr_push,
96 ndr_pull_flags_fn_t ndr_pull);
97 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
98 struct ndr_pull *pull_in,
99 void *struct_ptr,
100 size_t struct_size,
101 ndr_push_flags_fn_t ndr_push,
102 ndr_pull_flags_fn_t ndr_pull,
103 ndr_print_function_t ndr_print);
104 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
105 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
106 bool trigger_read);
107 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
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;
148 * Windows uses 5840 for ncacn_ip_tcp,
149 * so we also use it (for every transport)
150 * by default. But we give the transport
151 * the chance to overwrite it.
153 c->srv_max_xmit_frag = 5840;
154 c->srv_max_recv_frag = 5840;
155 c->pending = NULL;
157 c->io_trigger = tevent_create_immediate(c);
158 if (c->io_trigger == NULL) {
159 talloc_free(c);
160 return NULL;
163 talloc_set_destructor(c, dcerpc_connection_destructor);
165 return c;
168 struct dcerpc_bh_state {
169 struct dcerpc_pipe *p;
172 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
174 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
175 struct dcerpc_bh_state);
177 if (!hs->p) {
178 return false;
181 if (!hs->p->conn) {
182 return false;
185 if (hs->p->conn->dead) {
186 return false;
189 return true;
192 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
193 uint32_t timeout)
195 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
196 struct dcerpc_bh_state);
197 uint32_t old;
199 if (!hs->p) {
200 return DCERPC_REQUEST_TIMEOUT;
203 old = hs->p->request_timeout;
204 hs->p->request_timeout = timeout;
206 return old;
209 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
210 enum dcerpc_AuthType *auth_type,
211 enum dcerpc_AuthLevel *auth_level)
213 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
214 struct dcerpc_bh_state);
216 if (hs->p == NULL) {
217 return;
220 if (hs->p->conn == NULL) {
221 return;
224 if (hs->p->conn->security_state.auth_info == NULL) {
225 return;
228 *auth_type = hs->p->conn->security_state.auth_info->auth_type;
229 *auth_level = hs->p->conn->security_state.auth_info->auth_level;
232 struct dcerpc_bh_raw_call_state {
233 struct tevent_context *ev;
234 struct dcerpc_binding_handle *h;
235 DATA_BLOB in_data;
236 DATA_BLOB out_data;
237 uint32_t out_flags;
240 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
242 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
243 struct tevent_context *ev,
244 struct dcerpc_binding_handle *h,
245 const struct GUID *object,
246 uint32_t opnum,
247 uint32_t in_flags,
248 const uint8_t *in_data,
249 size_t in_length)
251 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
252 struct dcerpc_bh_state);
253 struct tevent_req *req;
254 struct dcerpc_bh_raw_call_state *state;
255 bool ok;
256 struct rpc_request *subreq;
258 req = tevent_req_create(mem_ctx, &state,
259 struct dcerpc_bh_raw_call_state);
260 if (req == NULL) {
261 return NULL;
263 state->ev = ev;
264 state->h = h;
265 state->in_data.data = discard_const_p(uint8_t, in_data);
266 state->in_data.length = in_length;
268 ok = dcerpc_bh_is_connected(h);
269 if (!ok) {
270 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
271 return tevent_req_post(req, ev);
274 subreq = dcerpc_request_send(state,
275 hs->p,
276 object,
277 opnum,
278 &state->in_data);
279 if (tevent_req_nomem(subreq, req)) {
280 return tevent_req_post(req, ev);
282 subreq->async.callback = dcerpc_bh_raw_call_done;
283 subreq->async.private_data = req;
285 return req;
288 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
290 struct tevent_req *req =
291 talloc_get_type_abort(subreq->async.private_data,
292 struct tevent_req);
293 struct dcerpc_bh_raw_call_state *state =
294 tevent_req_data(req,
295 struct dcerpc_bh_raw_call_state);
296 NTSTATUS status;
297 uint32_t fault_code;
299 state->out_flags = 0;
300 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
301 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
304 fault_code = subreq->fault_code;
306 status = dcerpc_request_recv(subreq, state, &state->out_data);
307 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
308 status = dcerpc_fault_to_nt_status(fault_code);
312 * We trigger the callback in the next event run
313 * because the code in this file might trigger
314 * multiple request callbacks from within a single
315 * while loop.
317 * In order to avoid segfaults from within
318 * dcerpc_connection_dead() we call
319 * tevent_req_defer_callback().
321 tevent_req_defer_callback(req, state->ev);
323 if (!NT_STATUS_IS_OK(status)) {
324 tevent_req_nterror(req, status);
325 return;
328 tevent_req_done(req);
331 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
332 TALLOC_CTX *mem_ctx,
333 uint8_t **out_data,
334 size_t *out_length,
335 uint32_t *out_flags)
337 struct dcerpc_bh_raw_call_state *state =
338 tevent_req_data(req,
339 struct dcerpc_bh_raw_call_state);
340 NTSTATUS status;
342 if (tevent_req_is_nterror(req, &status)) {
343 tevent_req_received(req);
344 return status;
347 *out_data = talloc_move(mem_ctx, &state->out_data.data);
348 *out_length = state->out_data.length;
349 *out_flags = state->out_flags;
350 tevent_req_received(req);
351 return NT_STATUS_OK;
354 struct dcerpc_bh_disconnect_state {
355 uint8_t _dummy;
358 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
359 struct tevent_context *ev,
360 struct dcerpc_binding_handle *h)
362 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
363 struct dcerpc_bh_state);
364 struct tevent_req *req;
365 struct dcerpc_bh_disconnect_state *state;
366 bool ok;
368 req = tevent_req_create(mem_ctx, &state,
369 struct dcerpc_bh_disconnect_state);
370 if (req == NULL) {
371 return NULL;
374 ok = dcerpc_bh_is_connected(h);
375 if (!ok) {
376 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
377 return tevent_req_post(req, ev);
380 /* TODO: do a real disconnect ... */
381 hs->p = NULL;
383 tevent_req_done(req);
384 return tevent_req_post(req, ev);
387 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
389 NTSTATUS status;
391 if (tevent_req_is_nterror(req, &status)) {
392 tevent_req_received(req);
393 return status;
396 tevent_req_received(req);
397 return NT_STATUS_OK;
400 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
402 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
403 struct dcerpc_bh_state);
405 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
406 return true;
409 return false;
412 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
414 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
415 struct dcerpc_bh_state);
417 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
418 return true;
421 return false;
424 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
426 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
427 struct dcerpc_bh_state);
429 if (hs->p->conn->flags & DCERPC_NDR64) {
430 return true;
433 return false;
436 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
437 int ndr_flags,
438 const void *_struct_ptr,
439 const struct ndr_interface_call *call)
441 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
442 struct dcerpc_bh_state);
443 void *struct_ptr = discard_const(_struct_ptr);
445 if (ndr_flags & NDR_IN) {
446 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
447 ndr_print_function_debug(call->ndr_print,
448 call->name,
449 ndr_flags,
450 struct_ptr);
453 if (ndr_flags & NDR_OUT) {
454 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
455 ndr_print_function_debug(call->ndr_print,
456 call->name,
457 ndr_flags,
458 struct_ptr);
463 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
464 NTSTATUS error,
465 const void *struct_ptr,
466 const struct ndr_interface_call *call)
468 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
469 call->name, nt_errstr(error)));
472 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
473 NTSTATUS error,
474 const DATA_BLOB *blob,
475 const struct ndr_interface_call *call)
477 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
478 struct dcerpc_bh_state);
479 const uint32_t num_examples = 20;
480 uint32_t i;
482 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
483 call->name, nt_errstr(error)));
485 if (hs->p->conn->packet_log_dir == NULL) return;
487 for (i=0;i<num_examples;i++) {
488 char *name=NULL;
489 asprintf(&name, "%s/rpclog/%s-out.%d",
490 hs->p->conn->packet_log_dir,
491 call->name, i);
492 if (name == NULL) {
493 return;
495 if (!file_exist(name)) {
496 if (file_save(name, blob->data, blob->length)) {
497 DEBUG(10,("Logged rpc packet to %s\n", name));
499 free(name);
500 break;
502 free(name);
506 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
507 TALLOC_CTX *mem_ctx,
508 const DATA_BLOB *blob,
509 const struct ndr_interface_call *call)
511 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
512 struct dcerpc_bh_state);
514 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
515 NTSTATUS status;
517 status = dcerpc_ndr_validate_in(hs->p->conn,
518 mem_ctx,
519 *blob,
520 call->struct_size,
521 call->ndr_push,
522 call->ndr_pull);
523 if (!NT_STATUS_IS_OK(status)) {
524 DEBUG(0,("Validation [in] failed for %s - %s\n",
525 call->name, nt_errstr(status)));
526 return status;
530 DEBUG(10,("rpc request data:\n"));
531 dump_data(10, blob->data, blob->length);
533 return NT_STATUS_OK;
536 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
537 struct ndr_pull *pull_in,
538 const void *_struct_ptr,
539 const struct ndr_interface_call *call)
541 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
542 struct dcerpc_bh_state);
543 void *struct_ptr = discard_const(_struct_ptr);
545 DEBUG(10,("rpc reply data:\n"));
546 dump_data(10, pull_in->data, pull_in->data_size);
548 if (pull_in->offset != pull_in->data_size) {
549 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
550 pull_in->data_size - pull_in->offset,
551 pull_in->offset, pull_in->offset,
552 call->name));
553 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
554 but it turns out that early versions of NT
555 (specifically NT3.1) add junk onto the end of rpc
556 packets, so if we want to interoperate at all with
557 those versions then we need to ignore this error */
560 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
561 NTSTATUS status;
563 status = dcerpc_ndr_validate_out(hs->p->conn,
564 pull_in,
565 struct_ptr,
566 call->struct_size,
567 call->ndr_push,
568 call->ndr_pull,
569 call->ndr_print);
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(2,("Validation [out] failed for %s - %s\n",
572 call->name, nt_errstr(status)));
573 return status;
577 return NT_STATUS_OK;
580 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
581 .name = "dcerpc",
582 .is_connected = dcerpc_bh_is_connected,
583 .set_timeout = dcerpc_bh_set_timeout,
584 .auth_info = dcerpc_bh_auth_info,
585 .raw_call_send = dcerpc_bh_raw_call_send,
586 .raw_call_recv = dcerpc_bh_raw_call_recv,
587 .disconnect_send = dcerpc_bh_disconnect_send,
588 .disconnect_recv = dcerpc_bh_disconnect_recv,
590 .push_bigendian = dcerpc_bh_push_bigendian,
591 .ref_alloc = dcerpc_bh_ref_alloc,
592 .use_ndr64 = dcerpc_bh_use_ndr64,
593 .do_ndr_print = dcerpc_bh_do_ndr_print,
594 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
595 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
596 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
597 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
600 /* initialise a dcerpc pipe. */
601 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
603 struct dcerpc_binding_handle *h;
604 struct dcerpc_bh_state *hs;
606 h = dcerpc_binding_handle_create(p,
607 &dcerpc_bh_ops,
608 NULL,
609 NULL, /* TODO */
610 &hs,
611 struct dcerpc_bh_state,
612 __location__);
613 if (h == NULL) {
614 return NULL;
616 hs->p = p;
618 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
620 return h;
623 /* initialise a dcerpc pipe. */
624 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
626 struct dcerpc_pipe *p;
628 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
629 if (!p) {
630 return NULL;
633 p->conn = dcerpc_connection_init(p, ev);
634 if (p->conn == NULL) {
635 talloc_free(p);
636 return NULL;
639 p->last_fault_code = 0;
640 p->context_id = 0;
641 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
642 p->binding = NULL;
644 ZERO_STRUCT(p->syntax);
645 ZERO_STRUCT(p->transfer_syntax);
647 if (DEBUGLVL(100)) {
648 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
651 p->binding_handle = dcerpc_pipe_binding_handle(p);
652 if (p->binding_handle == NULL) {
653 talloc_free(p);
654 return NULL;
657 return p;
662 choose the next call id to use
664 static uint32_t next_call_id(struct dcecli_connection *c)
666 c->call_id++;
667 if (c->call_id == 0) {
668 c->call_id++;
670 return c->call_id;
674 setup for a ndr pull, also setting up any flags from the binding string
676 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
677 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
679 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
681 if (ndr == NULL) return ndr;
683 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
684 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
687 if (c->flags & DCERPC_NDR_REF_ALLOC) {
688 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
691 if (c->flags & DCERPC_NDR64) {
692 ndr->flags |= LIBNDR_FLAG_NDR64;
695 return ndr;
699 parse a data blob into a ncacn_packet structure. This handles both
700 input and output packets
702 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
703 struct ncacn_packet *pkt)
705 struct ndr_pull *ndr;
706 enum ndr_err_code ndr_err;
708 ndr = ndr_pull_init_blob(blob, mem_ctx);
709 if (!ndr) {
710 return NT_STATUS_NO_MEMORY;
713 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
714 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
717 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
718 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
721 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
722 TALLOC_FREE(ndr);
723 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
724 return ndr_map_error2ntstatus(ndr_err);
727 if (pkt->frag_length != blob->length) {
728 return NT_STATUS_RPC_PROTOCOL_ERROR;
731 return NT_STATUS_OK;
735 parse the authentication information on a dcerpc response packet
737 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
738 DATA_BLOB *raw_packet,
739 struct ncacn_packet *pkt)
741 NTSTATUS status;
742 struct dcerpc_auth auth;
743 uint32_t auth_length;
745 if (!c->security_state.auth_info ||
746 !c->security_state.generic_state) {
747 return NT_STATUS_OK;
750 switch (c->security_state.auth_info->auth_level) {
751 case DCERPC_AUTH_LEVEL_PRIVACY:
752 case DCERPC_AUTH_LEVEL_INTEGRITY:
753 break;
755 case DCERPC_AUTH_LEVEL_CONNECT:
756 if (pkt->auth_length != 0) {
757 break;
759 return NT_STATUS_OK;
760 case DCERPC_AUTH_LEVEL_NONE:
761 if (pkt->auth_length != 0) {
762 return NT_STATUS_INVALID_NETWORK_RESPONSE;
764 return NT_STATUS_OK;
766 default:
767 return NT_STATUS_INVALID_LEVEL;
770 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
771 &pkt->u.response.stub_and_verifier,
772 &auth, &auth_length, false);
773 NT_STATUS_NOT_OK_RETURN(status);
775 pkt->u.response.stub_and_verifier.length -= auth_length;
777 /* check signature or unseal the packet */
778 switch (c->security_state.auth_info->auth_level) {
779 case DCERPC_AUTH_LEVEL_PRIVACY:
780 status = gensec_unseal_packet(c->security_state.generic_state,
781 raw_packet->data + DCERPC_REQUEST_LENGTH,
782 pkt->u.response.stub_and_verifier.length,
783 raw_packet->data,
784 raw_packet->length - auth.credentials.length,
785 &auth.credentials);
786 memcpy(pkt->u.response.stub_and_verifier.data,
787 raw_packet->data + DCERPC_REQUEST_LENGTH,
788 pkt->u.response.stub_and_verifier.length);
789 break;
791 case DCERPC_AUTH_LEVEL_INTEGRITY:
792 status = gensec_check_packet(c->security_state.generic_state,
793 pkt->u.response.stub_and_verifier.data,
794 pkt->u.response.stub_and_verifier.length,
795 raw_packet->data,
796 raw_packet->length - auth.credentials.length,
797 &auth.credentials);
798 break;
800 case DCERPC_AUTH_LEVEL_CONNECT:
801 /* for now we ignore possible signatures here */
802 status = NT_STATUS_OK;
803 break;
805 default:
806 status = NT_STATUS_INVALID_LEVEL;
807 break;
810 /* remove the indicated amount of padding */
811 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
812 return NT_STATUS_INFO_LENGTH_MISMATCH;
814 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
816 return status;
821 push a dcerpc request packet into a blob, possibly signing it.
823 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
824 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
825 size_t sig_size,
826 struct ncacn_packet *pkt)
828 NTSTATUS status;
829 struct ndr_push *ndr;
830 DATA_BLOB creds2;
831 size_t payload_length;
832 enum ndr_err_code ndr_err;
833 size_t hdr_size = DCERPC_REQUEST_LENGTH;
835 /* non-signed packets are simpler */
836 if (sig_size == 0) {
837 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
840 switch (c->security_state.auth_info->auth_level) {
841 case DCERPC_AUTH_LEVEL_PRIVACY:
842 case DCERPC_AUTH_LEVEL_INTEGRITY:
843 break;
845 case DCERPC_AUTH_LEVEL_CONNECT:
846 /* TODO: let the gensec mech decide if it wants to generate a signature */
847 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
849 case DCERPC_AUTH_LEVEL_NONE:
850 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
852 default:
853 return NT_STATUS_INVALID_LEVEL;
856 ndr = ndr_push_init_ctx(mem_ctx);
857 if (!ndr) {
858 return NT_STATUS_NO_MEMORY;
861 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
862 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
865 if (c->flags & DCERPC_NDR64) {
866 ndr->flags |= LIBNDR_FLAG_NDR64;
869 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
870 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
871 hdr_size += 16;
874 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
875 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
876 return ndr_map_error2ntstatus(ndr_err);
879 /* pad to 16 byte multiple in the payload portion of the
880 packet. This matches what w2k3 does. Note that we can't use
881 ndr_push_align() as that is relative to the start of the
882 whole packet, whereas w2k8 wants it relative to the start
883 of the stub */
884 c->security_state.auth_info->auth_pad_length =
885 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
886 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
887 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
888 return ndr_map_error2ntstatus(ndr_err);
891 payload_length = pkt->u.request.stub_and_verifier.length +
892 c->security_state.auth_info->auth_pad_length;
894 /* we start without signature, it will appended later */
895 c->security_state.auth_info->credentials = data_blob(NULL,0);
897 /* add the auth verifier */
898 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
899 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
900 return ndr_map_error2ntstatus(ndr_err);
903 /* extract the whole packet as a blob */
904 *blob = ndr_push_blob(ndr);
907 * Setup the frag and auth length in the packet buffer.
908 * This is needed if the GENSEC mech does AEAD signing
909 * of the packet headers. The signature itself will be
910 * appended later.
912 dcerpc_set_frag_length(blob, blob->length + sig_size);
913 dcerpc_set_auth_length(blob, sig_size);
915 /* sign or seal the packet */
916 switch (c->security_state.auth_info->auth_level) {
917 case DCERPC_AUTH_LEVEL_PRIVACY:
918 status = gensec_seal_packet(c->security_state.generic_state,
919 mem_ctx,
920 blob->data + hdr_size,
921 payload_length,
922 blob->data,
923 blob->length,
924 &creds2);
925 if (!NT_STATUS_IS_OK(status)) {
926 return status;
928 break;
930 case DCERPC_AUTH_LEVEL_INTEGRITY:
931 status = gensec_sign_packet(c->security_state.generic_state,
932 mem_ctx,
933 blob->data + hdr_size,
934 payload_length,
935 blob->data,
936 blob->length,
937 &creds2);
938 if (!NT_STATUS_IS_OK(status)) {
939 return status;
941 break;
943 default:
944 status = NT_STATUS_INVALID_LEVEL;
945 break;
948 if (creds2.length != sig_size) {
949 /* this means the sig_size estimate for the signature
950 was incorrect. We have to correct the packet
951 sizes. That means we could go over the max fragment
952 length */
953 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
954 (unsigned) creds2.length,
955 (unsigned) sig_size,
956 (unsigned) c->security_state.auth_info->auth_pad_length,
957 (unsigned) pkt->u.request.stub_and_verifier.length));
958 dcerpc_set_frag_length(blob, blob->length + creds2.length);
959 dcerpc_set_auth_length(blob, creds2.length);
962 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
963 return NT_STATUS_NO_MEMORY;
966 return NT_STATUS_OK;
971 fill in the fixed values in a dcerpc header
973 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
975 pkt->rpc_vers = 5;
976 pkt->rpc_vers_minor = 0;
977 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
978 pkt->drep[0] = 0;
979 } else {
980 pkt->drep[0] = DCERPC_DREP_LE;
982 pkt->drep[1] = 0;
983 pkt->drep[2] = 0;
984 pkt->drep[3] = 0;
988 map a bind nak reason to a NTSTATUS
990 static NTSTATUS dcerpc_map_reason(uint16_t reason)
992 switch (reason) {
993 case DCERPC_BIND_REASON_ASYNTAX:
994 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
995 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
996 return NT_STATUS_INVALID_PARAMETER;
998 return NT_STATUS_UNSUCCESSFUL;
1002 remove requests from the pending or queued queues
1004 static int dcerpc_req_dequeue(struct rpc_request *req)
1006 switch (req->state) {
1007 case RPC_REQUEST_QUEUED:
1008 DLIST_REMOVE(req->p->conn->request_queue, req);
1009 break;
1010 case RPC_REQUEST_PENDING:
1011 DLIST_REMOVE(req->p->conn->pending, req);
1012 break;
1013 case RPC_REQUEST_DONE:
1014 break;
1016 return 0;
1021 mark the dcerpc connection dead. All outstanding requests get an error
1023 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1025 if (conn->dead) return;
1027 conn->dead = true;
1029 TALLOC_FREE(conn->io_trigger);
1030 conn->io_trigger_pending = false;
1032 conn->transport.recv_data = NULL;
1034 dcerpc_shutdown_pipe(conn, status);
1036 /* all pending requests get the error */
1037 while (conn->pending) {
1038 struct rpc_request *req = conn->pending;
1039 dcerpc_req_dequeue(req);
1040 req->state = RPC_REQUEST_DONE;
1041 req->status = status;
1042 if (req->async.callback) {
1043 req->async.callback(req);
1047 /* all requests, which are not shipped */
1048 while (conn->request_queue) {
1049 struct rpc_request *req = conn->request_queue;
1050 dcerpc_req_dequeue(req);
1051 req->state = RPC_REQUEST_DONE;
1052 req->status = status;
1053 if (req->async.callback) {
1054 req->async.callback(req);
1058 talloc_set_destructor(conn, NULL);
1059 if (conn->free_skipped) {
1060 talloc_free(conn);
1065 forward declarations of the recv_data handlers for the types of
1066 packets we need to handle
1068 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1069 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1072 receive a dcerpc reply from the transport. Here we work out what
1073 type of reply it is (normal request, bind or alter context) and
1074 dispatch to the appropriate handler
1076 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1078 struct ncacn_packet pkt;
1080 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1081 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1084 /* the transport may be telling us of a severe error, such as
1085 a dropped socket */
1086 if (!NT_STATUS_IS_OK(status)) {
1087 data_blob_free(blob);
1088 dcerpc_connection_dead(conn, status);
1089 return;
1092 /* parse the basic packet to work out what type of response this is */
1093 status = ncacn_pull(conn, blob, blob->data, &pkt);
1094 if (!NT_STATUS_IS_OK(status)) {
1095 data_blob_free(blob);
1096 dcerpc_connection_dead(conn, status);
1097 return;
1100 dcerpc_request_recv_data(conn, blob, &pkt);
1104 handle timeouts of individual dcerpc requests
1106 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1107 struct timeval t, void *private_data)
1109 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1111 if (req->ignore_timeout) {
1112 dcerpc_req_dequeue(req);
1113 req->state = RPC_REQUEST_DONE;
1114 req->status = NT_STATUS_IO_TIMEOUT;
1115 if (req->async.callback) {
1116 req->async.callback(req);
1118 return;
1121 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1124 struct dcerpc_bind_state {
1125 struct tevent_context *ev;
1126 struct dcerpc_pipe *p;
1129 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1130 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1131 DATA_BLOB *raw_packet,
1132 struct ncacn_packet *pkt);
1134 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1135 struct tevent_context *ev,
1136 struct dcerpc_pipe *p,
1137 const struct ndr_syntax_id *syntax,
1138 const struct ndr_syntax_id *transfer_syntax)
1140 struct tevent_req *req;
1141 struct dcerpc_bind_state *state;
1142 struct ncacn_packet pkt;
1143 DATA_BLOB blob;
1144 NTSTATUS status;
1145 struct rpc_request *subreq;
1147 req = tevent_req_create(mem_ctx, &state,
1148 struct dcerpc_bind_state);
1149 if (req == NULL) {
1150 return NULL;
1153 state->ev = ev;
1154 state->p = p;
1156 p->syntax = *syntax;
1157 p->transfer_syntax = *transfer_syntax;
1159 init_ncacn_hdr(p->conn, &pkt);
1161 pkt.ptype = DCERPC_PKT_BIND;
1162 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1163 pkt.call_id = p->conn->call_id;
1164 pkt.auth_length = 0;
1166 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1167 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1170 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1171 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1174 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1175 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1176 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1177 pkt.u.bind.num_contexts = 1;
1178 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1179 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1180 return tevent_req_post(req, ev);
1182 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1183 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1184 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1185 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1186 pkt.u.bind.auth_info = data_blob(NULL, 0);
1188 /* construct the NDR form of the packet */
1189 status = ncacn_push_auth(&blob, state, &pkt,
1190 p->conn->security_state.auth_info);
1191 if (tevent_req_nterror(req, status)) {
1192 return tevent_req_post(req, ev);
1195 p->conn->transport.recv_data = dcerpc_recv_data;
1198 * we allocate a dcerpc_request so we can be in the same
1199 * request queue as normal requests
1201 subreq = talloc_zero(state, struct rpc_request);
1202 if (tevent_req_nomem(subreq, req)) {
1203 return tevent_req_post(req, ev);
1206 subreq->state = RPC_REQUEST_PENDING;
1207 subreq->call_id = pkt.call_id;
1208 subreq->async.private_data = req;
1209 subreq->async.callback = dcerpc_bind_fail_handler;
1210 subreq->p = p;
1211 subreq->recv_handler = dcerpc_bind_recv_handler;
1212 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1213 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1215 status = dcerpc_send_request(p->conn, &blob, true);
1216 if (tevent_req_nterror(req, status)) {
1217 return tevent_req_post(req, ev);
1220 tevent_add_timer(ev, subreq,
1221 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1222 dcerpc_timeout_handler, subreq);
1224 return req;
1227 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1229 struct tevent_req *req =
1230 talloc_get_type_abort(subreq->async.private_data,
1231 struct tevent_req);
1232 struct dcerpc_bind_state *state =
1233 tevent_req_data(req,
1234 struct dcerpc_bind_state);
1235 NTSTATUS status = subreq->status;
1237 TALLOC_FREE(subreq);
1240 * We trigger the callback in the next event run
1241 * because the code in this file might trigger
1242 * multiple request callbacks from within a single
1243 * while loop.
1245 * In order to avoid segfaults from within
1246 * dcerpc_connection_dead() we call
1247 * tevent_req_defer_callback().
1249 tevent_req_defer_callback(req, state->ev);
1251 tevent_req_nterror(req, status);
1254 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1255 DATA_BLOB *raw_packet,
1256 struct ncacn_packet *pkt)
1258 struct tevent_req *req =
1259 talloc_get_type_abort(subreq->async.private_data,
1260 struct tevent_req);
1261 struct dcerpc_bind_state *state =
1262 tevent_req_data(req,
1263 struct dcerpc_bind_state);
1264 struct dcecli_connection *conn = state->p->conn;
1265 NTSTATUS status;
1268 * Note that pkt is allocated under raw_packet->data,
1269 * while raw_packet->data is a child of subreq.
1271 talloc_steal(state, raw_packet->data);
1272 TALLOC_FREE(subreq);
1275 * We trigger the callback in the next event run
1276 * because the code in this file might trigger
1277 * multiple request callbacks from within a single
1278 * while loop.
1280 * In order to avoid segfaults from within
1281 * dcerpc_connection_dead() we call
1282 * tevent_req_defer_callback().
1284 tevent_req_defer_callback(req, state->ev);
1286 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1287 status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason);
1289 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1290 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1292 tevent_req_nterror(req, status);
1293 return;
1296 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1297 (pkt->u.bind_ack.num_results == 0) ||
1298 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1299 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1300 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1301 return;
1305 * DCE-RPC 1.1 (c706) specifies
1306 * CONST_MUST_RCV_FRAG_SIZE as 1432
1308 if (pkt->u.bind_ack.max_xmit_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 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1314 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1315 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1316 return;
1318 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1319 pkt->u.bind_ack.max_xmit_frag);
1320 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1321 pkt->u.bind_ack.max_recv_frag);
1323 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1324 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1325 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1328 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1329 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1330 conn->flags |= DCERPC_HEADER_SIGNING;
1333 /* the bind_ack might contain a reply set of credentials */
1334 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1335 uint32_t auth_length;
1337 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1338 conn->security_state.auth_info, &auth_length, true);
1339 if (tevent_req_nterror(req, status)) {
1340 return;
1344 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1346 tevent_req_done(req);
1349 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1351 return tevent_req_simple_recv_ntstatus(req);
1355 perform a continued bind (and auth3)
1357 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1358 TALLOC_CTX *mem_ctx)
1360 struct ncacn_packet pkt;
1361 NTSTATUS status;
1362 DATA_BLOB blob;
1364 init_ncacn_hdr(p->conn, &pkt);
1366 pkt.ptype = DCERPC_PKT_AUTH3;
1367 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1368 pkt.call_id = next_call_id(p->conn);
1369 pkt.auth_length = 0;
1370 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1372 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1373 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1376 /* construct the NDR form of the packet */
1377 status = ncacn_push_auth(&blob, mem_ctx,
1378 &pkt,
1379 p->conn->security_state.auth_info);
1380 if (!NT_STATUS_IS_OK(status)) {
1381 return status;
1384 /* send it on its way */
1385 status = dcerpc_send_request(p->conn, &blob, false);
1386 if (!NT_STATUS_IS_OK(status)) {
1387 return status;
1390 return NT_STATUS_OK;
1395 process a fragment received from the transport layer during a
1396 request
1398 This function frees the data
1400 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1401 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1403 struct rpc_request *req;
1404 unsigned int length;
1405 NTSTATUS status = NT_STATUS_OK;
1408 if this is an authenticated connection then parse and check
1409 the auth info. We have to do this before finding the
1410 matching packet, as the request structure might have been
1411 removed due to a timeout, but if it has been we still need
1412 to run the auth routines so that we don't get the sign/seal
1413 info out of step with the server
1415 if (c->security_state.auth_info && c->security_state.generic_state &&
1416 pkt->ptype == DCERPC_PKT_RESPONSE) {
1417 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1420 /* find the matching request */
1421 for (req=c->pending;req;req=req->next) {
1422 if (pkt->call_id == req->call_id) break;
1425 #if 0
1426 /* useful for testing certain vendors RPC servers */
1427 if (req == NULL && c->pending && pkt->call_id == 0) {
1428 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1429 req = c->pending;
1431 #endif
1433 if (req == NULL) {
1434 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1435 data_blob_free(raw_packet);
1436 return;
1439 talloc_steal(req, raw_packet->data);
1441 if (req->recv_handler != NULL) {
1442 dcerpc_req_dequeue(req);
1443 req->state = RPC_REQUEST_DONE;
1446 * We have to look at shipping further requests before calling
1447 * the async function, that one might close the pipe
1449 dcerpc_schedule_io_trigger(c);
1451 req->recv_handler(req, raw_packet, pkt);
1452 return;
1455 if (pkt->ptype == DCERPC_PKT_FAULT) {
1456 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1457 req->fault_code = pkt->u.fault.status;
1458 req->status = NT_STATUS_NET_WRITE_FAULT;
1459 goto req_done;
1462 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1463 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1464 (int)pkt->ptype));
1465 req->fault_code = DCERPC_FAULT_OTHER;
1466 req->status = NT_STATUS_NET_WRITE_FAULT;
1467 goto req_done;
1470 /* now check the status from the auth routines, and if it failed then fail
1471 this request accordingly */
1472 if (!NT_STATUS_IS_OK(status)) {
1473 req->status = status;
1474 goto req_done;
1477 length = pkt->u.response.stub_and_verifier.length;
1479 if (length > 0) {
1480 req->payload.data = talloc_realloc(req,
1481 req->payload.data,
1482 uint8_t,
1483 req->payload.length + length);
1484 if (!req->payload.data) {
1485 req->status = NT_STATUS_NO_MEMORY;
1486 goto req_done;
1488 memcpy(req->payload.data+req->payload.length,
1489 pkt->u.response.stub_and_verifier.data, length);
1490 req->payload.length += length;
1493 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1494 data_blob_free(raw_packet);
1495 dcerpc_send_read(c);
1496 return;
1499 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1500 req->flags |= DCERPC_PULL_BIGENDIAN;
1501 } else {
1502 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1505 req_done:
1506 data_blob_free(raw_packet);
1508 /* we've got the full payload */
1509 dcerpc_req_dequeue(req);
1510 req->state = RPC_REQUEST_DONE;
1513 * We have to look at shipping further requests before calling
1514 * the async function, that one might close the pipe
1516 dcerpc_schedule_io_trigger(c);
1518 if (req->async.callback) {
1519 req->async.callback(req);
1524 perform the send side of a async dcerpc request
1526 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1527 struct dcerpc_pipe *p,
1528 const struct GUID *object,
1529 uint16_t opnum,
1530 DATA_BLOB *stub_data)
1532 struct rpc_request *req;
1534 p->conn->transport.recv_data = dcerpc_recv_data;
1536 req = talloc_zero(mem_ctx, struct rpc_request);
1537 if (req == NULL) {
1538 return NULL;
1541 req->p = p;
1542 req->call_id = next_call_id(p->conn);
1543 req->state = RPC_REQUEST_QUEUED;
1545 if (object != NULL) {
1546 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1547 if (req->object == NULL) {
1548 talloc_free(req);
1549 return NULL;
1553 req->opnum = opnum;
1554 req->request_data.length = stub_data->length;
1555 req->request_data.data = stub_data->data;
1557 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1558 talloc_set_destructor(req, dcerpc_req_dequeue);
1560 dcerpc_schedule_io_trigger(p->conn);
1562 if (p->request_timeout) {
1563 tevent_add_timer(dcerpc_event_context(p), req,
1564 timeval_current_ofs(p->request_timeout, 0),
1565 dcerpc_timeout_handler, req);
1568 return req;
1572 Send a request using the transport
1575 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1577 struct rpc_request *req;
1578 struct dcerpc_pipe *p;
1579 DATA_BLOB *stub_data;
1580 struct ncacn_packet pkt;
1581 DATA_BLOB blob;
1582 uint32_t remaining, chunk_size;
1583 bool first_packet = true;
1584 size_t sig_size = 0;
1585 bool need_async = false;
1586 bool can_async = true;
1588 req = c->request_queue;
1589 if (req == NULL) {
1590 return;
1593 p = req->p;
1594 stub_data = &req->request_data;
1596 if (c->pending) {
1597 need_async = true;
1600 if (c->security_state.auth_info &&
1601 c->security_state.generic_state)
1603 struct gensec_security *gensec = c->security_state.generic_state;
1605 switch (c->security_state.auth_info->auth_level) {
1606 case DCERPC_AUTH_LEVEL_PRIVACY:
1607 case DCERPC_AUTH_LEVEL_INTEGRITY:
1608 can_async = gensec_have_feature(gensec,
1609 GENSEC_FEATURE_ASYNC_REPLIES);
1610 break;
1611 case DCERPC_AUTH_LEVEL_CONNECT:
1612 case DCERPC_AUTH_LEVEL_NONE:
1613 can_async = true;
1614 break;
1615 default:
1616 can_async = false;
1617 break;
1621 if (need_async && !can_async) {
1622 req->wait_for_sync = true;
1623 return;
1626 DLIST_REMOVE(c->request_queue, req);
1627 DLIST_ADD(c->pending, req);
1628 req->state = RPC_REQUEST_PENDING;
1630 init_ncacn_hdr(p->conn, &pkt);
1632 remaining = stub_data->length;
1634 /* we can write a full max_recv_frag size, minus the dcerpc
1635 request header size */
1636 chunk_size = p->conn->srv_max_recv_frag;
1637 chunk_size -= DCERPC_REQUEST_LENGTH;
1638 if (c->security_state.auth_info &&
1639 c->security_state.generic_state) {
1640 sig_size = gensec_sig_size(c->security_state.generic_state,
1641 p->conn->srv_max_recv_frag);
1642 if (sig_size) {
1643 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1644 chunk_size -= sig_size;
1647 chunk_size -= (chunk_size % 16);
1649 pkt.ptype = DCERPC_PKT_REQUEST;
1650 pkt.call_id = req->call_id;
1651 pkt.auth_length = 0;
1652 pkt.pfc_flags = 0;
1653 pkt.u.request.context_id = p->context_id;
1654 pkt.u.request.opnum = req->opnum;
1656 if (req->object) {
1657 pkt.u.request.object.object = *req->object;
1658 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1659 chunk_size -= ndr_size_GUID(req->object,0);
1662 /* we send a series of pdus without waiting for a reply */
1663 while (remaining > 0 || first_packet) {
1664 uint32_t chunk = MIN(chunk_size, remaining);
1665 bool last_frag = false;
1666 bool do_trans = false;
1668 first_packet = false;
1669 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1671 if (remaining == stub_data->length) {
1672 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1674 if (chunk == remaining) {
1675 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1676 last_frag = true;
1679 pkt.u.request.alloc_hint = remaining;
1680 pkt.u.request.stub_and_verifier.data = stub_data->data +
1681 (stub_data->length - remaining);
1682 pkt.u.request.stub_and_verifier.length = chunk;
1684 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1685 if (!NT_STATUS_IS_OK(req->status)) {
1686 req->state = RPC_REQUEST_DONE;
1687 DLIST_REMOVE(p->conn->pending, req);
1688 return;
1691 if (last_frag && !need_async) {
1692 do_trans = true;
1695 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1696 if (!NT_STATUS_IS_OK(req->status)) {
1697 req->state = RPC_REQUEST_DONE;
1698 DLIST_REMOVE(p->conn->pending, req);
1699 return;
1702 if (last_frag && !do_trans) {
1703 req->status = dcerpc_send_read(p->conn);
1704 if (!NT_STATUS_IS_OK(req->status)) {
1705 req->state = RPC_REQUEST_DONE;
1706 DLIST_REMOVE(p->conn->pending, req);
1707 return;
1711 remaining -= chunk;
1715 static void dcerpc_io_trigger(struct tevent_context *ctx,
1716 struct tevent_immediate *im,
1717 void *private_data)
1719 struct dcecli_connection *c =
1720 talloc_get_type_abort(private_data,
1721 struct dcecli_connection);
1723 c->io_trigger_pending = false;
1725 dcerpc_schedule_io_trigger(c);
1727 dcerpc_ship_next_request(c);
1730 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1732 if (c->dead) {
1733 return;
1736 if (c->request_queue == NULL) {
1737 return;
1740 if (c->request_queue->wait_for_sync && c->pending) {
1741 return;
1744 if (c->io_trigger_pending) {
1745 return;
1748 c->io_trigger_pending = true;
1750 tevent_schedule_immediate(c->io_trigger,
1751 c->event_ctx,
1752 dcerpc_io_trigger,
1757 return the event context for a dcerpc pipe
1758 used by callers who wish to operate asynchronously
1760 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1762 return p->conn->event_ctx;
1768 perform the receive side of a async dcerpc request
1770 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1771 TALLOC_CTX *mem_ctx,
1772 DATA_BLOB *stub_data)
1774 NTSTATUS status;
1776 while (req->state != RPC_REQUEST_DONE) {
1777 struct tevent_context *ctx = dcerpc_event_context(req->p);
1778 if (tevent_loop_once(ctx) != 0) {
1779 return NT_STATUS_CONNECTION_DISCONNECTED;
1782 *stub_data = req->payload;
1783 status = req->status;
1784 if (stub_data->data) {
1785 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1787 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1788 req->p->last_fault_code = req->fault_code;
1790 talloc_unlink(talloc_parent(req), req);
1791 return status;
1795 this is a paranoid NDR validator. For every packet we push onto the wire
1796 we pull it back again, then push it again. Then we compare the raw NDR data
1797 for that to the NDR we initially generated. If they don't match then we know
1798 we must have a bug in either the pull or push side of our code
1800 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1801 TALLOC_CTX *mem_ctx,
1802 DATA_BLOB blob,
1803 size_t struct_size,
1804 ndr_push_flags_fn_t ndr_push,
1805 ndr_pull_flags_fn_t ndr_pull)
1807 void *st;
1808 struct ndr_pull *pull;
1809 struct ndr_push *push;
1810 DATA_BLOB blob2;
1811 enum ndr_err_code ndr_err;
1813 st = talloc_size(mem_ctx, struct_size);
1814 if (!st) {
1815 return NT_STATUS_NO_MEMORY;
1818 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1819 if (!pull) {
1820 return NT_STATUS_NO_MEMORY;
1822 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1824 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1825 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1828 if (c->flags & DCERPC_NDR64) {
1829 pull->flags |= LIBNDR_FLAG_NDR64;
1832 ndr_err = ndr_pull(pull, NDR_IN, st);
1833 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1834 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1835 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1836 "failed input validation pull - %s",
1837 nt_errstr(status));
1838 return ndr_map_error2ntstatus(ndr_err);
1841 push = ndr_push_init_ctx(mem_ctx);
1842 if (!push) {
1843 return NT_STATUS_NO_MEMORY;
1846 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1847 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1850 if (c->flags & DCERPC_NDR64) {
1851 push->flags |= LIBNDR_FLAG_NDR64;
1854 ndr_err = ndr_push(push, NDR_IN, st);
1855 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1856 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1857 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1858 "failed input validation push - %s",
1859 nt_errstr(status));
1860 return ndr_map_error2ntstatus(ndr_err);
1863 blob2 = ndr_push_blob(push);
1865 if (data_blob_cmp(&blob, &blob2) != 0) {
1866 DEBUG(3,("original:\n"));
1867 dump_data(3, blob.data, blob.length);
1868 DEBUG(3,("secondary:\n"));
1869 dump_data(3, blob2.data, blob2.length);
1870 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1871 "failed input validation blobs doesn't match");
1872 return ndr_map_error2ntstatus(ndr_err);
1875 return NT_STATUS_OK;
1879 this is a paranoid NDR input validator. For every packet we pull
1880 from the wire we push it back again then pull and push it
1881 again. Then we compare the raw NDR data for that to the NDR we
1882 initially generated. If they don't match then we know we must have a
1883 bug in either the pull or push side of our code
1885 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1886 struct ndr_pull *pull_in,
1887 void *struct_ptr,
1888 size_t struct_size,
1889 ndr_push_flags_fn_t ndr_push,
1890 ndr_pull_flags_fn_t ndr_pull,
1891 ndr_print_function_t ndr_print)
1893 void *st;
1894 struct ndr_pull *pull;
1895 struct ndr_push *push;
1896 DATA_BLOB blob, blob2;
1897 TALLOC_CTX *mem_ctx = pull_in;
1898 char *s1, *s2;
1899 enum ndr_err_code ndr_err;
1901 st = talloc_size(mem_ctx, struct_size);
1902 if (!st) {
1903 return NT_STATUS_NO_MEMORY;
1905 memcpy(st, struct_ptr, struct_size);
1907 push = ndr_push_init_ctx(mem_ctx);
1908 if (!push) {
1909 return NT_STATUS_NO_MEMORY;
1912 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1913 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1914 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1915 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1916 "failed output validation push - %s",
1917 nt_errstr(status));
1918 return ndr_map_error2ntstatus(ndr_err);
1921 blob = ndr_push_blob(push);
1923 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1924 if (!pull) {
1925 return NT_STATUS_NO_MEMORY;
1928 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1929 ndr_err = ndr_pull(pull, NDR_OUT, st);
1930 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1931 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1932 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1933 "failed output validation pull - %s",
1934 nt_errstr(status));
1935 return ndr_map_error2ntstatus(ndr_err);
1938 push = ndr_push_init_ctx(mem_ctx);
1939 if (!push) {
1940 return NT_STATUS_NO_MEMORY;
1943 ndr_err = ndr_push(push, NDR_OUT, st);
1944 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1945 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1946 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1947 "failed output validation push2 - %s",
1948 nt_errstr(status));
1949 return ndr_map_error2ntstatus(ndr_err);
1952 blob2 = ndr_push_blob(push);
1954 if (data_blob_cmp(&blob, &blob2) != 0) {
1955 DEBUG(3,("original:\n"));
1956 dump_data(3, blob.data, blob.length);
1957 DEBUG(3,("secondary:\n"));
1958 dump_data(3, blob2.data, blob2.length);
1959 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1960 "failed output validation blobs doesn't match");
1961 return ndr_map_error2ntstatus(ndr_err);
1964 /* this checks the printed forms of the two structures, which effectively
1965 tests all of the value() attributes */
1966 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1967 NDR_OUT, struct_ptr);
1968 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1969 NDR_OUT, st);
1970 if (strcmp(s1, s2) != 0) {
1971 #if 1
1972 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1973 #else
1974 /* this is sometimes useful */
1975 printf("VALIDATE ERROR\n");
1976 file_save("wire.dat", s1, strlen(s1));
1977 file_save("gen.dat", s2, strlen(s2));
1978 system("diff -u wire.dat gen.dat");
1979 #endif
1980 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1981 "failed output validation strings doesn't match");
1982 return ndr_map_error2ntstatus(ndr_err);
1985 return NT_STATUS_OK;
1989 a useful function for retrieving the server name we connected to
1991 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1993 return p->conn ? p->conn->server_name : NULL;
1998 get the dcerpc auth_level for a open connection
2000 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2002 uint8_t auth_level;
2004 if (c->flags & DCERPC_SEAL) {
2005 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2006 } else if (c->flags & DCERPC_SIGN) {
2007 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2008 } else if (c->flags & DCERPC_CONNECT) {
2009 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2010 } else {
2011 auth_level = DCERPC_AUTH_LEVEL_NONE;
2013 return auth_level;
2016 struct dcerpc_alter_context_state {
2017 struct tevent_context *ev;
2018 struct dcerpc_pipe *p;
2021 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2022 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2023 DATA_BLOB *raw_packet,
2024 struct ncacn_packet *pkt);
2026 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2027 struct tevent_context *ev,
2028 struct dcerpc_pipe *p,
2029 const struct ndr_syntax_id *syntax,
2030 const struct ndr_syntax_id *transfer_syntax)
2032 struct tevent_req *req;
2033 struct dcerpc_alter_context_state *state;
2034 struct ncacn_packet pkt;
2035 DATA_BLOB blob;
2036 NTSTATUS status;
2037 struct rpc_request *subreq;
2039 req = tevent_req_create(mem_ctx, &state,
2040 struct dcerpc_alter_context_state);
2041 if (req == NULL) {
2042 return NULL;
2045 state->ev = ev;
2046 state->p = p;
2048 p->syntax = *syntax;
2049 p->transfer_syntax = *transfer_syntax;
2051 init_ncacn_hdr(p->conn, &pkt);
2053 pkt.ptype = DCERPC_PKT_ALTER;
2054 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2055 pkt.call_id = p->conn->call_id;
2056 pkt.auth_length = 0;
2058 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
2059 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2062 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2063 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2064 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
2065 pkt.u.alter.num_contexts = 1;
2066 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2067 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2068 return tevent_req_post(req, ev);
2070 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2071 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2072 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2073 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2074 pkt.u.alter.auth_info = data_blob(NULL, 0);
2076 /* construct the NDR form of the packet */
2077 status = ncacn_push_auth(&blob, state, &pkt,
2078 p->conn->security_state.auth_info);
2079 if (tevent_req_nterror(req, status)) {
2080 return tevent_req_post(req, ev);
2083 p->conn->transport.recv_data = dcerpc_recv_data;
2086 * we allocate a dcerpc_request so we can be in the same
2087 * request queue as normal requests
2089 subreq = talloc_zero(state, struct rpc_request);
2090 if (tevent_req_nomem(subreq, req)) {
2091 return tevent_req_post(req, ev);
2094 subreq->state = RPC_REQUEST_PENDING;
2095 subreq->call_id = pkt.call_id;
2096 subreq->async.private_data = req;
2097 subreq->async.callback = dcerpc_alter_context_fail_handler;
2098 subreq->p = p;
2099 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2100 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2101 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2103 status = dcerpc_send_request(p->conn, &blob, true);
2104 if (tevent_req_nterror(req, status)) {
2105 return tevent_req_post(req, ev);
2108 tevent_add_timer(ev, subreq,
2109 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2110 dcerpc_timeout_handler, subreq);
2112 return req;
2115 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2117 struct tevent_req *req =
2118 talloc_get_type_abort(subreq->async.private_data,
2119 struct tevent_req);
2120 struct dcerpc_alter_context_state *state =
2121 tevent_req_data(req,
2122 struct dcerpc_alter_context_state);
2123 NTSTATUS status = subreq->status;
2125 TALLOC_FREE(subreq);
2128 * We trigger the callback in the next event run
2129 * because the code in this file might trigger
2130 * multiple request callbacks from within a single
2131 * while loop.
2133 * In order to avoid segfaults from within
2134 * dcerpc_connection_dead() we call
2135 * tevent_req_defer_callback().
2137 tevent_req_defer_callback(req, state->ev);
2139 tevent_req_nterror(req, status);
2142 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2143 DATA_BLOB *raw_packet,
2144 struct ncacn_packet *pkt)
2146 struct tevent_req *req =
2147 talloc_get_type_abort(subreq->async.private_data,
2148 struct tevent_req);
2149 struct dcerpc_alter_context_state *state =
2150 tevent_req_data(req,
2151 struct dcerpc_alter_context_state);
2152 struct dcecli_connection *conn = state->p->conn;
2153 NTSTATUS status;
2156 * Note that pkt is allocated under raw_packet->data,
2157 * while raw_packet->data is a child of subreq.
2159 talloc_steal(state, raw_packet->data);
2160 TALLOC_FREE(subreq);
2163 * We trigger the callback in the next event run
2164 * because the code in this file might trigger
2165 * multiple request callbacks from within a single
2166 * while loop.
2168 * In order to avoid segfaults from within
2169 * dcerpc_connection_dead() we call
2170 * tevent_req_defer_callback().
2172 tevent_req_defer_callback(req, state->ev);
2174 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2175 pkt->u.alter_resp.num_results == 1 &&
2176 pkt->u.alter_resp.ctx_list[0].result != 0) {
2177 status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason);
2178 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2179 pkt->u.alter_resp.ctx_list[0].reason,
2180 nt_errstr(status)));
2181 tevent_req_nterror(req, status);
2182 return;
2185 if (pkt->ptype == DCERPC_PKT_FAULT) {
2186 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2187 dcerpc_errstr(state, pkt->u.fault.status)));
2188 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2189 state->p->last_fault_code = pkt->u.fault.status;
2190 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2191 } else {
2192 state->p->last_fault_code = pkt->u.fault.status;
2193 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2195 return;
2198 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2199 pkt->u.alter_resp.num_results == 0 ||
2200 pkt->u.alter_resp.ctx_list[0].result != 0) {
2201 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2202 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2203 return;
2206 /* the alter_resp might contain a reply set of credentials */
2207 if (conn->security_state.auth_info &&
2208 pkt->u.alter_resp.auth_info.length) {
2209 uint32_t auth_length;
2211 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2212 conn->security_state.auth_info, &auth_length, true);
2213 if (tevent_req_nterror(req, status)) {
2214 return;
2218 tevent_req_done(req);
2221 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2223 return tevent_req_simple_recv_ntstatus(req);
2227 send a dcerpc alter_context request
2229 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2230 TALLOC_CTX *mem_ctx,
2231 const struct ndr_syntax_id *syntax,
2232 const struct ndr_syntax_id *transfer_syntax)
2234 struct tevent_req *subreq;
2235 struct tevent_context *ev = p->conn->event_ctx;
2236 bool ok;
2238 /* TODO: create a new event context here */
2240 subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx,
2241 p, syntax, transfer_syntax);
2242 if (subreq == NULL) {
2243 return NT_STATUS_NO_MEMORY;
2246 ok = tevent_req_poll(subreq, ev);
2247 if (!ok) {
2248 NTSTATUS status;
2249 status = map_nt_error_from_unix_common(errno);
2250 return status;
2253 return dcerpc_alter_context_recv(subreq);
2256 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2258 if (c->transport.stream == NULL) {
2259 return;
2262 tevent_queue_stop(c->transport.write_queue);
2263 TALLOC_FREE(c->transport.read_subreq);
2264 TALLOC_FREE(c->transport.stream);
2266 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2267 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2270 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2271 status = NT_STATUS_END_OF_FILE;
2274 if (c->transport.recv_data) {
2275 c->transport.recv_data(c, NULL, status);
2281 shutdown SMB pipe connection
2283 struct dcerpc_shutdown_pipe_state {
2284 struct dcecli_connection *c;
2285 NTSTATUS status;
2288 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2290 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2292 struct dcerpc_shutdown_pipe_state *state;
2293 struct tevent_req *subreq;
2295 if (c->transport.stream == NULL) {
2296 return NT_STATUS_OK;
2299 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2300 if (state == NULL) {
2301 return NT_STATUS_NO_MEMORY;
2303 state->c = c;
2304 state->status = status;
2306 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2307 if (subreq == NULL) {
2308 return NT_STATUS_NO_MEMORY;
2310 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2312 return status;
2315 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2317 struct dcerpc_shutdown_pipe_state *state =
2318 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2319 struct dcecli_connection *c = state->c;
2320 NTSTATUS status = state->status;
2321 int error;
2324 * here we ignore the return values...
2326 tstream_disconnect_recv(subreq, &error);
2327 TALLOC_FREE(subreq);
2329 TALLOC_FREE(state);
2331 dcerpc_transport_dead(c, status);
2336 struct dcerpc_send_read_state {
2337 struct dcecli_connection *p;
2340 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2342 struct dcecli_connection *p = state->p;
2344 p->transport.read_subreq = NULL;
2346 return 0;
2349 static void dcerpc_send_read_done(struct tevent_req *subreq);
2351 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2353 struct dcerpc_send_read_state *state;
2355 if (p->transport.read_subreq != NULL) {
2356 p->transport.pending_reads++;
2357 return NT_STATUS_OK;
2360 state = talloc_zero(p, struct dcerpc_send_read_state);
2361 if (state == NULL) {
2362 return NT_STATUS_NO_MEMORY;
2364 state->p = p;
2366 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2368 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2369 p->event_ctx,
2370 p->transport.stream);
2371 if (p->transport.read_subreq == NULL) {
2372 return NT_STATUS_NO_MEMORY;
2374 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2376 return NT_STATUS_OK;
2379 static void dcerpc_send_read_done(struct tevent_req *subreq)
2381 struct dcerpc_send_read_state *state =
2382 tevent_req_callback_data(subreq,
2383 struct dcerpc_send_read_state);
2384 struct dcecli_connection *p = state->p;
2385 NTSTATUS status;
2386 struct ncacn_packet *pkt;
2387 DATA_BLOB blob;
2389 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2390 &pkt, &blob);
2391 TALLOC_FREE(subreq);
2392 if (!NT_STATUS_IS_OK(status)) {
2393 TALLOC_FREE(state);
2394 dcerpc_transport_dead(p, status);
2395 return;
2399 * here we steal into thet connection context,
2400 * but p->transport.recv_data() will steal or free it again
2402 talloc_steal(p, blob.data);
2403 TALLOC_FREE(state);
2405 if (p->transport.pending_reads > 0) {
2406 p->transport.pending_reads--;
2408 status = dcerpc_send_read(p);
2409 if (!NT_STATUS_IS_OK(status)) {
2410 dcerpc_transport_dead(p, status);
2411 return;
2415 if (p->transport.recv_data) {
2416 p->transport.recv_data(p, &blob, NT_STATUS_OK);
2420 struct dcerpc_send_request_state {
2421 struct dcecli_connection *p;
2422 DATA_BLOB blob;
2423 struct iovec iov;
2426 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2428 struct dcecli_connection *p = state->p;
2430 p->transport.read_subreq = NULL;
2432 return 0;
2435 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2436 static void dcerpc_send_request_done(struct tevent_req *subreq);
2438 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2439 bool trigger_read)
2441 struct dcerpc_send_request_state *state;
2442 struct tevent_req *subreq;
2443 bool use_trans = trigger_read;
2445 if (p->transport.stream == NULL) {
2446 return NT_STATUS_CONNECTION_DISCONNECTED;
2449 state = talloc_zero(p, struct dcerpc_send_request_state);
2450 if (state == NULL) {
2451 return NT_STATUS_NO_MEMORY;
2453 state->p = p;
2455 state->blob = data_blob_talloc(state, data->data, data->length);
2456 if (state->blob.data == NULL) {
2457 TALLOC_FREE(state);
2458 return NT_STATUS_NO_MEMORY;
2460 state->iov.iov_base = (void *)state->blob.data;
2461 state->iov.iov_len = state->blob.length;
2463 if (p->transport.read_subreq != NULL) {
2464 use_trans = false;
2467 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2468 use_trans = false;
2471 if (use_trans) {
2473 * we need to block reads until our write is
2474 * the next in the write queue.
2476 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2477 p->transport.write_queue);
2478 if (p->transport.read_subreq == NULL) {
2479 TALLOC_FREE(state);
2480 return NT_STATUS_NO_MEMORY;
2482 tevent_req_set_callback(p->transport.read_subreq,
2483 dcerpc_send_request_wait_done,
2484 state);
2486 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2488 trigger_read = false;
2491 subreq = tstream_writev_queue_send(state, p->event_ctx,
2492 p->transport.stream,
2493 p->transport.write_queue,
2494 &state->iov, 1);
2495 if (subreq == NULL) {
2496 TALLOC_FREE(state);
2497 return NT_STATUS_NO_MEMORY;
2499 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2501 if (trigger_read) {
2502 dcerpc_send_read(p);
2505 return NT_STATUS_OK;
2508 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2510 struct dcerpc_send_request_state *state =
2511 tevent_req_callback_data(subreq,
2512 struct dcerpc_send_request_state);
2513 struct dcecli_connection *p = state->p;
2514 NTSTATUS status;
2515 bool ok;
2517 p->transport.read_subreq = NULL;
2518 talloc_set_destructor(state, NULL);
2520 ok = tevent_queue_wait_recv(subreq);
2521 if (!ok) {
2522 TALLOC_FREE(state);
2523 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2524 return;
2527 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2528 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2529 if (!NT_STATUS_IS_OK(status)) {
2530 TALLOC_FREE(state);
2531 dcerpc_transport_dead(p, status);
2532 return;
2536 /* we free subreq after tstream_cli_np_use_trans */
2537 TALLOC_FREE(subreq);
2539 dcerpc_send_read(p);
2542 static void dcerpc_send_request_done(struct tevent_req *subreq)
2544 struct dcerpc_send_request_state *state =
2545 tevent_req_callback_data(subreq,
2546 struct dcerpc_send_request_state);
2547 int ret;
2548 int error;
2550 ret = tstream_writev_queue_recv(subreq, &error);
2551 TALLOC_FREE(subreq);
2552 if (ret == -1) {
2553 struct dcecli_connection *p = state->p;
2554 NTSTATUS status = map_nt_error_from_unix_common(error);
2556 TALLOC_FREE(state);
2557 dcerpc_transport_dead(p, status);
2558 return;
2561 TALLOC_FREE(state);