ctdb-scripts: Support storing statd-callout state in cluster filesystem
[samba4-gss.git] / source4 / librpc / rpc / dcerpc.c
blob2224186aee235de34bbb68faf866537254410bde
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 #define SOURCE4_LIBRPC_INTERNALS 1
25 #include "includes.h"
26 #include "lib/util/util_file.h"
27 #include "system/filesys.h"
28 #include "../lib/util/dlinklist.h"
29 #include "lib/events/events.h"
30 #include "librpc/rpc/dcerpc.h"
31 #include "librpc/rpc/dcerpc_proto.h"
32 #include "librpc/rpc/dcerpc_util.h"
33 #include "librpc/rpc/dcerpc_pkt_auth.h"
34 #include "librpc/gen_ndr/ndr_misc.h"
35 #include "librpc/gen_ndr/ndr_dcerpc.h"
36 #include "auth/gensec/gensec.h"
37 #include "param/param.h"
38 #include "lib/util/tevent_ntstatus.h"
39 #include "librpc/rpc/rpc_common.h"
40 #include "lib/tsocket/tsocket.h"
41 #include "libcli/smb/tstream_smbXcli_np.h"
44 enum rpc_request_state {
45 RPC_REQUEST_QUEUED,
46 RPC_REQUEST_PENDING,
47 RPC_REQUEST_DONE
51 handle for an async dcerpc request
53 struct rpc_request {
54 struct rpc_request *next, *prev;
55 struct dcerpc_pipe *p;
56 NTSTATUS status;
57 uint32_t call_id;
58 enum rpc_request_state state;
59 DATA_BLOB payload;
60 uint32_t flags;
61 uint32_t fault_code;
63 /* this is used to distinguish bind and alter_context requests
64 from normal requests */
65 void (*recv_handler)(struct rpc_request *conn,
66 DATA_BLOB *blob, struct ncacn_packet *pkt);
68 const struct GUID *object;
69 uint16_t opnum;
70 DATA_BLOB request_data;
71 bool ignore_timeout;
72 bool wait_for_sync;
73 bool verify_bitmask1;
74 bool verify_pcontext;
76 struct {
77 void (*callback)(struct rpc_request *);
78 void *private_data;
79 } async;
82 _PUBLIC_ NTSTATUS dcerpc_init(void)
84 return gensec_init();
87 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
88 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
90 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
91 struct dcerpc_pipe *p,
92 const struct GUID *object,
93 uint16_t opnum,
94 DATA_BLOB *stub_data);
95 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
96 TALLOC_CTX *mem_ctx,
97 DATA_BLOB *stub_data);
98 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
99 TALLOC_CTX *mem_ctx,
100 DATA_BLOB blob,
101 size_t struct_size,
102 ndr_push_flags_fn_t ndr_push,
103 ndr_pull_flags_fn_t ndr_pull);
104 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
105 struct ndr_pull *pull_in,
106 void *struct_ptr,
107 size_t struct_size,
108 ndr_push_flags_fn_t ndr_push,
109 ndr_pull_flags_fn_t ndr_pull,
110 ndr_print_function_t ndr_print);
111 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
112 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
113 bool trigger_read);
114 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
116 /* destroy a dcerpc connection */
117 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
119 if (conn->dead) {
120 conn->free_skipped = true;
121 return -1;
123 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
124 return 0;
128 /* initialise a dcerpc connection.
129 the event context is optional
131 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
132 struct tevent_context *ev)
134 struct dcecli_connection *c;
136 c = talloc_zero(mem_ctx, struct dcecli_connection);
137 if (!c) {
138 return NULL;
141 c->event_ctx = ev;
143 if (c->event_ctx == NULL) {
144 talloc_free(c);
145 return NULL;
148 c->call_id = 1;
149 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
150 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
151 c->security_state.auth_context_id = 0;
152 c->security_state.session_key = dcecli_generic_session_key;
153 c->security_state.generic_state = NULL;
154 c->flags = 0;
156 * Windows uses 5840 for ncacn_ip_tcp,
157 * so we also use it (for every transport)
158 * by default. But we give the transport
159 * the chance to overwrite it.
161 c->srv_max_xmit_frag = 5840;
162 c->srv_max_recv_frag = 5840;
163 c->max_total_response_size = DCERPC_NCACN_RESPONSE_DEFAULT_MAX_SIZE;
164 c->pending = NULL;
166 c->io_trigger = tevent_create_immediate(c);
167 if (c->io_trigger == NULL) {
168 talloc_free(c);
169 return NULL;
172 talloc_set_destructor(c, dcerpc_connection_destructor);
174 return c;
177 struct dcerpc_bh_state {
178 struct dcerpc_pipe *p;
181 static const struct dcerpc_binding *dcerpc_bh_get_binding(struct dcerpc_binding_handle *h)
183 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
184 struct dcerpc_bh_state);
186 return hs->p->binding;
189 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
191 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
192 struct dcerpc_bh_state);
194 if (!hs->p) {
195 return false;
198 if (!hs->p->conn) {
199 return false;
202 if (hs->p->conn->dead) {
203 return false;
206 return true;
209 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
210 uint32_t timeout)
212 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
213 struct dcerpc_bh_state);
214 uint32_t old;
216 if (!hs->p) {
217 return DCERPC_REQUEST_TIMEOUT;
220 old = hs->p->request_timeout;
221 hs->p->request_timeout = timeout;
223 return old;
226 static bool dcerpc_bh_transport_encrypted(struct dcerpc_binding_handle *h)
228 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
229 struct dcerpc_bh_state);
231 if (hs->p == NULL) {
232 return false;
235 if (hs->p->conn == NULL) {
236 return false;
239 return hs->p->conn->transport.encrypted;
242 static NTSTATUS dcerpc_bh_transport_session_key(struct dcerpc_binding_handle *h,
243 TALLOC_CTX *mem_ctx,
244 DATA_BLOB *session_key)
246 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
247 struct dcerpc_bh_state);
248 struct dcecli_security *sec = NULL;
249 DATA_BLOB sk = { .length = 0, };
250 NTSTATUS status;
252 if (hs->p == NULL) {
253 return NT_STATUS_NO_USER_SESSION_KEY;
256 if (hs->p->conn == NULL) {
257 return NT_STATUS_NO_USER_SESSION_KEY;
260 sec = &hs->p->conn->security_state;
262 if (sec->session_key == NULL) {
263 return NT_STATUS_NO_USER_SESSION_KEY;
266 status = sec->session_key(hs->p->conn, &sk);
267 if (!NT_STATUS_IS_OK(status)) {
268 return status;
271 sk.length = MIN(sk.length, 16);
273 *session_key = data_blob_dup_talloc(mem_ctx, sk);
274 if (session_key->length != sk.length) {
275 return NT_STATUS_NO_MEMORY;
277 talloc_keep_secret(session_key->data);
278 return NT_STATUS_OK;
281 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
282 enum dcerpc_AuthType *auth_type,
283 enum dcerpc_AuthLevel *auth_level)
285 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
286 struct dcerpc_bh_state);
288 if (hs->p == NULL) {
289 return;
292 if (hs->p->conn == NULL) {
293 return;
296 *auth_type = hs->p->conn->security_state.auth_type;
297 *auth_level = hs->p->conn->security_state.auth_level;
300 static NTSTATUS dcerpc_bh_auth_session_key(struct dcerpc_binding_handle *h,
301 TALLOC_CTX *mem_ctx,
302 DATA_BLOB *session_key)
304 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
305 struct dcerpc_bh_state);
306 struct dcecli_security *sec = NULL;
307 NTSTATUS status;
309 if (hs->p == NULL) {
310 return NT_STATUS_NO_USER_SESSION_KEY;
313 if (hs->p->conn == NULL) {
314 return NT_STATUS_NO_USER_SESSION_KEY;
317 sec = &hs->p->conn->security_state;
319 if (sec->auth_type == DCERPC_AUTH_TYPE_NONE) {
320 return NT_STATUS_NO_USER_SESSION_KEY;
323 if (sec->generic_state == NULL) {
324 return NT_STATUS_NO_USER_SESSION_KEY;
327 status = gensec_session_key(sec->generic_state,
328 mem_ctx,
329 session_key);
330 if (!NT_STATUS_IS_OK(status)) {
331 return status;
334 talloc_keep_secret(session_key->data);
335 return NT_STATUS_OK;
338 struct dcerpc_bh_raw_call_state {
339 struct tevent_context *ev;
340 struct dcerpc_binding_handle *h;
341 DATA_BLOB in_data;
342 DATA_BLOB out_data;
343 uint32_t out_flags;
346 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
348 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
349 struct tevent_context *ev,
350 struct dcerpc_binding_handle *h,
351 const struct GUID *object,
352 uint32_t opnum,
353 uint32_t in_flags,
354 const uint8_t *in_data,
355 size_t in_length)
357 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
358 struct dcerpc_bh_state);
359 struct tevent_req *req;
360 struct dcerpc_bh_raw_call_state *state;
361 bool ok;
362 struct rpc_request *subreq;
364 req = tevent_req_create(mem_ctx, &state,
365 struct dcerpc_bh_raw_call_state);
366 if (req == NULL) {
367 return NULL;
369 state->ev = ev;
370 state->h = h;
371 state->in_data.data = discard_const_p(uint8_t, in_data);
372 state->in_data.length = in_length;
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 subreq = dcerpc_request_send(state,
381 hs->p,
382 object,
383 opnum,
384 &state->in_data);
385 if (tevent_req_nomem(subreq, req)) {
386 return tevent_req_post(req, ev);
388 subreq->async.callback = dcerpc_bh_raw_call_done;
389 subreq->async.private_data = req;
391 return req;
394 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
396 struct tevent_req *req =
397 talloc_get_type_abort(subreq->async.private_data,
398 struct tevent_req);
399 struct dcerpc_bh_raw_call_state *state =
400 tevent_req_data(req,
401 struct dcerpc_bh_raw_call_state);
402 NTSTATUS status;
403 uint32_t fault_code;
405 state->out_flags = 0;
406 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
407 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
410 fault_code = subreq->fault_code;
412 status = dcerpc_request_recv(subreq, state, &state->out_data);
413 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
414 status = dcerpc_fault_to_nt_status(fault_code);
418 * We trigger the callback in the next event run
419 * because the code in this file might trigger
420 * multiple request callbacks from within a single
421 * while loop.
423 * In order to avoid segfaults from within
424 * dcerpc_connection_dead() we call
425 * tevent_req_defer_callback().
427 tevent_req_defer_callback(req, state->ev);
429 if (!NT_STATUS_IS_OK(status)) {
430 tevent_req_nterror(req, status);
431 return;
434 tevent_req_done(req);
437 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
438 TALLOC_CTX *mem_ctx,
439 uint8_t **out_data,
440 size_t *out_length,
441 uint32_t *out_flags)
443 struct dcerpc_bh_raw_call_state *state =
444 tevent_req_data(req,
445 struct dcerpc_bh_raw_call_state);
446 NTSTATUS status;
448 if (tevent_req_is_nterror(req, &status)) {
449 tevent_req_received(req);
450 return status;
453 *out_data = talloc_move(mem_ctx, &state->out_data.data);
454 *out_length = state->out_data.length;
455 *out_flags = state->out_flags;
456 tevent_req_received(req);
457 return NT_STATUS_OK;
460 struct dcerpc_bh_disconnect_state {
461 uint8_t _dummy;
464 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
465 struct tevent_context *ev,
466 struct dcerpc_binding_handle *h)
468 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
469 struct dcerpc_bh_state);
470 struct tevent_req *req;
471 struct dcerpc_bh_disconnect_state *state;
472 bool ok;
474 req = tevent_req_create(mem_ctx, &state,
475 struct dcerpc_bh_disconnect_state);
476 if (req == NULL) {
477 return NULL;
480 ok = dcerpc_bh_is_connected(h);
481 if (!ok) {
482 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
483 return tevent_req_post(req, ev);
486 /* TODO: do a real disconnect ... */
487 hs->p = NULL;
489 tevent_req_done(req);
490 return tevent_req_post(req, ev);
493 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
495 NTSTATUS status;
497 if (tevent_req_is_nterror(req, &status)) {
498 tevent_req_received(req);
499 return status;
502 tevent_req_received(req);
503 return NT_STATUS_OK;
506 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
508 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
509 struct dcerpc_bh_state);
511 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
512 return true;
515 return false;
518 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
520 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
521 struct dcerpc_bh_state);
523 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
524 return true;
527 return false;
530 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
532 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
533 struct dcerpc_bh_state);
535 if (hs->p->conn->flags & DCERPC_NDR64) {
536 return true;
539 return false;
542 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
543 ndr_flags_type ndr_flags,
544 const void *_struct_ptr,
545 const struct ndr_interface_call *call)
547 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
548 struct dcerpc_bh_state);
549 void *struct_ptr = discard_const(_struct_ptr);
550 bool print_in = false;
551 bool print_out = false;
553 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
554 print_in = true;
557 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
558 print_out = true;
561 if (DEBUGLEVEL >= 11) {
562 print_in = true;
563 print_out = true;
566 if (ndr_flags & NDR_IN) {
567 if (print_in) {
568 ndr_print_function_debug(call->ndr_print,
569 call->name,
570 ndr_flags,
571 struct_ptr);
574 if (ndr_flags & NDR_OUT) {
575 if (print_out) {
576 ndr_print_function_debug(call->ndr_print,
577 call->name,
578 ndr_flags,
579 struct_ptr);
584 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
585 NTSTATUS error,
586 const void *struct_ptr,
587 const struct ndr_interface_call *call)
589 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
590 call->name, nt_errstr(error)));
593 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
594 NTSTATUS error,
595 const DATA_BLOB *blob,
596 const struct ndr_interface_call *call)
598 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
599 struct dcerpc_bh_state);
600 const uint32_t num_examples = 20;
601 uint32_t i;
603 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
604 call->name, nt_errstr(error)));
606 if (hs->p->conn->packet_log_dir == NULL) return;
608 for (i=0;i<num_examples;i++) {
609 char *name=NULL;
610 int ret;
612 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
613 hs->p->conn->packet_log_dir,
614 call->name, i);
615 if (ret == -1) {
616 return;
618 if (!file_exist(name)) {
619 if (file_save(name, blob->data, blob->length)) {
620 DEBUG(10,("Logged rpc packet to %s\n", name));
622 free(name);
623 break;
625 free(name);
629 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
630 TALLOC_CTX *mem_ctx,
631 const DATA_BLOB *blob,
632 const struct ndr_interface_call *call)
634 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
635 struct dcerpc_bh_state);
637 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
638 NTSTATUS status;
640 status = dcerpc_ndr_validate_in(hs->p->conn,
641 mem_ctx,
642 *blob,
643 call->struct_size,
644 call->ndr_push,
645 call->ndr_pull);
646 if (!NT_STATUS_IS_OK(status)) {
647 DEBUG(0,("Validation [in] failed for %s - %s\n",
648 call->name, nt_errstr(status)));
649 return status;
653 DEBUG(10,("rpc request data:\n"));
654 dump_data(10, blob->data, blob->length);
656 return NT_STATUS_OK;
659 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
660 struct ndr_pull *pull_in,
661 const void *_struct_ptr,
662 const struct ndr_interface_call *call)
664 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
665 struct dcerpc_bh_state);
666 void *struct_ptr = discard_const(_struct_ptr);
668 DEBUG(10,("rpc reply data:\n"));
669 dump_data(10, pull_in->data, pull_in->data_size);
671 if (pull_in->offset != pull_in->data_size) {
672 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
673 pull_in->data_size - pull_in->offset,
674 pull_in->offset, pull_in->offset,
675 call->name));
676 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
677 but it turns out that early versions of NT
678 (specifically NT3.1) add junk onto the end of rpc
679 packets, so if we want to interoperate at all with
680 those versions then we need to ignore this error */
683 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
684 NTSTATUS status;
686 status = dcerpc_ndr_validate_out(hs->p->conn,
687 pull_in,
688 struct_ptr,
689 call->struct_size,
690 call->ndr_push,
691 call->ndr_pull,
692 call->ndr_print);
693 if (!NT_STATUS_IS_OK(status)) {
694 DEBUG(2,("Validation [out] failed for %s - %s\n",
695 call->name, nt_errstr(status)));
696 return status;
700 return NT_STATUS_OK;
703 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
704 .name = "dcerpc",
705 .get_binding = dcerpc_bh_get_binding,
706 .is_connected = dcerpc_bh_is_connected,
707 .set_timeout = dcerpc_bh_set_timeout,
708 .transport_encrypted = dcerpc_bh_transport_encrypted,
709 .transport_session_key = dcerpc_bh_transport_session_key,
710 .auth_info = dcerpc_bh_auth_info,
711 .auth_session_key = dcerpc_bh_auth_session_key,
712 .raw_call_send = dcerpc_bh_raw_call_send,
713 .raw_call_recv = dcerpc_bh_raw_call_recv,
714 .disconnect_send = dcerpc_bh_disconnect_send,
715 .disconnect_recv = dcerpc_bh_disconnect_recv,
717 .push_bigendian = dcerpc_bh_push_bigendian,
718 .ref_alloc = dcerpc_bh_ref_alloc,
719 .use_ndr64 = dcerpc_bh_use_ndr64,
720 .do_ndr_print = dcerpc_bh_do_ndr_print,
721 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
722 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
723 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
724 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
727 /* initialise a dcerpc pipe. */
728 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p,
729 const struct GUID *object,
730 const struct ndr_interface_table *table)
732 struct dcerpc_binding_handle *h;
733 struct dcerpc_bh_state *hs;
735 h = dcerpc_binding_handle_create(p,
736 &dcerpc_bh_ops,
737 object,
738 table,
739 &hs,
740 struct dcerpc_bh_state,
741 __location__);
742 if (h == NULL) {
743 return NULL;
745 hs->p = p;
747 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
749 return h;
752 /* initialise a dcerpc pipe. */
753 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
755 struct dcerpc_pipe *p;
757 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
758 if (!p) {
759 return NULL;
762 p->conn = dcerpc_connection_init(p, ev);
763 if (p->conn == NULL) {
764 talloc_free(p);
765 return NULL;
768 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
770 if (DEBUGLVL(100)) {
771 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
774 return p;
779 choose the next call id to use
781 static uint32_t next_call_id(struct dcecli_connection *c)
783 c->call_id++;
784 if (c->call_id == 0) {
785 c->call_id++;
787 return c->call_id;
791 setup for a ndr pull, also setting up any flags from the binding string
793 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
794 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
796 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
798 if (ndr == NULL) return ndr;
800 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
801 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
804 if (c->flags & DCERPC_NDR_REF_ALLOC) {
805 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
808 if (c->flags & DCERPC_NDR64) {
809 ndr->flags |= LIBNDR_FLAG_NDR64;
812 return ndr;
816 parse the authentication information on a dcerpc response packet
818 static NTSTATUS ncacn_pull_pkt_auth(struct dcecli_connection *c,
819 TALLOC_CTX *mem_ctx,
820 enum dcerpc_pkt_type ptype,
821 uint8_t required_flags,
822 uint8_t optional_flags,
823 uint8_t payload_offset,
824 DATA_BLOB *payload_and_verifier,
825 DATA_BLOB *raw_packet,
826 const struct ncacn_packet *pkt)
828 const struct dcerpc_auth tmp_auth = {
829 .auth_type = c->security_state.auth_type,
830 .auth_level = c->security_state.auth_level,
831 .auth_context_id = c->security_state.auth_context_id,
833 NTSTATUS status;
835 status = dcerpc_ncacn_pull_pkt_auth(&tmp_auth,
836 c->security_state.generic_state,
837 true, /* check_pkt_auth_fields */
838 mem_ctx,
839 ptype,
840 required_flags,
841 optional_flags,
842 payload_offset,
843 payload_and_verifier,
844 raw_packet,
845 pkt);
846 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
847 return NT_STATUS_INVALID_NETWORK_RESPONSE;
849 if (!NT_STATUS_IS_OK(status)) {
850 return status;
853 return NT_STATUS_OK;
858 push a dcerpc request packet into a blob, possibly signing it.
860 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
861 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
862 size_t sig_size,
863 struct ncacn_packet *pkt)
865 const struct dcerpc_auth tmp_auth = {
866 .auth_type = c->security_state.auth_type,
867 .auth_level = c->security_state.auth_level,
868 .auth_context_id = c->security_state.auth_context_id,
870 NTSTATUS status;
871 uint8_t payload_offset = DCERPC_REQUEST_LENGTH;
873 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
874 payload_offset += 16;
877 status = dcerpc_ncacn_push_pkt_auth(&tmp_auth,
878 c->security_state.generic_state,
879 mem_ctx, blob,
880 sig_size,
881 payload_offset,
882 &pkt->u.request.stub_and_verifier,
883 pkt);
884 if (!NT_STATUS_IS_OK(status)) {
885 return status;
888 return NT_STATUS_OK;
893 fill in the fixed values in a dcerpc header
895 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
897 pkt->rpc_vers = 5;
898 pkt->rpc_vers_minor = 0;
899 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
900 pkt->drep[0] = 0;
901 } else {
902 pkt->drep[0] = DCERPC_DREP_LE;
904 pkt->drep[1] = 0;
905 pkt->drep[2] = 0;
906 pkt->drep[3] = 0;
910 map a bind nak reason to a NTSTATUS
912 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
914 switch (reason) {
915 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
916 return NT_STATUS_REVISION_MISMATCH;
917 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
918 return NT_STATUS_INVALID_PARAMETER;
919 default:
920 break;
922 return NT_STATUS_UNSUCCESSFUL;
925 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
927 if (ack == NULL) {
928 return NT_STATUS_RPC_PROTOCOL_ERROR;
931 switch (ack->result) {
932 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
934 * We have not asked for this...
936 return NT_STATUS_RPC_PROTOCOL_ERROR;
937 default:
938 break;
941 switch (ack->reason.value) {
942 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
943 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
944 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
945 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
946 default:
947 break;
949 return NT_STATUS_UNSUCCESSFUL;
953 remove requests from the pending or queued queues
955 static int dcerpc_req_dequeue(struct rpc_request *req)
957 switch (req->state) {
958 case RPC_REQUEST_QUEUED:
959 DLIST_REMOVE(req->p->conn->request_queue, req);
960 break;
961 case RPC_REQUEST_PENDING:
962 DLIST_REMOVE(req->p->conn->pending, req);
963 break;
964 case RPC_REQUEST_DONE:
965 break;
967 return 0;
972 mark the dcerpc connection dead. All outstanding requests get an error
974 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
976 if (conn->dead) return;
978 conn->dead = true;
980 TALLOC_FREE(conn->io_trigger);
981 conn->io_trigger_pending = false;
983 dcerpc_shutdown_pipe(conn, status);
985 /* all pending requests get the error */
986 while (conn->pending) {
987 struct rpc_request *req = conn->pending;
988 dcerpc_req_dequeue(req);
989 req->state = RPC_REQUEST_DONE;
990 req->status = status;
991 if (req->async.callback) {
992 req->async.callback(req);
996 /* all requests, which are not shipped */
997 while (conn->request_queue) {
998 struct rpc_request *req = conn->request_queue;
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 talloc_set_destructor(conn, NULL);
1008 if (conn->free_skipped) {
1009 talloc_free(conn);
1014 forward declarations of the recv_data handlers for the types of
1015 packets we need to handle
1017 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1018 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1021 receive a dcerpc reply from the transport. Here we work out what
1022 type of reply it is (normal request, bind or alter context) and
1023 dispatch to the appropriate handler
1025 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1027 struct ncacn_packet pkt;
1029 if (conn->dead) {
1030 return;
1033 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1034 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1037 /* the transport may be telling us of a severe error, such as
1038 a dropped socket */
1039 if (!NT_STATUS_IS_OK(status)) {
1040 data_blob_free(blob);
1041 dcerpc_connection_dead(conn, status);
1042 return;
1045 /* parse the basic packet to work out what type of response this is */
1046 status = dcerpc_pull_ncacn_packet(blob->data, blob, &pkt);
1047 if (!NT_STATUS_IS_OK(status)) {
1048 data_blob_free(blob);
1049 dcerpc_connection_dead(conn, status);
1050 return;
1053 dcerpc_request_recv_data(conn, blob, &pkt);
1057 handle timeouts of individual dcerpc requests
1059 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1060 struct timeval t, void *private_data)
1062 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1064 if (req->ignore_timeout) {
1065 dcerpc_req_dequeue(req);
1066 req->state = RPC_REQUEST_DONE;
1067 req->status = NT_STATUS_IO_TIMEOUT;
1068 if (req->async.callback) {
1069 req->async.callback(req);
1071 return;
1074 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1077 struct dcerpc_bind_state {
1078 struct tevent_context *ev;
1079 struct dcerpc_pipe *p;
1082 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1083 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1084 DATA_BLOB *raw_packet,
1085 struct ncacn_packet *pkt);
1087 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1088 struct tevent_context *ev,
1089 struct dcerpc_pipe *p,
1090 const struct ndr_syntax_id *syntax,
1091 const struct ndr_syntax_id *transfer_syntax)
1093 struct tevent_req *req;
1094 struct dcerpc_bind_state *state;
1095 struct ncacn_packet pkt;
1096 DATA_BLOB blob;
1097 NTSTATUS status;
1098 struct rpc_request *subreq;
1099 uint32_t flags;
1100 struct ndr_syntax_id bind_time_features;
1102 bind_time_features = dcerpc_construct_bind_time_features(
1103 DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
1104 DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
1106 req = tevent_req_create(mem_ctx, &state,
1107 struct dcerpc_bind_state);
1108 if (req == NULL) {
1109 return NULL;
1112 state->ev = ev;
1113 state->p = p;
1115 p->syntax = *syntax;
1116 p->transfer_syntax = *transfer_syntax;
1118 flags = dcerpc_binding_get_flags(p->binding);
1120 init_ncacn_hdr(p->conn, &pkt);
1122 pkt.ptype = DCERPC_PKT_BIND;
1123 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1124 pkt.call_id = p->conn->call_id;
1125 pkt.auth_length = 0;
1127 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1128 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1131 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1132 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1135 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1136 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1137 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1138 pkt.u.bind.num_contexts = 2;
1139 pkt.u.bind.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
1140 pkt.u.bind.num_contexts);
1141 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1142 return tevent_req_post(req, ev);
1144 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1145 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1146 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1147 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1148 pkt.u.bind.ctx_list[1].context_id = p->context_id + 1;
1149 pkt.u.bind.ctx_list[1].num_transfer_syntaxes = 1;
1150 pkt.u.bind.ctx_list[1].abstract_syntax = p->syntax;
1151 pkt.u.bind.ctx_list[1].transfer_syntaxes = &bind_time_features;
1152 pkt.u.bind.auth_info = data_blob(NULL, 0);
1154 /* construct the NDR form of the packet */
1155 status = dcerpc_ncacn_push_auth(&blob,
1156 state,
1157 &pkt,
1158 p->conn->security_state.tmp_auth_info.out);
1159 if (tevent_req_nterror(req, status)) {
1160 return tevent_req_post(req, ev);
1164 * we allocate a dcerpc_request so we can be in the same
1165 * request queue as normal requests
1167 subreq = talloc_zero(state, struct rpc_request);
1168 if (tevent_req_nomem(subreq, req)) {
1169 return tevent_req_post(req, ev);
1172 subreq->state = RPC_REQUEST_PENDING;
1173 subreq->call_id = pkt.call_id;
1174 subreq->async.private_data = req;
1175 subreq->async.callback = dcerpc_bind_fail_handler;
1176 subreq->p = p;
1177 subreq->recv_handler = dcerpc_bind_recv_handler;
1178 DLIST_ADD_END(p->conn->pending, subreq);
1179 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1181 status = dcerpc_send_request(p->conn, &blob, true);
1182 if (tevent_req_nterror(req, status)) {
1183 return tevent_req_post(req, ev);
1186 tevent_add_timer(ev, subreq,
1187 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1188 dcerpc_timeout_handler, subreq);
1190 return req;
1193 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1195 struct tevent_req *req =
1196 talloc_get_type_abort(subreq->async.private_data,
1197 struct tevent_req);
1198 struct dcerpc_bind_state *state =
1199 tevent_req_data(req,
1200 struct dcerpc_bind_state);
1201 NTSTATUS status = subreq->status;
1203 TALLOC_FREE(subreq);
1206 * We trigger the callback in the next event run
1207 * because the code in this file might trigger
1208 * multiple request callbacks from within a single
1209 * while loop.
1211 * In order to avoid segfaults from within
1212 * dcerpc_connection_dead() we call
1213 * tevent_req_defer_callback().
1215 tevent_req_defer_callback(req, state->ev);
1217 tevent_req_nterror(req, status);
1220 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1221 DATA_BLOB *raw_packet,
1222 struct ncacn_packet *pkt)
1224 struct tevent_req *req =
1225 talloc_get_type_abort(subreq->async.private_data,
1226 struct tevent_req);
1227 struct dcerpc_bind_state *state =
1228 tevent_req_data(req,
1229 struct dcerpc_bind_state);
1230 struct dcecli_connection *conn = state->p->conn;
1231 struct dcecli_security *sec = &conn->security_state;
1232 struct dcerpc_binding *b = NULL;
1233 NTSTATUS status;
1234 uint32_t flags;
1237 * Note that pkt is allocated under raw_packet->data,
1238 * while raw_packet->data is a child of subreq.
1240 talloc_steal(state, raw_packet->data);
1241 TALLOC_FREE(subreq);
1244 * We trigger the callback in the next event run
1245 * because the code in this file might trigger
1246 * multiple request callbacks from within a single
1247 * while loop.
1249 * In order to avoid segfaults from within
1250 * dcerpc_connection_dead() we call
1251 * tevent_req_defer_callback().
1253 tevent_req_defer_callback(req, state->ev);
1255 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1256 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1258 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1259 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1261 tevent_req_nterror(req, status);
1262 return;
1265 status = dcerpc_verify_ncacn_packet_header(pkt,
1266 DCERPC_PKT_BIND_ACK,
1267 pkt->u.bind_ack.auth_info.length,
1268 DCERPC_PFC_FLAG_FIRST |
1269 DCERPC_PFC_FLAG_LAST,
1270 DCERPC_PFC_FLAG_CONC_MPX |
1271 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1272 if (!NT_STATUS_IS_OK(status)) {
1273 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1274 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1275 return;
1278 if (pkt->u.bind_ack.num_results < 1) {
1279 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1280 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1281 return;
1284 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1285 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1286 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1287 pkt->u.bind_ack.ctx_list[0].reason.value,
1288 nt_errstr(status)));
1289 tevent_req_nterror(req, status);
1290 return;
1293 if (pkt->u.bind_ack.num_results >= 2) {
1294 if (pkt->u.bind_ack.ctx_list[1].result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1295 conn->bind_time_features = pkt->u.bind_ack.ctx_list[1].reason.negotiate;
1296 } else {
1297 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[1]);
1298 DEBUG(10,("dcerpc: bind_time_feature failed - reason %d - %s\n",
1299 pkt->u.bind_ack.ctx_list[1].reason.value,
1300 nt_errstr(status)));
1301 status = NT_STATUS_OK;
1306 * DCE-RPC 1.1 (c706) specifies
1307 * CONST_MUST_RCV_FRAG_SIZE as 1432
1309 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1310 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1311 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1312 return;
1314 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1315 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1316 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1317 return;
1319 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1320 pkt->u.bind_ack.max_xmit_frag);
1321 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1322 pkt->u.bind_ack.max_recv_frag);
1324 flags = dcerpc_binding_get_flags(state->p->binding);
1326 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1327 if (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX) {
1328 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1329 } else {
1330 conn->flags &= ~DCERPC_CONCURRENT_MULTIPLEX;
1334 if (!(conn->flags & DCERPC_CONCURRENT_MULTIPLEX)) {
1335 struct dcerpc_binding *pb =
1336 discard_const_p(struct dcerpc_binding, state->p->binding);
1338 * clear DCERPC_CONCURRENT_MULTIPLEX
1340 status = dcerpc_binding_set_flags(pb, 0,
1341 DCERPC_CONCURRENT_MULTIPLEX);
1342 if (tevent_req_nterror(req, status)) {
1343 return;
1346 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1347 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1348 conn->flags |= DCERPC_HEADER_SIGNING;
1351 /* the bind_ack might contain a reply set of credentials */
1352 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1353 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1354 &pkt->u.bind_ack.auth_info,
1355 sec->tmp_auth_info.in,
1356 NULL, true);
1357 if (tevent_req_nterror(req, status)) {
1358 return;
1363 * We're the owner of the binding, so we're allowed to modify it.
1365 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1366 status = dcerpc_binding_set_assoc_group_id(b,
1367 pkt->u.bind_ack.assoc_group_id);
1368 if (tevent_req_nterror(req, status)) {
1369 return;
1371 status = dcerpc_binding_set_abstract_syntax(b, &state->p->syntax);
1372 if (tevent_req_nterror(req, status)) {
1373 return;
1376 tevent_req_done(req);
1379 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1381 return tevent_req_simple_recv_ntstatus(req);
1385 perform a continued bind (and auth3)
1387 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1388 TALLOC_CTX *mem_ctx)
1390 struct ncacn_packet pkt;
1391 NTSTATUS status;
1392 DATA_BLOB blob;
1393 uint32_t flags;
1395 flags = dcerpc_binding_get_flags(p->binding);
1397 init_ncacn_hdr(p->conn, &pkt);
1399 pkt.ptype = DCERPC_PKT_AUTH3;
1400 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1401 pkt.call_id = next_call_id(p->conn);
1402 pkt.auth_length = 0;
1403 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1405 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1406 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1409 /* construct the NDR form of the packet */
1410 status = dcerpc_ncacn_push_auth(&blob,
1411 mem_ctx,
1412 &pkt,
1413 p->conn->security_state.tmp_auth_info.out);
1414 if (!NT_STATUS_IS_OK(status)) {
1415 return status;
1418 /* send it on its way */
1419 status = dcerpc_send_request(p->conn, &blob, false);
1420 if (!NT_STATUS_IS_OK(status)) {
1421 return status;
1424 return NT_STATUS_OK;
1429 process a fragment received from the transport layer during a
1430 request
1432 This function frees the data
1434 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1435 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1437 struct rpc_request *req;
1438 unsigned int length;
1439 NTSTATUS status = NT_STATUS_OK;
1442 if this is an authenticated connection then parse and check
1443 the auth info. We have to do this before finding the
1444 matching packet, as the request structure might have been
1445 removed due to a timeout, but if it has been we still need
1446 to run the auth routines so that we don't get the sign/seal
1447 info out of step with the server
1449 switch (pkt->ptype) {
1450 case DCERPC_PKT_RESPONSE:
1451 status = ncacn_pull_pkt_auth(c, raw_packet->data,
1452 DCERPC_PKT_RESPONSE,
1453 0, /* required_flags */
1454 DCERPC_PFC_FLAG_FIRST |
1455 DCERPC_PFC_FLAG_LAST,
1456 DCERPC_REQUEST_LENGTH,
1457 &pkt->u.response.stub_and_verifier,
1458 raw_packet, pkt);
1459 break;
1460 default:
1461 break;
1464 /* find the matching request */
1465 for (req=c->pending;req;req=req->next) {
1466 if (pkt->call_id == req->call_id) break;
1469 #if 0
1470 /* useful for testing certain vendors RPC servers */
1471 if (req == NULL && c->pending && pkt->call_id == 0) {
1472 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1473 req = c->pending;
1475 #endif
1477 if (req == NULL) {
1478 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1479 data_blob_free(raw_packet);
1480 return;
1483 talloc_steal(req, raw_packet->data);
1485 if (req->recv_handler != NULL) {
1486 dcerpc_req_dequeue(req);
1487 req->state = RPC_REQUEST_DONE;
1490 * We have to look at shipping further requests before calling
1491 * the async function, that one might close the pipe
1493 dcerpc_schedule_io_trigger(c);
1495 req->recv_handler(req, raw_packet, pkt);
1496 return;
1499 if (pkt->ptype == DCERPC_PKT_FAULT) {
1500 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
1501 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1502 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
1503 dcerpc_connection_dead(c, status);
1504 return;
1506 if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
1507 dcerpc_connection_dead(c, status);
1508 return;
1510 req->fault_code = pkt->u.fault.status;
1511 req->status = NT_STATUS_NET_WRITE_FAULT;
1512 goto req_done;
1515 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1516 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1517 (int)pkt->ptype));
1518 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1519 return;
1522 /* now check the status from the auth routines, and if it failed then fail
1523 this request accordingly */
1524 if (!NT_STATUS_IS_OK(status)) {
1525 dcerpc_connection_dead(c, status);
1526 return;
1529 length = pkt->u.response.stub_and_verifier.length;
1531 if (req->payload.length + length > c->max_total_response_size) {
1532 DEBUG(2,("Unexpected total payload 0x%X > 0x%X dcerpc response\n",
1533 (unsigned)req->payload.length + length,
1534 (unsigned)c->max_total_response_size));
1535 dcerpc_connection_dead(c, NT_STATUS_RPC_PROTOCOL_ERROR);
1536 return;
1539 if (length > 0) {
1540 req->payload.data = talloc_realloc(req,
1541 req->payload.data,
1542 uint8_t,
1543 req->payload.length + length);
1544 if (!req->payload.data) {
1545 req->status = NT_STATUS_NO_MEMORY;
1546 goto req_done;
1548 memcpy(req->payload.data+req->payload.length,
1549 pkt->u.response.stub_and_verifier.data, length);
1550 req->payload.length += length;
1553 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1554 data_blob_free(raw_packet);
1555 dcerpc_send_read(c);
1556 return;
1559 if (req->verify_bitmask1) {
1560 req->p->conn->security_state.verified_bitmask1 = true;
1562 if (req->verify_pcontext) {
1563 req->p->verified_pcontext = true;
1566 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1567 req->flags |= DCERPC_PULL_BIGENDIAN;
1568 } else {
1569 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1572 req_done:
1573 data_blob_free(raw_packet);
1575 /* we've got the full payload */
1576 dcerpc_req_dequeue(req);
1577 req->state = RPC_REQUEST_DONE;
1580 * We have to look at shipping further requests before calling
1581 * the async function, that one might close the pipe
1583 dcerpc_schedule_io_trigger(c);
1585 if (req->async.callback) {
1586 req->async.callback(req);
1590 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1593 perform the send side of a async dcerpc request
1595 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1596 struct dcerpc_pipe *p,
1597 const struct GUID *object,
1598 uint16_t opnum,
1599 DATA_BLOB *stub_data)
1601 struct rpc_request *req;
1602 NTSTATUS status;
1604 req = talloc_zero(mem_ctx, struct rpc_request);
1605 if (req == NULL) {
1606 return NULL;
1609 req->p = p;
1610 req->call_id = next_call_id(p->conn);
1611 req->state = RPC_REQUEST_QUEUED;
1613 if (object != NULL) {
1614 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1615 if (req->object == NULL) {
1616 talloc_free(req);
1617 return NULL;
1621 req->opnum = opnum;
1622 req->request_data.length = stub_data->length;
1623 req->request_data.data = stub_data->data;
1625 status = dcerpc_request_prepare_vt(req);
1626 if (!NT_STATUS_IS_OK(status)) {
1627 talloc_free(req);
1628 return NULL;
1631 DLIST_ADD_END(p->conn->request_queue, req);
1632 talloc_set_destructor(req, dcerpc_req_dequeue);
1634 dcerpc_schedule_io_trigger(p->conn);
1636 if (p->request_timeout) {
1637 tevent_add_timer(p->conn->event_ctx, req,
1638 timeval_current_ofs(p->request_timeout, 0),
1639 dcerpc_timeout_handler, req);
1642 return req;
1645 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1647 struct dcecli_security *sec = &req->p->conn->security_state;
1648 struct dcerpc_sec_verification_trailer *t;
1649 struct dcerpc_sec_vt *c = NULL;
1650 struct ndr_push *ndr = NULL;
1651 enum ndr_err_code ndr_err;
1653 if (sec->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1654 return NT_STATUS_OK;
1657 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1658 if (t == NULL) {
1659 return NT_STATUS_NO_MEMORY;
1662 if (!sec->verified_bitmask1) {
1663 t->commands = talloc_realloc(t, t->commands,
1664 struct dcerpc_sec_vt,
1665 t->count.count + 1);
1666 if (t->commands == NULL) {
1667 return NT_STATUS_NO_MEMORY;
1669 c = &t->commands[t->count.count++];
1670 ZERO_STRUCTP(c);
1672 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1673 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1674 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1676 req->verify_bitmask1 = true;
1679 if (!req->p->verified_pcontext) {
1680 t->commands = talloc_realloc(t, t->commands,
1681 struct dcerpc_sec_vt,
1682 t->count.count + 1);
1683 if (t->commands == NULL) {
1684 return NT_STATUS_NO_MEMORY;
1686 c = &t->commands[t->count.count++];
1687 ZERO_STRUCTP(c);
1689 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1690 c->u.pcontext.abstract_syntax = req->p->syntax;
1691 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1693 req->verify_pcontext = true;
1696 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1697 t->commands = talloc_realloc(t, t->commands,
1698 struct dcerpc_sec_vt,
1699 t->count.count + 1);
1700 if (t->commands == NULL) {
1701 return NT_STATUS_NO_MEMORY;
1703 c = &t->commands[t->count.count++];
1704 ZERO_STRUCTP(c);
1706 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1707 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1708 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1709 c->u.header2.drep[0] = 0;
1710 } else {
1711 c->u.header2.drep[0] = DCERPC_DREP_LE;
1713 c->u.header2.drep[1] = 0;
1714 c->u.header2.drep[2] = 0;
1715 c->u.header2.drep[3] = 0;
1716 c->u.header2.call_id = req->call_id;
1717 c->u.header2.context_id = req->p->context_id;
1718 c->u.header2.opnum = req->opnum;
1721 if (t->count.count == 0) {
1722 TALLOC_FREE(t);
1723 return NT_STATUS_OK;
1726 c = &t->commands[t->count.count - 1];
1727 c->command |= DCERPC_SEC_VT_COMMAND_END;
1729 if (DEBUGLEVEL >= 10) {
1730 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1733 ndr = ndr_push_init_ctx(req);
1734 if (ndr == NULL) {
1735 return NT_STATUS_NO_MEMORY;
1739 * for now we just copy and append
1742 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1743 req->request_data.length);
1744 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1745 return ndr_map_error2ntstatus(ndr_err);
1748 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1749 NDR_SCALARS | NDR_BUFFERS,
1751 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1752 return ndr_map_error2ntstatus(ndr_err);
1754 req->request_data = ndr_push_blob(ndr);
1756 return NT_STATUS_OK;
1760 Send a request using the transport
1763 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1765 struct rpc_request *req;
1766 struct dcerpc_pipe *p;
1767 DATA_BLOB *stub_data;
1768 struct ncacn_packet pkt;
1769 DATA_BLOB blob;
1770 uint32_t remaining, chunk_size;
1771 bool first_packet = true;
1772 size_t sig_size = 0;
1773 bool need_async = false;
1774 bool can_async = true;
1776 req = c->request_queue;
1777 if (req == NULL) {
1778 return;
1781 p = req->p;
1782 stub_data = &req->request_data;
1784 if (c->pending) {
1785 need_async = true;
1788 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1789 can_async = gensec_have_feature(c->security_state.generic_state,
1790 GENSEC_FEATURE_ASYNC_REPLIES);
1793 if (need_async && !can_async) {
1794 req->wait_for_sync = true;
1795 return;
1798 DLIST_REMOVE(c->request_queue, req);
1799 DLIST_ADD(c->pending, req);
1800 req->state = RPC_REQUEST_PENDING;
1802 init_ncacn_hdr(p->conn, &pkt);
1804 remaining = stub_data->length;
1806 /* we can write a full max_recv_frag size, minus the dcerpc
1807 request header size */
1808 chunk_size = p->conn->srv_max_recv_frag;
1809 chunk_size -= DCERPC_REQUEST_LENGTH;
1810 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_PACKET) {
1811 size_t max_payload = chunk_size;
1813 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1814 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1816 sig_size = gensec_sig_size(c->security_state.generic_state,
1817 max_payload);
1818 if (sig_size) {
1819 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1820 chunk_size -= sig_size;
1823 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1825 pkt.ptype = DCERPC_PKT_REQUEST;
1826 pkt.call_id = req->call_id;
1827 pkt.auth_length = 0;
1828 pkt.pfc_flags = 0;
1829 pkt.u.request.context_id = p->context_id;
1830 pkt.u.request.opnum = req->opnum;
1832 if (req->object) {
1833 pkt.u.request.object.object = *req->object;
1834 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1835 chunk_size -= ndr_size_GUID(req->object,0);
1838 /* we send a series of pdus without waiting for a reply */
1839 while (remaining > 0 || first_packet) {
1840 uint32_t chunk = MIN(chunk_size, remaining);
1841 bool last_frag = false;
1842 bool do_trans = false;
1844 first_packet = false;
1845 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1847 if (remaining == stub_data->length) {
1848 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1850 if (chunk == remaining) {
1851 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1852 last_frag = true;
1855 pkt.u.request.alloc_hint = remaining;
1856 pkt.u.request.stub_and_verifier.data = stub_data->data +
1857 (stub_data->length - remaining);
1858 pkt.u.request.stub_and_verifier.length = chunk;
1860 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1861 if (!NT_STATUS_IS_OK(req->status)) {
1862 req->state = RPC_REQUEST_DONE;
1863 DLIST_REMOVE(p->conn->pending, req);
1864 return;
1867 if (last_frag && !need_async) {
1868 do_trans = true;
1871 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1872 if (!NT_STATUS_IS_OK(req->status)) {
1873 req->state = RPC_REQUEST_DONE;
1874 DLIST_REMOVE(p->conn->pending, req);
1875 return;
1878 if (last_frag && !do_trans) {
1879 req->status = dcerpc_send_read(p->conn);
1880 if (!NT_STATUS_IS_OK(req->status)) {
1881 req->state = RPC_REQUEST_DONE;
1882 DLIST_REMOVE(p->conn->pending, req);
1883 return;
1887 remaining -= chunk;
1891 static void dcerpc_io_trigger(struct tevent_context *ctx,
1892 struct tevent_immediate *im,
1893 void *private_data)
1895 struct dcecli_connection *c =
1896 talloc_get_type_abort(private_data,
1897 struct dcecli_connection);
1899 c->io_trigger_pending = false;
1901 dcerpc_schedule_io_trigger(c);
1903 dcerpc_ship_next_request(c);
1906 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1908 if (c->dead) {
1909 return;
1912 if (c->request_queue == NULL) {
1913 return;
1916 if (c->request_queue->wait_for_sync && c->pending) {
1917 return;
1920 if (c->io_trigger_pending) {
1921 return;
1924 c->io_trigger_pending = true;
1926 tevent_schedule_immediate(c->io_trigger,
1927 c->event_ctx,
1928 dcerpc_io_trigger,
1933 perform the receive side of a async dcerpc request
1935 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1936 TALLOC_CTX *mem_ctx,
1937 DATA_BLOB *stub_data)
1939 NTSTATUS status;
1941 while (req->state != RPC_REQUEST_DONE) {
1942 struct tevent_context *ctx = req->p->conn->event_ctx;
1943 if (tevent_loop_once(ctx) != 0) {
1944 return NT_STATUS_CONNECTION_DISCONNECTED;
1947 *stub_data = req->payload;
1948 status = req->status;
1949 if (stub_data->data) {
1950 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1952 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1953 req->p->last_fault_code = req->fault_code;
1955 talloc_unlink(talloc_parent(req), req);
1956 return status;
1960 this is a paranoid NDR validator. For every packet we push onto the wire
1961 we pull it back again, then push it again. Then we compare the raw NDR data
1962 for that to the NDR we initially generated. If they don't match then we know
1963 we must have a bug in either the pull or push side of our code
1965 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1966 TALLOC_CTX *mem_ctx,
1967 DATA_BLOB blob,
1968 size_t struct_size,
1969 ndr_push_flags_fn_t ndr_push,
1970 ndr_pull_flags_fn_t ndr_pull)
1972 void *st;
1973 struct ndr_pull *pull;
1974 struct ndr_push *push;
1975 DATA_BLOB blob2;
1976 enum ndr_err_code ndr_err;
1978 st = talloc_size(mem_ctx, struct_size);
1979 if (!st) {
1980 return NT_STATUS_NO_MEMORY;
1983 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1984 if (!pull) {
1985 return NT_STATUS_NO_MEMORY;
1987 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1989 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1990 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1993 if (c->flags & DCERPC_NDR64) {
1994 pull->flags |= LIBNDR_FLAG_NDR64;
1997 ndr_err = ndr_pull(pull, NDR_IN, st);
1998 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1999 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2000 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2001 "failed input validation pull - %s",
2002 nt_errstr(status));
2003 return ndr_map_error2ntstatus(ndr_err);
2006 push = ndr_push_init_ctx(mem_ctx);
2007 if (!push) {
2008 return NT_STATUS_NO_MEMORY;
2011 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2012 push->flags |= LIBNDR_FLAG_BIGENDIAN;
2015 if (c->flags & DCERPC_NDR64) {
2016 push->flags |= LIBNDR_FLAG_NDR64;
2019 ndr_err = ndr_push(push, NDR_IN, st);
2020 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2021 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2022 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2023 "failed input validation push - %s",
2024 nt_errstr(status));
2025 return ndr_map_error2ntstatus(ndr_err);
2028 blob2 = ndr_push_blob(push);
2030 if (data_blob_cmp(&blob, &blob2) != 0) {
2031 DEBUG(3,("original:\n"));
2032 dump_data(3, blob.data, blob.length);
2033 DEBUG(3,("secondary:\n"));
2034 dump_data(3, blob2.data, blob2.length);
2035 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2036 "failed input validation blobs doesn't match");
2037 return ndr_map_error2ntstatus(ndr_err);
2040 return NT_STATUS_OK;
2044 this is a paranoid NDR input validator. For every packet we pull
2045 from the wire we push it back again then pull and push it
2046 again. Then we compare the raw NDR data for that to the NDR we
2047 initially generated. If they don't match then we know we must have a
2048 bug in either the pull or push side of our code
2050 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
2051 struct ndr_pull *pull_in,
2052 void *struct_ptr,
2053 size_t struct_size,
2054 ndr_push_flags_fn_t ndr_push,
2055 ndr_pull_flags_fn_t ndr_pull,
2056 ndr_print_function_t ndr_print)
2058 void *st;
2059 struct ndr_pull *pull;
2060 struct ndr_push *push;
2061 DATA_BLOB blob, blob2;
2062 TALLOC_CTX *mem_ctx = pull_in;
2063 char *s1, *s2;
2064 enum ndr_err_code ndr_err;
2066 st = talloc_size(mem_ctx, struct_size);
2067 if (!st) {
2068 return NT_STATUS_NO_MEMORY;
2070 memcpy(st, struct_ptr, struct_size);
2072 push = ndr_push_init_ctx(mem_ctx);
2073 if (!push) {
2074 return NT_STATUS_NO_MEMORY;
2077 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2078 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2079 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2080 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2081 "failed output validation push - %s",
2082 nt_errstr(status));
2083 return ndr_map_error2ntstatus(ndr_err);
2086 blob = ndr_push_blob(push);
2088 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2089 if (!pull) {
2090 return NT_STATUS_NO_MEMORY;
2093 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2094 ndr_err = ndr_pull(pull, NDR_OUT, st);
2095 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2096 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2097 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2098 "failed output validation pull - %s",
2099 nt_errstr(status));
2100 return ndr_map_error2ntstatus(ndr_err);
2103 push = ndr_push_init_ctx(mem_ctx);
2104 if (!push) {
2105 return NT_STATUS_NO_MEMORY;
2108 ndr_err = ndr_push(push, NDR_OUT, st);
2109 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2110 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2111 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2112 "failed output validation push2 - %s",
2113 nt_errstr(status));
2114 return ndr_map_error2ntstatus(ndr_err);
2117 blob2 = ndr_push_blob(push);
2119 if (data_blob_cmp(&blob, &blob2) != 0) {
2120 DEBUG(3,("original:\n"));
2121 dump_data(3, blob.data, blob.length);
2122 DEBUG(3,("secondary:\n"));
2123 dump_data(3, blob2.data, blob2.length);
2124 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2125 "failed output validation blobs doesn't match");
2126 return ndr_map_error2ntstatus(ndr_err);
2129 /* this checks the printed forms of the two structures, which effectively
2130 tests all of the value() attributes */
2131 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2132 NDR_OUT, struct_ptr);
2133 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2134 NDR_OUT, st);
2135 if (strcmp(s1, s2) != 0) {
2136 #if 1
2137 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2138 #else
2139 /* this is sometimes useful */
2140 printf("VALIDATE ERROR\n");
2141 file_save("wire.dat", s1, strlen(s1));
2142 file_save("gen.dat", s2, strlen(s2));
2143 system("diff -u wire.dat gen.dat");
2144 #endif
2145 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2146 "failed output validation strings doesn't match");
2147 return ndr_map_error2ntstatus(ndr_err);
2150 return NT_STATUS_OK;
2154 a useful function for retrieving the server name we connected to
2156 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2158 return p->conn ? p->conn->server_name : NULL;
2163 get the dcerpc auth_level for a open connection
2165 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2167 uint8_t auth_level;
2169 if (c->flags & DCERPC_SEAL) {
2170 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2171 } else if (c->flags & DCERPC_SIGN) {
2172 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2173 } else if (c->flags & DCERPC_PACKET) {
2174 auth_level = DCERPC_AUTH_LEVEL_PACKET;
2175 } else if (c->flags & DCERPC_CONNECT) {
2176 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2177 } else {
2178 auth_level = DCERPC_AUTH_LEVEL_NONE;
2180 return auth_level;
2183 struct dcerpc_alter_context_state {
2184 struct tevent_context *ev;
2185 struct dcerpc_pipe *p;
2188 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2189 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2190 DATA_BLOB *raw_packet,
2191 struct ncacn_packet *pkt);
2193 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2194 struct tevent_context *ev,
2195 struct dcerpc_pipe *p,
2196 const struct ndr_syntax_id *syntax,
2197 const struct ndr_syntax_id *transfer_syntax)
2199 struct tevent_req *req;
2200 struct dcerpc_alter_context_state *state;
2201 struct ncacn_packet pkt;
2202 DATA_BLOB blob;
2203 NTSTATUS status;
2204 struct rpc_request *subreq;
2205 uint32_t flags;
2207 req = tevent_req_create(mem_ctx, &state,
2208 struct dcerpc_alter_context_state);
2209 if (req == NULL) {
2210 return NULL;
2213 state->ev = ev;
2214 state->p = p;
2216 p->syntax = *syntax;
2217 p->transfer_syntax = *transfer_syntax;
2219 flags = dcerpc_binding_get_flags(p->binding);
2221 init_ncacn_hdr(p->conn, &pkt);
2223 pkt.ptype = DCERPC_PKT_ALTER;
2224 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2225 pkt.call_id = p->conn->call_id;
2226 pkt.auth_length = 0;
2228 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2229 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2232 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2233 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2234 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2235 pkt.u.alter.num_contexts = 1;
2236 pkt.u.alter.ctx_list = talloc_zero_array(state, struct dcerpc_ctx_list,
2237 pkt.u.alter.num_contexts);
2238 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2239 return tevent_req_post(req, ev);
2241 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2242 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2243 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2244 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2245 pkt.u.alter.auth_info = data_blob(NULL, 0);
2247 /* construct the NDR form of the packet */
2248 status = dcerpc_ncacn_push_auth(&blob,
2249 state,
2250 &pkt,
2251 p->conn->security_state.tmp_auth_info.out);
2252 if (tevent_req_nterror(req, status)) {
2253 return tevent_req_post(req, ev);
2257 * we allocate a dcerpc_request so we can be in the same
2258 * request queue as normal requests
2260 subreq = talloc_zero(state, struct rpc_request);
2261 if (tevent_req_nomem(subreq, req)) {
2262 return tevent_req_post(req, ev);
2265 subreq->state = RPC_REQUEST_PENDING;
2266 subreq->call_id = pkt.call_id;
2267 subreq->async.private_data = req;
2268 subreq->async.callback = dcerpc_alter_context_fail_handler;
2269 subreq->p = p;
2270 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2271 DLIST_ADD_END(p->conn->pending, subreq);
2272 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2274 status = dcerpc_send_request(p->conn, &blob, true);
2275 if (tevent_req_nterror(req, status)) {
2276 return tevent_req_post(req, ev);
2279 tevent_add_timer(ev, subreq,
2280 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2281 dcerpc_timeout_handler, subreq);
2283 return req;
2286 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2288 struct tevent_req *req =
2289 talloc_get_type_abort(subreq->async.private_data,
2290 struct tevent_req);
2291 struct dcerpc_alter_context_state *state =
2292 tevent_req_data(req,
2293 struct dcerpc_alter_context_state);
2294 NTSTATUS status = subreq->status;
2296 TALLOC_FREE(subreq);
2299 * We trigger the callback in the next event run
2300 * because the code in this file might trigger
2301 * multiple request callbacks from within a single
2302 * while loop.
2304 * In order to avoid segfaults from within
2305 * dcerpc_connection_dead() we call
2306 * tevent_req_defer_callback().
2308 tevent_req_defer_callback(req, state->ev);
2310 tevent_req_nterror(req, status);
2313 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2314 DATA_BLOB *raw_packet,
2315 struct ncacn_packet *pkt)
2317 struct tevent_req *req =
2318 talloc_get_type_abort(subreq->async.private_data,
2319 struct tevent_req);
2320 struct dcerpc_alter_context_state *state =
2321 tevent_req_data(req,
2322 struct dcerpc_alter_context_state);
2323 struct dcecli_connection *conn = state->p->conn;
2324 struct dcecli_security *sec = &conn->security_state;
2325 struct dcerpc_binding *b = NULL;
2326 NTSTATUS status;
2329 * Note that pkt is allocated under raw_packet->data,
2330 * while raw_packet->data is a child of subreq.
2332 talloc_steal(state, raw_packet->data);
2333 TALLOC_FREE(subreq);
2336 * We trigger the callback in the next event run
2337 * because the code in this file might trigger
2338 * multiple request callbacks from within a single
2339 * while loop.
2341 * In order to avoid segfaults from within
2342 * dcerpc_connection_dead() we call
2343 * tevent_req_defer_callback().
2345 tevent_req_defer_callback(req, state->ev);
2347 if (pkt->ptype == DCERPC_PKT_FAULT) {
2348 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2349 dcerpc_errstr(state, pkt->u.fault.status)));
2350 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2351 state->p->last_fault_code = pkt->u.fault.status;
2352 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2353 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2354 state->p->last_fault_code = pkt->u.fault.status;
2355 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2356 } else {
2357 state->p->last_fault_code = pkt->u.fault.status;
2358 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2359 tevent_req_nterror(req, status);
2361 return;
2364 status = dcerpc_verify_ncacn_packet_header(pkt,
2365 DCERPC_PKT_ALTER_RESP,
2366 pkt->u.alter_resp.auth_info.length,
2367 DCERPC_PFC_FLAG_FIRST |
2368 DCERPC_PFC_FLAG_LAST,
2369 DCERPC_PFC_FLAG_CONC_MPX |
2370 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2371 if (!NT_STATUS_IS_OK(status)) {
2372 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2373 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2374 return;
2377 if (pkt->u.alter_resp.num_results != 1) {
2378 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2379 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2380 return;
2383 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2384 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2385 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2386 pkt->u.alter_resp.ctx_list[0].reason.value,
2387 nt_errstr(status)));
2388 tevent_req_nterror(req, status);
2389 return;
2392 /* the alter_resp might contain a reply set of credentials */
2393 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2394 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2395 &pkt->u.alter_resp.auth_info,
2396 sec->tmp_auth_info.in,
2397 NULL, true);
2398 if (tevent_req_nterror(req, status)) {
2399 return;
2404 * We're the owner of the binding, so we're allowed to modify it.
2406 b = discard_const_p(struct dcerpc_binding, state->p->binding);
2407 status = dcerpc_binding_set_abstract_syntax(b, &state->p->syntax);
2408 if (tevent_req_nterror(req, status)) {
2409 return;
2412 tevent_req_done(req);
2415 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2417 return tevent_req_simple_recv_ntstatus(req);
2421 send a dcerpc alter_context request
2423 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2424 TALLOC_CTX *mem_ctx,
2425 const struct ndr_syntax_id *syntax,
2426 const struct ndr_syntax_id *transfer_syntax)
2428 struct tevent_req *subreq;
2429 struct tevent_context *ev = p->conn->event_ctx;
2430 bool ok;
2432 /* TODO: create a new event context here */
2434 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2435 p, syntax, transfer_syntax);
2436 if (subreq == NULL) {
2437 return NT_STATUS_NO_MEMORY;
2440 ok = tevent_req_poll(subreq, ev);
2441 if (!ok) {
2442 NTSTATUS status;
2443 status = map_nt_error_from_unix_common(errno);
2444 return status;
2447 return dcerpc_alter_context_recv(subreq);
2450 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2452 if (c->transport.stream == NULL) {
2453 return;
2456 tevent_queue_stop(c->transport.write_queue);
2457 TALLOC_FREE(c->transport.read_subreq);
2458 TALLOC_FREE(c->transport.stream);
2460 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2461 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2464 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2465 status = NT_STATUS_END_OF_FILE;
2468 dcerpc_recv_data(c, NULL, status);
2473 shutdown SMB pipe connection
2475 struct dcerpc_shutdown_pipe_state {
2476 struct dcecli_connection *c;
2477 NTSTATUS status;
2480 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2482 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2484 struct dcerpc_shutdown_pipe_state *state;
2485 struct tevent_req *subreq;
2487 if (c->transport.stream == NULL) {
2488 return NT_STATUS_OK;
2491 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2492 if (state == NULL) {
2493 return NT_STATUS_NO_MEMORY;
2495 state->c = c;
2496 state->status = status;
2498 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2499 if (subreq == NULL) {
2500 return NT_STATUS_NO_MEMORY;
2502 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2504 return status;
2507 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2509 struct dcerpc_shutdown_pipe_state *state =
2510 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2511 struct dcecli_connection *c = state->c;
2512 NTSTATUS status = state->status;
2513 int error;
2516 * here we ignore the return values...
2518 tstream_disconnect_recv(subreq, &error);
2519 TALLOC_FREE(subreq);
2521 TALLOC_FREE(state);
2523 dcerpc_transport_dead(c, status);
2528 struct dcerpc_send_read_state {
2529 struct dcecli_connection *p;
2532 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2534 struct dcecli_connection *p = state->p;
2536 p->transport.read_subreq = NULL;
2538 return 0;
2541 static void dcerpc_send_read_done(struct tevent_req *subreq);
2543 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2545 struct dcerpc_send_read_state *state;
2547 if (p->transport.read_subreq != NULL) {
2548 p->transport.pending_reads++;
2549 return NT_STATUS_OK;
2552 state = talloc_zero(p, struct dcerpc_send_read_state);
2553 if (state == NULL) {
2554 return NT_STATUS_NO_MEMORY;
2556 state->p = p;
2558 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2560 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2561 p->event_ctx,
2562 p->transport.stream);
2563 if (p->transport.read_subreq == NULL) {
2564 return NT_STATUS_NO_MEMORY;
2566 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2568 return NT_STATUS_OK;
2571 static void dcerpc_send_read_done(struct tevent_req *subreq)
2573 struct dcerpc_send_read_state *state =
2574 tevent_req_callback_data(subreq,
2575 struct dcerpc_send_read_state);
2576 struct dcecli_connection *p = state->p;
2577 NTSTATUS status;
2578 struct ncacn_packet *pkt;
2579 DATA_BLOB blob;
2581 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2582 &pkt, &blob);
2583 TALLOC_FREE(subreq);
2584 if (!NT_STATUS_IS_OK(status)) {
2585 TALLOC_FREE(state);
2586 dcerpc_transport_dead(p, status);
2587 return;
2591 * here we steal into thet connection context,
2592 * but p->transport.recv_data() will steal or free it again
2594 talloc_steal(p, blob.data);
2595 TALLOC_FREE(state);
2597 if (p->transport.pending_reads > 0) {
2598 p->transport.pending_reads--;
2600 status = dcerpc_send_read(p);
2601 if (!NT_STATUS_IS_OK(status)) {
2602 dcerpc_transport_dead(p, status);
2603 return;
2607 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2610 struct dcerpc_send_request_state {
2611 struct dcecli_connection *p;
2612 DATA_BLOB blob;
2613 struct iovec iov;
2616 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2618 struct dcecli_connection *p = state->p;
2620 p->transport.read_subreq = NULL;
2622 return 0;
2625 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2626 static void dcerpc_send_request_done(struct tevent_req *subreq);
2628 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2629 bool trigger_read)
2631 struct dcerpc_send_request_state *state;
2632 struct tevent_req *subreq;
2633 bool use_trans = trigger_read;
2635 if (p->transport.stream == NULL) {
2636 return NT_STATUS_CONNECTION_DISCONNECTED;
2639 state = talloc_zero(p, struct dcerpc_send_request_state);
2640 if (state == NULL) {
2641 return NT_STATUS_NO_MEMORY;
2643 state->p = p;
2645 state->blob = data_blob_talloc(state, data->data, data->length);
2646 if (state->blob.data == NULL) {
2647 TALLOC_FREE(state);
2648 return NT_STATUS_NO_MEMORY;
2650 state->iov.iov_base = (void *)state->blob.data;
2651 state->iov.iov_len = state->blob.length;
2653 if (p->transport.read_subreq != NULL) {
2654 use_trans = false;
2657 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2658 use_trans = false;
2661 if (use_trans) {
2663 * we need to block reads until our write is
2664 * the next in the write queue.
2666 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2667 p->transport.write_queue);
2668 if (p->transport.read_subreq == NULL) {
2669 TALLOC_FREE(state);
2670 return NT_STATUS_NO_MEMORY;
2672 tevent_req_set_callback(p->transport.read_subreq,
2673 dcerpc_send_request_wait_done,
2674 state);
2676 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2678 trigger_read = false;
2681 subreq = tstream_writev_queue_send(state, p->event_ctx,
2682 p->transport.stream,
2683 p->transport.write_queue,
2684 &state->iov, 1);
2685 if (subreq == NULL) {
2686 TALLOC_FREE(state);
2687 return NT_STATUS_NO_MEMORY;
2689 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2691 if (trigger_read) {
2692 dcerpc_send_read(p);
2695 return NT_STATUS_OK;
2698 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2700 struct dcerpc_send_request_state *state =
2701 tevent_req_callback_data(subreq,
2702 struct dcerpc_send_request_state);
2703 struct dcecli_connection *p = state->p;
2704 NTSTATUS status;
2705 bool ok;
2707 p->transport.read_subreq = NULL;
2708 talloc_set_destructor(state, NULL);
2710 ok = tevent_queue_wait_recv(subreq);
2711 if (!ok) {
2712 TALLOC_FREE(state);
2713 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2714 return;
2717 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2718 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2719 if (!NT_STATUS_IS_OK(status)) {
2720 TALLOC_FREE(state);
2721 dcerpc_transport_dead(p, status);
2722 return;
2726 /* we free subreq after tstream_cli_np_use_trans */
2727 TALLOC_FREE(subreq);
2729 dcerpc_send_read(p);
2732 static void dcerpc_send_request_done(struct tevent_req *subreq)
2734 struct dcerpc_send_request_state *state =
2735 tevent_req_callback_data(subreq,
2736 struct dcerpc_send_request_state);
2737 int ret;
2738 int error;
2740 ret = tstream_writev_queue_recv(subreq, &error);
2741 TALLOC_FREE(subreq);
2742 if (ret == -1) {
2743 struct dcecli_connection *p = state->p;
2744 NTSTATUS status = map_nt_error_from_unix_common(error);
2746 TALLOC_FREE(state);
2747 dcerpc_transport_dead(p, status);
2748 return;
2751 TALLOC_FREE(state);