s4:librpc/rpc: convert dcerpc_alter_context_send/recv to tevent_req
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blob9e7abecf9ba3c6949890af4d31603418722f00c3
1 /*
2 Unix SMB/CIFS implementation.
3 raw dcerpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "auth/gensec/gensec.h"
31 #include "param/param.h"
32 #include "lib/util/tevent_ntstatus.h"
33 #include "librpc/rpc/rpc_common.h"
35 enum rpc_request_state {
36 RPC_REQUEST_QUEUED,
37 RPC_REQUEST_PENDING,
38 RPC_REQUEST_DONE
42 handle for an async dcerpc request
44 struct rpc_request {
45 struct rpc_request *next, *prev;
46 struct dcerpc_pipe *p;
47 NTSTATUS status;
48 uint32_t call_id;
49 enum rpc_request_state state;
50 DATA_BLOB payload;
51 uint32_t flags;
52 uint32_t fault_code;
54 /* this is used to distinguish bind and alter_context requests
55 from normal requests */
56 void (*recv_handler)(struct rpc_request *conn,
57 DATA_BLOB *blob, struct ncacn_packet *pkt);
59 const struct GUID *object;
60 uint16_t opnum;
61 DATA_BLOB request_data;
62 bool ignore_timeout;
64 /* use by the ndr level async recv call */
65 struct {
66 const struct ndr_interface_table *table;
67 uint32_t opnum;
68 void *struct_ptr;
69 TALLOC_CTX *mem_ctx;
70 } ndr;
72 struct {
73 void (*callback)(struct rpc_request *);
74 void *private_data;
75 } async;
78 _PUBLIC_ NTSTATUS dcerpc_init(void)
80 return gensec_init();
83 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
84 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
86 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
87 const struct GUID *object,
88 uint16_t opnum,
89 DATA_BLOB *stub_data);
90 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
91 TALLOC_CTX *mem_ctx,
92 DATA_BLOB *stub_data);
93 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
94 TALLOC_CTX *mem_ctx,
95 DATA_BLOB blob,
96 size_t struct_size,
97 ndr_push_flags_fn_t ndr_push,
98 ndr_pull_flags_fn_t ndr_pull);
99 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
100 struct ndr_pull *pull_in,
101 void *struct_ptr,
102 size_t struct_size,
103 ndr_push_flags_fn_t ndr_push,
104 ndr_pull_flags_fn_t ndr_pull,
105 ndr_print_function_t ndr_print);
107 /* destroy a dcerpc connection */
108 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
110 if (conn->dead) {
111 conn->free_skipped = true;
112 return -1;
114 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
115 return 0;
119 /* initialise a dcerpc connection.
120 the event context is optional
122 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
123 struct tevent_context *ev)
125 struct dcecli_connection *c;
127 c = talloc_zero(mem_ctx, struct dcecli_connection);
128 if (!c) {
129 return NULL;
132 c->event_ctx = ev;
134 if (c->event_ctx == NULL) {
135 talloc_free(c);
136 return NULL;
139 c->call_id = 1;
140 c->security_state.auth_info = NULL;
141 c->security_state.session_key = dcerpc_generic_session_key;
142 c->security_state.generic_state = NULL;
143 c->binding_string = NULL;
144 c->flags = 0;
145 c->srv_max_xmit_frag = 0;
146 c->srv_max_recv_frag = 0;
147 c->pending = NULL;
149 c->io_trigger = tevent_create_immediate(c);
150 if (c->io_trigger == NULL) {
151 talloc_free(c);
152 return NULL;
155 talloc_set_destructor(c, dcerpc_connection_destructor);
157 return c;
160 struct dcerpc_bh_state {
161 struct dcerpc_pipe *p;
164 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
166 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
167 struct dcerpc_bh_state);
169 if (!hs->p) {
170 return false;
173 if (!hs->p->conn) {
174 return false;
177 if (hs->p->conn->dead) {
178 return false;
181 return true;
184 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
185 uint32_t timeout)
187 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
188 struct dcerpc_bh_state);
189 uint32_t old;
191 if (!hs->p) {
192 return DCERPC_REQUEST_TIMEOUT;
195 old = hs->p->request_timeout;
196 hs->p->request_timeout = timeout;
198 return old;
201 struct dcerpc_bh_raw_call_state {
202 struct tevent_context *ev;
203 struct dcerpc_binding_handle *h;
204 DATA_BLOB in_data;
205 DATA_BLOB out_data;
206 uint32_t out_flags;
209 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
211 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
212 struct tevent_context *ev,
213 struct dcerpc_binding_handle *h,
214 const struct GUID *object,
215 uint32_t opnum,
216 uint32_t in_flags,
217 const uint8_t *in_data,
218 size_t in_length)
220 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
221 struct dcerpc_bh_state);
222 struct tevent_req *req;
223 struct dcerpc_bh_raw_call_state *state;
224 bool ok;
225 struct rpc_request *subreq;
227 req = tevent_req_create(mem_ctx, &state,
228 struct dcerpc_bh_raw_call_state);
229 if (req == NULL) {
230 return NULL;
232 state->ev = ev;
233 state->h = h;
234 state->in_data.data = discard_const_p(uint8_t, in_data);
235 state->in_data.length = in_length;
237 ok = dcerpc_bh_is_connected(h);
238 if (!ok) {
239 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
240 return tevent_req_post(req, ev);
243 subreq = dcerpc_request_send(hs->p,
244 object,
245 opnum,
246 &state->in_data);
247 if (tevent_req_nomem(subreq, req)) {
248 return tevent_req_post(req, ev);
250 subreq->async.callback = dcerpc_bh_raw_call_done;
251 subreq->async.private_data = req;
253 return req;
256 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
258 struct tevent_req *req =
259 talloc_get_type_abort(subreq->async.private_data,
260 struct tevent_req);
261 struct dcerpc_bh_raw_call_state *state =
262 tevent_req_data(req,
263 struct dcerpc_bh_raw_call_state);
264 NTSTATUS status;
265 uint32_t fault_code;
267 state->out_flags = 0;
268 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
269 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
272 fault_code = subreq->fault_code;
274 status = dcerpc_request_recv(subreq, state, &state->out_data);
275 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
276 status = dcerpc_fault_to_nt_status(fault_code);
280 * We trigger the callback in the next event run
281 * because the code in this file might trigger
282 * multiple request callbacks from within a single
283 * while loop.
285 * In order to avoid segfaults from within
286 * dcerpc_connection_dead() we call
287 * tevent_req_defer_callback().
289 tevent_req_defer_callback(req, state->ev);
291 if (!NT_STATUS_IS_OK(status)) {
292 tevent_req_nterror(req, status);
293 return;
296 tevent_req_done(req);
299 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
300 TALLOC_CTX *mem_ctx,
301 uint8_t **out_data,
302 size_t *out_length,
303 uint32_t *out_flags)
305 struct dcerpc_bh_raw_call_state *state =
306 tevent_req_data(req,
307 struct dcerpc_bh_raw_call_state);
308 NTSTATUS status;
310 if (tevent_req_is_nterror(req, &status)) {
311 tevent_req_received(req);
312 return status;
315 *out_data = talloc_move(mem_ctx, &state->out_data.data);
316 *out_length = state->out_data.length;
317 *out_flags = state->out_flags;
318 tevent_req_received(req);
319 return NT_STATUS_OK;
322 struct dcerpc_bh_disconnect_state {
323 uint8_t _dummy;
326 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
327 struct tevent_context *ev,
328 struct dcerpc_binding_handle *h)
330 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
331 struct dcerpc_bh_state);
332 struct tevent_req *req;
333 struct dcerpc_bh_disconnect_state *state;
334 bool ok;
336 req = tevent_req_create(mem_ctx, &state,
337 struct dcerpc_bh_disconnect_state);
338 if (req == NULL) {
339 return NULL;
342 ok = dcerpc_bh_is_connected(h);
343 if (!ok) {
344 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
345 return tevent_req_post(req, ev);
348 /* TODO: do a real disconnect ... */
349 hs->p = NULL;
351 tevent_req_done(req);
352 return tevent_req_post(req, ev);
355 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
357 NTSTATUS status;
359 if (tevent_req_is_nterror(req, &status)) {
360 tevent_req_received(req);
361 return status;
364 tevent_req_received(req);
365 return NT_STATUS_OK;
368 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
370 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
371 struct dcerpc_bh_state);
373 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
374 return true;
377 return false;
380 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
382 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
383 struct dcerpc_bh_state);
385 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
386 return true;
389 return false;
392 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
394 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
395 struct dcerpc_bh_state);
397 if (hs->p->conn->flags & DCERPC_NDR64) {
398 return true;
401 return false;
404 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
405 int ndr_flags,
406 const void *_struct_ptr,
407 const struct ndr_interface_call *call)
409 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
410 struct dcerpc_bh_state);
411 void *struct_ptr = discard_const(_struct_ptr);
413 if (ndr_flags & NDR_IN) {
414 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
415 ndr_print_function_debug(call->ndr_print,
416 call->name,
417 ndr_flags,
418 struct_ptr);
421 if (ndr_flags & NDR_OUT) {
422 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
423 ndr_print_function_debug(call->ndr_print,
424 call->name,
425 ndr_flags,
426 struct_ptr);
431 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
432 NTSTATUS error,
433 const void *struct_ptr,
434 const struct ndr_interface_call *call)
436 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
437 call->name, nt_errstr(error)));
440 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
441 NTSTATUS error,
442 const DATA_BLOB *blob,
443 const struct ndr_interface_call *call)
445 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
446 struct dcerpc_bh_state);
447 const uint32_t num_examples = 20;
448 uint32_t i;
450 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
451 call->name, nt_errstr(error)));
453 if (hs->p->conn->packet_log_dir == NULL) return;
455 for (i=0;i<num_examples;i++) {
456 char *name=NULL;
457 asprintf(&name, "%s/rpclog/%s-out.%d",
458 hs->p->conn->packet_log_dir,
459 call->name, i);
460 if (name == NULL) {
461 return;
463 if (!file_exist(name)) {
464 if (file_save(name, blob->data, blob->length)) {
465 DEBUG(10,("Logged rpc packet to %s\n", name));
467 free(name);
468 break;
470 free(name);
474 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
475 TALLOC_CTX *mem_ctx,
476 const DATA_BLOB *blob,
477 const struct ndr_interface_call *call)
479 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
480 struct dcerpc_bh_state);
482 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
483 NTSTATUS status;
485 status = dcerpc_ndr_validate_in(hs->p->conn,
486 mem_ctx,
487 *blob,
488 call->struct_size,
489 call->ndr_push,
490 call->ndr_pull);
491 if (!NT_STATUS_IS_OK(status)) {
492 DEBUG(0,("Validation [in] failed for %s - %s\n",
493 call->name, nt_errstr(status)));
494 return status;
498 DEBUG(10,("rpc request data:\n"));
499 dump_data(10, blob->data, blob->length);
501 return NT_STATUS_OK;
504 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
505 struct ndr_pull *pull_in,
506 const void *_struct_ptr,
507 const struct ndr_interface_call *call)
509 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
510 struct dcerpc_bh_state);
511 void *struct_ptr = discard_const(_struct_ptr);
513 DEBUG(10,("rpc reply data:\n"));
514 dump_data(10, pull_in->data, pull_in->data_size);
516 if (pull_in->offset != pull_in->data_size) {
517 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
518 pull_in->data_size - pull_in->offset,
519 pull_in->offset, pull_in->offset,
520 call->name));
521 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
522 but it turns out that early versions of NT
523 (specifically NT3.1) add junk onto the end of rpc
524 packets, so if we want to interoperate at all with
525 those versions then we need to ignore this error */
528 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
529 NTSTATUS status;
531 status = dcerpc_ndr_validate_out(hs->p->conn,
532 pull_in,
533 struct_ptr,
534 call->struct_size,
535 call->ndr_push,
536 call->ndr_pull,
537 call->ndr_print);
538 if (!NT_STATUS_IS_OK(status)) {
539 DEBUG(2,("Validation [out] failed for %s - %s\n",
540 call->name, nt_errstr(status)));
541 return status;
545 return NT_STATUS_OK;
548 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
549 .name = "dcerpc",
550 .is_connected = dcerpc_bh_is_connected,
551 .set_timeout = dcerpc_bh_set_timeout,
552 .raw_call_send = dcerpc_bh_raw_call_send,
553 .raw_call_recv = dcerpc_bh_raw_call_recv,
554 .disconnect_send = dcerpc_bh_disconnect_send,
555 .disconnect_recv = dcerpc_bh_disconnect_recv,
557 .push_bigendian = dcerpc_bh_push_bigendian,
558 .ref_alloc = dcerpc_bh_ref_alloc,
559 .use_ndr64 = dcerpc_bh_use_ndr64,
560 .do_ndr_print = dcerpc_bh_do_ndr_print,
561 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
562 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
563 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
564 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
567 /* initialise a dcerpc pipe. */
568 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
570 struct dcerpc_binding_handle *h;
571 struct dcerpc_bh_state *hs;
573 h = dcerpc_binding_handle_create(p,
574 &dcerpc_bh_ops,
575 NULL,
576 NULL, /* TODO */
577 &hs,
578 struct dcerpc_bh_state,
579 __location__);
580 if (h == NULL) {
581 return NULL;
583 hs->p = p;
585 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
587 return h;
590 /* initialise a dcerpc pipe. */
591 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
593 struct dcerpc_pipe *p;
595 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
596 if (!p) {
597 return NULL;
600 p->conn = dcerpc_connection_init(p, ev);
601 if (p->conn == NULL) {
602 talloc_free(p);
603 return NULL;
606 p->last_fault_code = 0;
607 p->context_id = 0;
608 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
609 p->binding = NULL;
611 ZERO_STRUCT(p->syntax);
612 ZERO_STRUCT(p->transfer_syntax);
614 if (DEBUGLVL(100)) {
615 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
618 p->binding_handle = dcerpc_pipe_binding_handle(p);
619 if (p->binding_handle == NULL) {
620 talloc_free(p);
621 return NULL;
624 return p;
629 choose the next call id to use
631 static uint32_t next_call_id(struct dcecli_connection *c)
633 c->call_id++;
634 if (c->call_id == 0) {
635 c->call_id++;
637 return c->call_id;
641 setup for a ndr pull, also setting up any flags from the binding string
643 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
644 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
646 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
648 if (ndr == NULL) return ndr;
650 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
651 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
654 if (c->flags & DCERPC_NDR_REF_ALLOC) {
655 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
658 if (c->flags & DCERPC_NDR64) {
659 ndr->flags |= LIBNDR_FLAG_NDR64;
662 return ndr;
666 parse a data blob into a ncacn_packet structure. This handles both
667 input and output packets
669 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
670 struct ncacn_packet *pkt)
672 struct ndr_pull *ndr;
673 enum ndr_err_code ndr_err;
675 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
676 if (!ndr) {
677 return NT_STATUS_NO_MEMORY;
680 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
681 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
684 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
685 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
686 return ndr_map_error2ntstatus(ndr_err);
689 return NT_STATUS_OK;
693 parse the authentication information on a dcerpc response packet
695 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
696 DATA_BLOB *raw_packet,
697 struct ncacn_packet *pkt)
699 NTSTATUS status;
700 struct dcerpc_auth auth;
701 uint32_t auth_length;
703 if (!c->security_state.auth_info ||
704 !c->security_state.generic_state) {
705 return NT_STATUS_OK;
708 switch (c->security_state.auth_info->auth_level) {
709 case DCERPC_AUTH_LEVEL_PRIVACY:
710 case DCERPC_AUTH_LEVEL_INTEGRITY:
711 break;
713 case DCERPC_AUTH_LEVEL_CONNECT:
714 if (pkt->auth_length != 0) {
715 break;
717 return NT_STATUS_OK;
718 case DCERPC_AUTH_LEVEL_NONE:
719 if (pkt->auth_length != 0) {
720 return NT_STATUS_INVALID_NETWORK_RESPONSE;
722 return NT_STATUS_OK;
724 default:
725 return NT_STATUS_INVALID_LEVEL;
728 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
729 &pkt->u.response.stub_and_verifier,
730 &auth, &auth_length, false);
731 NT_STATUS_NOT_OK_RETURN(status);
733 pkt->u.response.stub_and_verifier.length -= auth_length;
735 /* check signature or unseal the packet */
736 switch (c->security_state.auth_info->auth_level) {
737 case DCERPC_AUTH_LEVEL_PRIVACY:
738 status = gensec_unseal_packet(c->security_state.generic_state,
739 raw_packet->data + DCERPC_REQUEST_LENGTH,
740 pkt->u.response.stub_and_verifier.length,
741 raw_packet->data,
742 raw_packet->length - auth.credentials.length,
743 &auth.credentials);
744 memcpy(pkt->u.response.stub_and_verifier.data,
745 raw_packet->data + DCERPC_REQUEST_LENGTH,
746 pkt->u.response.stub_and_verifier.length);
747 break;
749 case DCERPC_AUTH_LEVEL_INTEGRITY:
750 status = gensec_check_packet(c->security_state.generic_state,
751 pkt->u.response.stub_and_verifier.data,
752 pkt->u.response.stub_and_verifier.length,
753 raw_packet->data,
754 raw_packet->length - auth.credentials.length,
755 &auth.credentials);
756 break;
758 case DCERPC_AUTH_LEVEL_CONNECT:
759 /* for now we ignore possible signatures here */
760 status = NT_STATUS_OK;
761 break;
763 default:
764 status = NT_STATUS_INVALID_LEVEL;
765 break;
768 /* remove the indicated amount of padding */
769 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
770 return NT_STATUS_INFO_LENGTH_MISMATCH;
772 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
774 return status;
779 push a dcerpc request packet into a blob, possibly signing it.
781 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
782 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
783 size_t sig_size,
784 struct ncacn_packet *pkt)
786 NTSTATUS status;
787 struct ndr_push *ndr;
788 DATA_BLOB creds2;
789 size_t payload_length;
790 enum ndr_err_code ndr_err;
791 size_t hdr_size = DCERPC_REQUEST_LENGTH;
793 /* non-signed packets are simpler */
794 if (sig_size == 0) {
795 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
798 switch (c->security_state.auth_info->auth_level) {
799 case DCERPC_AUTH_LEVEL_PRIVACY:
800 case DCERPC_AUTH_LEVEL_INTEGRITY:
801 break;
803 case DCERPC_AUTH_LEVEL_CONNECT:
804 /* TODO: let the gensec mech decide if it wants to generate a signature */
805 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
807 case DCERPC_AUTH_LEVEL_NONE:
808 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
810 default:
811 return NT_STATUS_INVALID_LEVEL;
814 ndr = ndr_push_init_ctx(mem_ctx);
815 if (!ndr) {
816 return NT_STATUS_NO_MEMORY;
819 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
820 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
823 if (c->flags & DCERPC_NDR64) {
824 ndr->flags |= LIBNDR_FLAG_NDR64;
827 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
828 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
829 hdr_size += 16;
832 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
833 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
834 return ndr_map_error2ntstatus(ndr_err);
837 /* pad to 16 byte multiple in the payload portion of the
838 packet. This matches what w2k3 does. Note that we can't use
839 ndr_push_align() as that is relative to the start of the
840 whole packet, whereas w2k8 wants it relative to the start
841 of the stub */
842 c->security_state.auth_info->auth_pad_length =
843 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
844 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
845 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
846 return ndr_map_error2ntstatus(ndr_err);
849 payload_length = pkt->u.request.stub_and_verifier.length +
850 c->security_state.auth_info->auth_pad_length;
852 /* we start without signature, it will appended later */
853 c->security_state.auth_info->credentials = data_blob(NULL,0);
855 /* add the auth verifier */
856 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
857 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
858 return ndr_map_error2ntstatus(ndr_err);
861 /* extract the whole packet as a blob */
862 *blob = ndr_push_blob(ndr);
865 * Setup the frag and auth length in the packet buffer.
866 * This is needed if the GENSEC mech does AEAD signing
867 * of the packet headers. The signature itself will be
868 * appended later.
870 dcerpc_set_frag_length(blob, blob->length + sig_size);
871 dcerpc_set_auth_length(blob, sig_size);
873 /* sign or seal the packet */
874 switch (c->security_state.auth_info->auth_level) {
875 case DCERPC_AUTH_LEVEL_PRIVACY:
876 status = gensec_seal_packet(c->security_state.generic_state,
877 mem_ctx,
878 blob->data + hdr_size,
879 payload_length,
880 blob->data,
881 blob->length,
882 &creds2);
883 if (!NT_STATUS_IS_OK(status)) {
884 return status;
886 break;
888 case DCERPC_AUTH_LEVEL_INTEGRITY:
889 status = gensec_sign_packet(c->security_state.generic_state,
890 mem_ctx,
891 blob->data + hdr_size,
892 payload_length,
893 blob->data,
894 blob->length,
895 &creds2);
896 if (!NT_STATUS_IS_OK(status)) {
897 return status;
899 break;
901 default:
902 status = NT_STATUS_INVALID_LEVEL;
903 break;
906 if (creds2.length != sig_size) {
907 /* this means the sig_size estimate for the signature
908 was incorrect. We have to correct the packet
909 sizes. That means we could go over the max fragment
910 length */
911 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
912 (unsigned) creds2.length,
913 (unsigned) sig_size,
914 (unsigned) c->security_state.auth_info->auth_pad_length,
915 (unsigned) pkt->u.request.stub_and_verifier.length));
916 dcerpc_set_frag_length(blob, blob->length + creds2.length);
917 dcerpc_set_auth_length(blob, creds2.length);
920 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
921 return NT_STATUS_NO_MEMORY;
924 return NT_STATUS_OK;
929 fill in the fixed values in a dcerpc header
931 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
933 pkt->rpc_vers = 5;
934 pkt->rpc_vers_minor = 0;
935 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
936 pkt->drep[0] = 0;
937 } else {
938 pkt->drep[0] = DCERPC_DREP_LE;
940 pkt->drep[1] = 0;
941 pkt->drep[2] = 0;
942 pkt->drep[3] = 0;
946 map a bind nak reason to a NTSTATUS
948 static NTSTATUS dcerpc_map_reason(uint16_t reason)
950 switch (reason) {
951 case DCERPC_BIND_REASON_ASYNTAX:
952 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
953 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
954 return NT_STATUS_INVALID_PARAMETER;
956 return NT_STATUS_UNSUCCESSFUL;
960 remove requests from the pending or queued queues
962 static int dcerpc_req_dequeue(struct rpc_request *req)
964 switch (req->state) {
965 case RPC_REQUEST_QUEUED:
966 DLIST_REMOVE(req->p->conn->request_queue, req);
967 break;
968 case RPC_REQUEST_PENDING:
969 DLIST_REMOVE(req->p->conn->pending, req);
970 break;
971 case RPC_REQUEST_DONE:
972 break;
974 return 0;
979 mark the dcerpc connection dead. All outstanding requests get an error
981 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
983 if (conn->dead) return;
985 conn->dead = true;
987 TALLOC_FREE(conn->io_trigger);
988 conn->io_trigger_pending = false;
990 conn->transport.recv_data = NULL;
992 if (conn->transport.shutdown_pipe) {
993 conn->transport.shutdown_pipe(conn, status);
996 /* all pending requests get the error */
997 while (conn->pending) {
998 struct rpc_request *req = conn->pending;
999 dcerpc_req_dequeue(req);
1000 req->state = RPC_REQUEST_DONE;
1001 req->status = status;
1002 if (req->async.callback) {
1003 req->async.callback(req);
1007 /* all requests, which are not shipped */
1008 while (conn->request_queue) {
1009 struct rpc_request *req = conn->request_queue;
1010 dcerpc_req_dequeue(req);
1011 req->state = RPC_REQUEST_DONE;
1012 req->status = status;
1013 if (req->async.callback) {
1014 req->async.callback(req);
1018 talloc_set_destructor(conn, NULL);
1019 if (conn->free_skipped) {
1020 talloc_free(conn);
1025 forward declarations of the recv_data handlers for the types of
1026 packets we need to handle
1028 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1029 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1032 receive a dcerpc reply from the transport. Here we work out what
1033 type of reply it is (normal request, bind or alter context) and
1034 dispatch to the appropriate handler
1036 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1038 struct ncacn_packet pkt;
1040 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1041 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1044 /* the transport may be telling us of a severe error, such as
1045 a dropped socket */
1046 if (!NT_STATUS_IS_OK(status)) {
1047 data_blob_free(blob);
1048 dcerpc_connection_dead(conn, status);
1049 return;
1052 /* parse the basic packet to work out what type of response this is */
1053 status = ncacn_pull(conn, blob, blob->data, &pkt);
1054 if (!NT_STATUS_IS_OK(status)) {
1055 data_blob_free(blob);
1056 dcerpc_connection_dead(conn, status);
1057 return;
1060 dcerpc_request_recv_data(conn, blob, &pkt);
1064 handle timeouts of individual dcerpc requests
1066 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1067 struct timeval t, void *private_data)
1069 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1071 if (req->ignore_timeout) {
1072 dcerpc_req_dequeue(req);
1073 req->state = RPC_REQUEST_DONE;
1074 req->status = NT_STATUS_IO_TIMEOUT;
1075 if (req->async.callback) {
1076 req->async.callback(req);
1078 return;
1081 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1084 struct dcerpc_bind_state {
1085 struct dcerpc_pipe *p;
1088 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1089 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1090 DATA_BLOB *raw_packet,
1091 struct ncacn_packet *pkt);
1093 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1094 struct tevent_context *ev,
1095 struct dcerpc_pipe *p,
1096 const struct ndr_syntax_id *syntax,
1097 const struct ndr_syntax_id *transfer_syntax)
1099 struct tevent_req *req;
1100 struct dcerpc_bind_state *state;
1101 struct ncacn_packet pkt;
1102 DATA_BLOB blob;
1103 NTSTATUS status;
1104 struct rpc_request *subreq;
1106 req = tevent_req_create(mem_ctx, &state,
1107 struct dcerpc_bind_state);
1108 if (req == NULL) {
1109 return NULL;
1112 state->p = p;
1114 p->syntax = *syntax;
1115 p->transfer_syntax = *transfer_syntax;
1117 init_ncacn_hdr(p->conn, &pkt);
1119 pkt.ptype = DCERPC_PKT_BIND;
1120 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1121 pkt.call_id = p->conn->call_id;
1122 pkt.auth_length = 0;
1124 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1125 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1128 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1129 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1132 pkt.u.bind.max_xmit_frag = 5840;
1133 pkt.u.bind.max_recv_frag = 5840;
1134 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1135 pkt.u.bind.num_contexts = 1;
1136 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1137 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1138 return tevent_req_post(req, ev);
1140 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1141 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1142 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1143 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1144 pkt.u.bind.auth_info = data_blob(NULL, 0);
1146 /* construct the NDR form of the packet */
1147 status = ncacn_push_auth(&blob, state, &pkt,
1148 p->conn->security_state.auth_info);
1149 if (tevent_req_nterror(req, status)) {
1150 return tevent_req_post(req, ev);
1153 p->conn->transport.recv_data = dcerpc_recv_data;
1156 * we allocate a dcerpc_request so we can be in the same
1157 * request queue as normal requests
1159 subreq = talloc_zero(state, struct rpc_request);
1160 if (tevent_req_nomem(subreq, req)) {
1161 return tevent_req_post(req, ev);
1164 subreq->state = RPC_REQUEST_PENDING;
1165 subreq->call_id = pkt.call_id;
1166 subreq->async.private_data = req;
1167 subreq->async.callback = dcerpc_bind_fail_handler;
1168 subreq->p = p;
1169 subreq->recv_handler = dcerpc_bind_recv_handler;
1170 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1171 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1173 status = p->conn->transport.send_request(p->conn, &blob, true);
1174 if (tevent_req_nterror(req, status)) {
1175 return tevent_req_post(req, ev);
1178 tevent_add_timer(ev, subreq,
1179 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1180 dcerpc_timeout_handler, subreq);
1182 return req;
1185 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1187 struct tevent_req *req =
1188 talloc_get_type_abort(subreq->async.private_data,
1189 struct tevent_req);
1190 NTSTATUS status = subreq->status;
1192 TALLOC_FREE(subreq);
1194 tevent_req_nterror(req, status);
1197 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1198 DATA_BLOB *raw_packet,
1199 struct ncacn_packet *pkt)
1201 struct tevent_req *req =
1202 talloc_get_type_abort(subreq->async.private_data,
1203 struct tevent_req);
1204 struct dcerpc_bind_state *state =
1205 tevent_req_data(req,
1206 struct dcerpc_bind_state);
1207 struct dcecli_connection *conn = state->p->conn;
1208 NTSTATUS status;
1211 * Note that pkt is allocated under raw_packet->data,
1212 * while raw_packet->data is a child of subreq.
1214 talloc_steal(state, raw_packet->data);
1215 TALLOC_FREE(subreq);
1217 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1218 status = dcerpc_map_reason(pkt->u.bind_nak.reject_reason);
1220 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1221 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1223 tevent_req_nterror(req, status);
1224 return;
1227 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1228 (pkt->u.bind_ack.num_results == 0) ||
1229 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1230 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1231 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1232 return;
1235 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1236 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1238 if ((state->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1239 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1240 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1243 if ((state->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1244 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1245 conn->flags |= DCERPC_HEADER_SIGNING;
1248 /* the bind_ack might contain a reply set of credentials */
1249 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1250 uint32_t auth_length;
1252 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1253 conn->security_state.auth_info, &auth_length, true);
1254 if (tevent_req_nterror(req, status)) {
1255 return;
1259 state->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1261 tevent_req_done(req);
1264 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1266 return tevent_req_simple_recv_ntstatus(req);
1270 perform a continued bind (and auth3)
1272 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1273 TALLOC_CTX *mem_ctx)
1275 struct ncacn_packet pkt;
1276 NTSTATUS status;
1277 DATA_BLOB blob;
1279 init_ncacn_hdr(p->conn, &pkt);
1281 pkt.ptype = DCERPC_PKT_AUTH3;
1282 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1283 pkt.call_id = next_call_id(p->conn);
1284 pkt.auth_length = 0;
1285 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1287 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1288 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1291 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1292 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1295 /* construct the NDR form of the packet */
1296 status = ncacn_push_auth(&blob, mem_ctx,
1297 &pkt,
1298 p->conn->security_state.auth_info);
1299 if (!NT_STATUS_IS_OK(status)) {
1300 return status;
1303 /* send it on its way */
1304 status = p->conn->transport.send_request(p->conn, &blob, false);
1305 if (!NT_STATUS_IS_OK(status)) {
1306 return status;
1309 return NT_STATUS_OK;
1314 process a fragment received from the transport layer during a
1315 request
1317 This function frees the data
1319 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1320 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1322 struct rpc_request *req;
1323 unsigned int length;
1324 NTSTATUS status = NT_STATUS_OK;
1327 if this is an authenticated connection then parse and check
1328 the auth info. We have to do this before finding the
1329 matching packet, as the request structure might have been
1330 removed due to a timeout, but if it has been we still need
1331 to run the auth routines so that we don't get the sign/seal
1332 info out of step with the server
1334 if (c->security_state.auth_info && c->security_state.generic_state &&
1335 pkt->ptype == DCERPC_PKT_RESPONSE) {
1336 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1339 /* find the matching request */
1340 for (req=c->pending;req;req=req->next) {
1341 if (pkt->call_id == req->call_id) break;
1344 #if 0
1345 /* useful for testing certain vendors RPC servers */
1346 if (req == NULL && c->pending && pkt->call_id == 0) {
1347 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1348 req = c->pending;
1350 #endif
1352 if (req == NULL) {
1353 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1354 data_blob_free(raw_packet);
1355 return;
1358 talloc_steal(req, raw_packet->data);
1360 if (req->recv_handler != NULL) {
1361 dcerpc_req_dequeue(req);
1362 req->state = RPC_REQUEST_DONE;
1363 req->recv_handler(req, raw_packet, pkt);
1364 return;
1367 if (pkt->ptype == DCERPC_PKT_FAULT) {
1368 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1369 req->fault_code = pkt->u.fault.status;
1370 req->status = NT_STATUS_NET_WRITE_FAULT;
1371 goto req_done;
1374 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1375 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1376 (int)pkt->ptype));
1377 req->fault_code = DCERPC_FAULT_OTHER;
1378 req->status = NT_STATUS_NET_WRITE_FAULT;
1379 goto req_done;
1382 /* now check the status from the auth routines, and if it failed then fail
1383 this request accordingly */
1384 if (!NT_STATUS_IS_OK(status)) {
1385 req->status = status;
1386 goto req_done;
1389 length = pkt->u.response.stub_and_verifier.length;
1391 if (length > 0) {
1392 req->payload.data = talloc_realloc(req,
1393 req->payload.data,
1394 uint8_t,
1395 req->payload.length + length);
1396 if (!req->payload.data) {
1397 req->status = NT_STATUS_NO_MEMORY;
1398 goto req_done;
1400 memcpy(req->payload.data+req->payload.length,
1401 pkt->u.response.stub_and_verifier.data, length);
1402 req->payload.length += length;
1405 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1406 c->transport.send_read(c);
1407 return;
1410 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1411 req->flags |= DCERPC_PULL_BIGENDIAN;
1412 } else {
1413 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1417 req_done:
1418 /* we've got the full payload */
1419 req->state = RPC_REQUEST_DONE;
1420 DLIST_REMOVE(c->pending, req);
1423 * We have to look at shipping further requests before calling
1424 * the async function, that one might close the pipe
1426 dcerpc_schedule_io_trigger(c);
1428 if (req->async.callback) {
1429 req->async.callback(req);
1434 perform the send side of a async dcerpc request
1436 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
1437 const struct GUID *object,
1438 uint16_t opnum,
1439 DATA_BLOB *stub_data)
1441 struct rpc_request *req;
1443 p->conn->transport.recv_data = dcerpc_recv_data;
1445 req = talloc(p, struct rpc_request);
1446 if (req == NULL) {
1447 return NULL;
1450 req->p = p;
1451 req->call_id = next_call_id(p->conn);
1452 req->status = NT_STATUS_OK;
1453 req->state = RPC_REQUEST_QUEUED;
1454 req->payload = data_blob(NULL, 0);
1455 req->flags = 0;
1456 req->fault_code = 0;
1457 req->ignore_timeout = false;
1458 req->async.callback = NULL;
1459 req->async.private_data = NULL;
1460 req->recv_handler = NULL;
1462 if (object != NULL) {
1463 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1464 if (req->object == NULL) {
1465 talloc_free(req);
1466 return NULL;
1468 } else {
1469 req->object = NULL;
1472 req->opnum = opnum;
1473 req->request_data.length = stub_data->length;
1474 req->request_data.data = talloc_reference(req, stub_data->data);
1475 if (req->request_data.length && req->request_data.data == NULL) {
1476 return NULL;
1479 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1480 talloc_set_destructor(req, dcerpc_req_dequeue);
1482 dcerpc_schedule_io_trigger(p->conn);
1484 if (p->request_timeout) {
1485 tevent_add_timer(dcerpc_event_context(p), req,
1486 timeval_current_ofs(p->request_timeout, 0),
1487 dcerpc_timeout_handler, req);
1490 return req;
1494 Send a request using the transport
1497 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1499 struct rpc_request *req;
1500 struct dcerpc_pipe *p;
1501 DATA_BLOB *stub_data;
1502 struct ncacn_packet pkt;
1503 DATA_BLOB blob;
1504 uint32_t remaining, chunk_size;
1505 bool first_packet = true;
1506 size_t sig_size = 0;
1507 bool need_async = false;
1509 req = c->request_queue;
1510 if (req == NULL) {
1511 return;
1514 p = req->p;
1515 stub_data = &req->request_data;
1517 if (c->pending) {
1518 need_async = true;
1521 DLIST_REMOVE(c->request_queue, req);
1522 DLIST_ADD(c->pending, req);
1523 req->state = RPC_REQUEST_PENDING;
1525 init_ncacn_hdr(p->conn, &pkt);
1527 remaining = stub_data->length;
1529 /* we can write a full max_recv_frag size, minus the dcerpc
1530 request header size */
1531 chunk_size = p->conn->srv_max_recv_frag;
1532 chunk_size -= DCERPC_REQUEST_LENGTH;
1533 if (c->security_state.auth_info &&
1534 c->security_state.generic_state) {
1535 sig_size = gensec_sig_size(c->security_state.generic_state,
1536 p->conn->srv_max_recv_frag);
1537 if (sig_size) {
1538 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1539 chunk_size -= sig_size;
1542 chunk_size -= (chunk_size % 16);
1544 pkt.ptype = DCERPC_PKT_REQUEST;
1545 pkt.call_id = req->call_id;
1546 pkt.auth_length = 0;
1547 pkt.pfc_flags = 0;
1548 pkt.u.request.alloc_hint = remaining;
1549 pkt.u.request.context_id = p->context_id;
1550 pkt.u.request.opnum = req->opnum;
1552 if (req->object) {
1553 pkt.u.request.object.object = *req->object;
1554 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1555 chunk_size -= ndr_size_GUID(req->object,0);
1558 /* we send a series of pdus without waiting for a reply */
1559 while (remaining > 0 || first_packet) {
1560 uint32_t chunk = MIN(chunk_size, remaining);
1561 bool last_frag = false;
1562 bool do_trans = false;
1564 first_packet = false;
1565 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1567 if (remaining == stub_data->length) {
1568 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1570 if (chunk == remaining) {
1571 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1572 last_frag = true;
1575 pkt.u.request.stub_and_verifier.data = stub_data->data +
1576 (stub_data->length - remaining);
1577 pkt.u.request.stub_and_verifier.length = chunk;
1579 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1580 if (!NT_STATUS_IS_OK(req->status)) {
1581 req->state = RPC_REQUEST_DONE;
1582 DLIST_REMOVE(p->conn->pending, req);
1583 return;
1586 if (last_frag && !need_async) {
1587 do_trans = true;
1590 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1591 if (!NT_STATUS_IS_OK(req->status)) {
1592 req->state = RPC_REQUEST_DONE;
1593 DLIST_REMOVE(p->conn->pending, req);
1594 return;
1597 if (last_frag && !do_trans) {
1598 req->status = p->conn->transport.send_read(p->conn);
1599 if (!NT_STATUS_IS_OK(req->status)) {
1600 req->state = RPC_REQUEST_DONE;
1601 DLIST_REMOVE(p->conn->pending, req);
1602 return;
1606 remaining -= chunk;
1610 static void dcerpc_io_trigger(struct tevent_context *ctx,
1611 struct tevent_immediate *im,
1612 void *private_data)
1614 struct dcecli_connection *c =
1615 talloc_get_type_abort(private_data,
1616 struct dcecli_connection);
1618 c->io_trigger_pending = false;
1620 dcerpc_schedule_io_trigger(c);
1622 dcerpc_ship_next_request(c);
1625 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1627 if (c->dead) {
1628 return;
1631 if (c->request_queue == NULL) {
1632 return;
1635 if (c->io_trigger_pending) {
1636 return;
1639 c->io_trigger_pending = true;
1641 tevent_schedule_immediate(c->io_trigger,
1642 c->event_ctx,
1643 dcerpc_io_trigger,
1648 return the event context for a dcerpc pipe
1649 used by callers who wish to operate asynchronously
1651 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1653 return p->conn->event_ctx;
1659 perform the receive side of a async dcerpc request
1661 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1662 TALLOC_CTX *mem_ctx,
1663 DATA_BLOB *stub_data)
1665 NTSTATUS status;
1667 while (req->state != RPC_REQUEST_DONE) {
1668 struct tevent_context *ctx = dcerpc_event_context(req->p);
1669 if (tevent_loop_once(ctx) != 0) {
1670 return NT_STATUS_CONNECTION_DISCONNECTED;
1673 *stub_data = req->payload;
1674 status = req->status;
1675 if (stub_data->data) {
1676 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1678 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1679 req->p->last_fault_code = req->fault_code;
1681 talloc_unlink(talloc_parent(req), req);
1682 return status;
1686 this is a paranoid NDR validator. For every packet we push onto the wire
1687 we pull it back again, then push it again. Then we compare the raw NDR data
1688 for that to the NDR we initially generated. If they don't match then we know
1689 we must have a bug in either the pull or push side of our code
1691 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1692 TALLOC_CTX *mem_ctx,
1693 DATA_BLOB blob,
1694 size_t struct_size,
1695 ndr_push_flags_fn_t ndr_push,
1696 ndr_pull_flags_fn_t ndr_pull)
1698 void *st;
1699 struct ndr_pull *pull;
1700 struct ndr_push *push;
1701 DATA_BLOB blob2;
1702 enum ndr_err_code ndr_err;
1704 st = talloc_size(mem_ctx, struct_size);
1705 if (!st) {
1706 return NT_STATUS_NO_MEMORY;
1709 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1710 if (!pull) {
1711 return NT_STATUS_NO_MEMORY;
1713 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1715 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1716 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1719 if (c->flags & DCERPC_NDR64) {
1720 pull->flags |= LIBNDR_FLAG_NDR64;
1723 ndr_err = ndr_pull(pull, NDR_IN, st);
1724 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1725 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1726 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1727 "failed input validation pull - %s",
1728 nt_errstr(status));
1729 return ndr_map_error2ntstatus(ndr_err);
1732 push = ndr_push_init_ctx(mem_ctx);
1733 if (!push) {
1734 return NT_STATUS_NO_MEMORY;
1737 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1738 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1741 if (c->flags & DCERPC_NDR64) {
1742 push->flags |= LIBNDR_FLAG_NDR64;
1745 ndr_err = ndr_push(push, NDR_IN, st);
1746 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1747 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1748 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1749 "failed input validation push - %s",
1750 nt_errstr(status));
1751 return ndr_map_error2ntstatus(ndr_err);
1754 blob2 = ndr_push_blob(push);
1756 if (data_blob_cmp(&blob, &blob2) != 0) {
1757 DEBUG(3,("original:\n"));
1758 dump_data(3, blob.data, blob.length);
1759 DEBUG(3,("secondary:\n"));
1760 dump_data(3, blob2.data, blob2.length);
1761 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1762 "failed input validation blobs doesn't match");
1763 return ndr_map_error2ntstatus(ndr_err);
1766 return NT_STATUS_OK;
1770 this is a paranoid NDR input validator. For every packet we pull
1771 from the wire we push it back again then pull and push it
1772 again. Then we compare the raw NDR data for that to the NDR we
1773 initially generated. If they don't match then we know we must have a
1774 bug in either the pull or push side of our code
1776 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1777 struct ndr_pull *pull_in,
1778 void *struct_ptr,
1779 size_t struct_size,
1780 ndr_push_flags_fn_t ndr_push,
1781 ndr_pull_flags_fn_t ndr_pull,
1782 ndr_print_function_t ndr_print)
1784 void *st;
1785 struct ndr_pull *pull;
1786 struct ndr_push *push;
1787 DATA_BLOB blob, blob2;
1788 TALLOC_CTX *mem_ctx = pull_in;
1789 char *s1, *s2;
1790 enum ndr_err_code ndr_err;
1792 st = talloc_size(mem_ctx, struct_size);
1793 if (!st) {
1794 return NT_STATUS_NO_MEMORY;
1796 memcpy(st, struct_ptr, struct_size);
1798 push = ndr_push_init_ctx(mem_ctx);
1799 if (!push) {
1800 return NT_STATUS_NO_MEMORY;
1803 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1804 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1805 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1806 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1807 "failed output validation push - %s",
1808 nt_errstr(status));
1809 return ndr_map_error2ntstatus(ndr_err);
1812 blob = ndr_push_blob(push);
1814 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1815 if (!pull) {
1816 return NT_STATUS_NO_MEMORY;
1819 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1820 ndr_err = ndr_pull(pull, NDR_OUT, st);
1821 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1822 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1823 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1824 "failed output validation pull - %s",
1825 nt_errstr(status));
1826 return ndr_map_error2ntstatus(ndr_err);
1829 push = ndr_push_init_ctx(mem_ctx);
1830 if (!push) {
1831 return NT_STATUS_NO_MEMORY;
1834 ndr_err = ndr_push(push, NDR_OUT, st);
1835 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1836 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1837 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1838 "failed output validation push2 - %s",
1839 nt_errstr(status));
1840 return ndr_map_error2ntstatus(ndr_err);
1843 blob2 = ndr_push_blob(push);
1845 if (data_blob_cmp(&blob, &blob2) != 0) {
1846 DEBUG(3,("original:\n"));
1847 dump_data(3, blob.data, blob.length);
1848 DEBUG(3,("secondary:\n"));
1849 dump_data(3, blob2.data, blob2.length);
1850 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1851 "failed output validation blobs doesn't match");
1852 return ndr_map_error2ntstatus(ndr_err);
1855 /* this checks the printed forms of the two structures, which effectively
1856 tests all of the value() attributes */
1857 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1858 NDR_OUT, struct_ptr);
1859 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1860 NDR_OUT, st);
1861 if (strcmp(s1, s2) != 0) {
1862 #if 1
1863 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1864 #else
1865 /* this is sometimes useful */
1866 printf("VALIDATE ERROR\n");
1867 file_save("wire.dat", s1, strlen(s1));
1868 file_save("gen.dat", s2, strlen(s2));
1869 system("diff -u wire.dat gen.dat");
1870 #endif
1871 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1872 "failed output validation strings doesn't match");
1873 return ndr_map_error2ntstatus(ndr_err);
1876 return NT_STATUS_OK;
1880 a useful function for retrieving the server name we connected to
1882 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1884 if (!p->conn->transport.target_hostname) {
1885 if (!p->conn->transport.peer_name) {
1886 return "";
1888 return p->conn->transport.peer_name(p->conn);
1890 return p->conn->transport.target_hostname(p->conn);
1895 get the dcerpc auth_level for a open connection
1897 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1899 uint8_t auth_level;
1901 if (c->flags & DCERPC_SEAL) {
1902 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1903 } else if (c->flags & DCERPC_SIGN) {
1904 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1905 } else if (c->flags & DCERPC_CONNECT) {
1906 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1907 } else {
1908 auth_level = DCERPC_AUTH_LEVEL_NONE;
1910 return auth_level;
1913 struct dcerpc_alter_context_state {
1914 struct dcerpc_pipe *p;
1917 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
1918 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
1919 DATA_BLOB *raw_packet,
1920 struct ncacn_packet *pkt);
1922 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
1923 struct tevent_context *ev,
1924 struct dcerpc_pipe *p,
1925 const struct ndr_syntax_id *syntax,
1926 const struct ndr_syntax_id *transfer_syntax)
1928 struct tevent_req *req;
1929 struct dcerpc_alter_context_state *state;
1930 struct ncacn_packet pkt;
1931 DATA_BLOB blob;
1932 NTSTATUS status;
1933 struct rpc_request *subreq;
1935 req = tevent_req_create(mem_ctx, &state,
1936 struct dcerpc_alter_context_state);
1937 if (req == NULL) {
1938 return NULL;
1941 state->p = p;
1943 p->syntax = *syntax;
1944 p->transfer_syntax = *transfer_syntax;
1946 init_ncacn_hdr(p->conn, &pkt);
1948 pkt.ptype = DCERPC_PKT_ALTER;
1949 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1950 pkt.call_id = p->conn->call_id;
1951 pkt.auth_length = 0;
1953 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1954 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1957 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1958 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1961 pkt.u.alter.max_xmit_frag = 5840;
1962 pkt.u.alter.max_recv_frag = 5840;
1963 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1964 pkt.u.alter.num_contexts = 1;
1965 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
1966 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
1967 return tevent_req_post(req, ev);
1969 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1970 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1971 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1972 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1973 pkt.u.alter.auth_info = data_blob(NULL, 0);
1975 /* construct the NDR form of the packet */
1976 status = ncacn_push_auth(&blob, state, &pkt,
1977 p->conn->security_state.auth_info);
1978 if (tevent_req_nterror(req, status)) {
1979 return tevent_req_post(req, ev);
1982 p->conn->transport.recv_data = dcerpc_recv_data;
1985 * we allocate a dcerpc_request so we can be in the same
1986 * request queue as normal requests
1988 subreq = talloc_zero(state, struct rpc_request);
1989 if (tevent_req_nomem(subreq, req)) {
1990 return tevent_req_post(req, ev);
1993 subreq->state = RPC_REQUEST_PENDING;
1994 subreq->call_id = pkt.call_id;
1995 subreq->async.private_data = req;
1996 subreq->async.callback = dcerpc_alter_context_fail_handler;
1997 subreq->p = p;
1998 subreq->recv_handler = dcerpc_alter_context_recv_handler;
1999 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2000 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2002 status = p->conn->transport.send_request(p->conn, &blob, true);
2003 if (tevent_req_nterror(req, status)) {
2004 return tevent_req_post(req, ev);
2007 tevent_add_timer(ev, subreq,
2008 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2009 dcerpc_timeout_handler, subreq);
2011 return req;
2014 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2016 struct tevent_req *req =
2017 talloc_get_type_abort(subreq->async.private_data,
2018 struct tevent_req);
2019 NTSTATUS status = subreq->status;
2021 TALLOC_FREE(subreq);
2023 tevent_req_nterror(req, status);
2026 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2027 DATA_BLOB *raw_packet,
2028 struct ncacn_packet *pkt)
2030 struct tevent_req *req =
2031 talloc_get_type_abort(subreq->async.private_data,
2032 struct tevent_req);
2033 struct dcerpc_alter_context_state *state =
2034 tevent_req_data(req,
2035 struct dcerpc_alter_context_state);
2036 struct dcecli_connection *conn = state->p->conn;
2037 NTSTATUS status;
2040 * Note that pkt is allocated under raw_packet->data,
2041 * while raw_packet->data is a child of subreq.
2043 talloc_steal(state, raw_packet->data);
2044 TALLOC_FREE(subreq);
2046 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2047 pkt->u.alter_resp.num_results == 1 &&
2048 pkt->u.alter_resp.ctx_list[0].result != 0) {
2049 status = dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason);
2050 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2051 pkt->u.alter_resp.ctx_list[0].reason,
2052 nt_errstr(status)));
2053 tevent_req_nterror(req, status);
2054 return;
2057 if (pkt->ptype == DCERPC_PKT_FAULT) {
2058 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2059 dcerpc_errstr(state, pkt->u.fault.status)));
2060 state->p->last_fault_code = pkt->u.fault.status;
2061 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2062 return;
2065 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2066 pkt->u.alter_resp.num_results == 0 ||
2067 pkt->u.alter_resp.ctx_list[0].result != 0) {
2068 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2069 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2070 return;
2073 /* the alter_resp might contain a reply set of credentials */
2074 if (conn->security_state.auth_info &&
2075 pkt->u.alter_resp.auth_info.length) {
2076 uint32_t auth_length;
2078 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2079 conn->security_state.auth_info, &auth_length, true);
2080 if (tevent_req_nterror(req, status)) {
2081 return;
2085 tevent_req_done(req);
2088 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2090 return tevent_req_simple_recv_ntstatus(req);
2094 send a dcerpc alter_context request
2096 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2097 TALLOC_CTX *mem_ctx,
2098 const struct ndr_syntax_id *syntax,
2099 const struct ndr_syntax_id *transfer_syntax)
2101 struct tevent_req *subreq;
2102 struct tevent_context *ev = p->conn->event_ctx;
2103 bool ok;
2105 /* TODO: create a new event context here */
2107 subreq = dcerpc_alter_context_send(mem_ctx, p->conn->event_ctx,
2108 p, syntax, transfer_syntax);
2109 if (subreq == NULL) {
2110 return NT_STATUS_NO_MEMORY;
2113 ok = tevent_req_poll(subreq, ev);
2114 if (!ok) {
2115 NTSTATUS status;
2116 status = map_nt_error_from_unix_common(errno);
2117 return status;
2120 return dcerpc_alter_context_recv(subreq);