CVE-2015-5370: s4:librpc/rpc: use dcerpc_verify_ncacn_packet_header() to verify BIND_...
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blobfde0eb1ddb2eb6c69987c85783a4517548522bcc
1 /*
2 Unix SMB/CIFS implementation.
3 raw dcerpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
39 enum rpc_request_state {
40 RPC_REQUEST_QUEUED,
41 RPC_REQUEST_PENDING,
42 RPC_REQUEST_DONE
46 handle for an async dcerpc request
48 struct rpc_request {
49 struct rpc_request *next, *prev;
50 struct dcerpc_pipe *p;
51 NTSTATUS status;
52 uint32_t call_id;
53 enum rpc_request_state state;
54 DATA_BLOB payload;
55 uint32_t flags;
56 uint32_t fault_code;
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler)(struct rpc_request *conn,
61 DATA_BLOB *blob, struct ncacn_packet *pkt);
63 const struct GUID *object;
64 uint16_t opnum;
65 DATA_BLOB request_data;
66 bool ignore_timeout;
67 bool wait_for_sync;
68 bool verify_bitmask1;
69 bool verify_pcontext;
71 struct {
72 void (*callback)(struct rpc_request *);
73 void *private_data;
74 } async;
77 _PUBLIC_ NTSTATUS dcerpc_init(void)
79 return gensec_init();
82 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
83 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
85 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
86 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);
106 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
107 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
108 bool trigger_read);
109 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
111 /* destroy a dcerpc connection */
112 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
114 if (conn->dead) {
115 conn->free_skipped = true;
116 return -1;
118 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
119 return 0;
123 /* initialise a dcerpc connection.
124 the event context is optional
126 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
127 struct tevent_context *ev)
129 struct dcecli_connection *c;
131 c = talloc_zero(mem_ctx, struct dcecli_connection);
132 if (!c) {
133 return NULL;
136 c->event_ctx = ev;
138 if (c->event_ctx == NULL) {
139 talloc_free(c);
140 return NULL;
143 c->call_id = 1;
144 c->security_state.auth_type = DCERPC_AUTH_TYPE_NONE;
145 c->security_state.auth_level = DCERPC_AUTH_LEVEL_NONE;
146 c->security_state.auth_context_id = 0;
147 c->security_state.session_key = dcerpc_generic_session_key;
148 c->security_state.generic_state = NULL;
149 c->flags = 0;
151 * Windows uses 5840 for ncacn_ip_tcp,
152 * so we also use it (for every transport)
153 * by default. But we give the transport
154 * the chance to overwrite it.
156 c->srv_max_xmit_frag = 5840;
157 c->srv_max_recv_frag = 5840;
158 c->pending = NULL;
160 c->io_trigger = tevent_create_immediate(c);
161 if (c->io_trigger == NULL) {
162 talloc_free(c);
163 return NULL;
166 talloc_set_destructor(c, dcerpc_connection_destructor);
168 return c;
171 struct dcerpc_bh_state {
172 struct dcerpc_pipe *p;
175 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
177 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
178 struct dcerpc_bh_state);
180 if (!hs->p) {
181 return false;
184 if (!hs->p->conn) {
185 return false;
188 if (hs->p->conn->dead) {
189 return false;
192 return true;
195 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
196 uint32_t timeout)
198 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
199 struct dcerpc_bh_state);
200 uint32_t old;
202 if (!hs->p) {
203 return DCERPC_REQUEST_TIMEOUT;
206 old = hs->p->request_timeout;
207 hs->p->request_timeout = timeout;
209 return old;
212 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
213 enum dcerpc_AuthType *auth_type,
214 enum dcerpc_AuthLevel *auth_level)
216 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
217 struct dcerpc_bh_state);
219 if (hs->p == NULL) {
220 return;
223 if (hs->p->conn == NULL) {
224 return;
227 *auth_type = hs->p->conn->security_state.auth_type;
228 *auth_level = hs->p->conn->security_state.auth_level;
231 struct dcerpc_bh_raw_call_state {
232 struct tevent_context *ev;
233 struct dcerpc_binding_handle *h;
234 DATA_BLOB in_data;
235 DATA_BLOB out_data;
236 uint32_t out_flags;
239 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
241 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
242 struct tevent_context *ev,
243 struct dcerpc_binding_handle *h,
244 const struct GUID *object,
245 uint32_t opnum,
246 uint32_t in_flags,
247 const uint8_t *in_data,
248 size_t in_length)
250 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
251 struct dcerpc_bh_state);
252 struct tevent_req *req;
253 struct dcerpc_bh_raw_call_state *state;
254 bool ok;
255 struct rpc_request *subreq;
257 req = tevent_req_create(mem_ctx, &state,
258 struct dcerpc_bh_raw_call_state);
259 if (req == NULL) {
260 return NULL;
262 state->ev = ev;
263 state->h = h;
264 state->in_data.data = discard_const_p(uint8_t, in_data);
265 state->in_data.length = in_length;
267 ok = dcerpc_bh_is_connected(h);
268 if (!ok) {
269 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
270 return tevent_req_post(req, ev);
273 subreq = dcerpc_request_send(state,
274 hs->p,
275 object,
276 opnum,
277 &state->in_data);
278 if (tevent_req_nomem(subreq, req)) {
279 return tevent_req_post(req, ev);
281 subreq->async.callback = dcerpc_bh_raw_call_done;
282 subreq->async.private_data = req;
284 return req;
287 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
289 struct tevent_req *req =
290 talloc_get_type_abort(subreq->async.private_data,
291 struct tevent_req);
292 struct dcerpc_bh_raw_call_state *state =
293 tevent_req_data(req,
294 struct dcerpc_bh_raw_call_state);
295 NTSTATUS status;
296 uint32_t fault_code;
298 state->out_flags = 0;
299 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
300 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
303 fault_code = subreq->fault_code;
305 status = dcerpc_request_recv(subreq, state, &state->out_data);
306 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
307 status = dcerpc_fault_to_nt_status(fault_code);
311 * We trigger the callback in the next event run
312 * because the code in this file might trigger
313 * multiple request callbacks from within a single
314 * while loop.
316 * In order to avoid segfaults from within
317 * dcerpc_connection_dead() we call
318 * tevent_req_defer_callback().
320 tevent_req_defer_callback(req, state->ev);
322 if (!NT_STATUS_IS_OK(status)) {
323 tevent_req_nterror(req, status);
324 return;
327 tevent_req_done(req);
330 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
331 TALLOC_CTX *mem_ctx,
332 uint8_t **out_data,
333 size_t *out_length,
334 uint32_t *out_flags)
336 struct dcerpc_bh_raw_call_state *state =
337 tevent_req_data(req,
338 struct dcerpc_bh_raw_call_state);
339 NTSTATUS status;
341 if (tevent_req_is_nterror(req, &status)) {
342 tevent_req_received(req);
343 return status;
346 *out_data = talloc_move(mem_ctx, &state->out_data.data);
347 *out_length = state->out_data.length;
348 *out_flags = state->out_flags;
349 tevent_req_received(req);
350 return NT_STATUS_OK;
353 struct dcerpc_bh_disconnect_state {
354 uint8_t _dummy;
357 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
358 struct tevent_context *ev,
359 struct dcerpc_binding_handle *h)
361 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
362 struct dcerpc_bh_state);
363 struct tevent_req *req;
364 struct dcerpc_bh_disconnect_state *state;
365 bool ok;
367 req = tevent_req_create(mem_ctx, &state,
368 struct dcerpc_bh_disconnect_state);
369 if (req == NULL) {
370 return NULL;
373 ok = dcerpc_bh_is_connected(h);
374 if (!ok) {
375 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
376 return tevent_req_post(req, ev);
379 /* TODO: do a real disconnect ... */
380 hs->p = NULL;
382 tevent_req_done(req);
383 return tevent_req_post(req, ev);
386 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
388 NTSTATUS status;
390 if (tevent_req_is_nterror(req, &status)) {
391 tevent_req_received(req);
392 return status;
395 tevent_req_received(req);
396 return NT_STATUS_OK;
399 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
401 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
402 struct dcerpc_bh_state);
404 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
405 return true;
408 return false;
411 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
413 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
414 struct dcerpc_bh_state);
416 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
417 return true;
420 return false;
423 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
425 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
426 struct dcerpc_bh_state);
428 if (hs->p->conn->flags & DCERPC_NDR64) {
429 return true;
432 return false;
435 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
436 int ndr_flags,
437 const void *_struct_ptr,
438 const struct ndr_interface_call *call)
440 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
441 struct dcerpc_bh_state);
442 void *struct_ptr = discard_const(_struct_ptr);
444 if (ndr_flags & NDR_IN) {
445 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
446 ndr_print_function_debug(call->ndr_print,
447 call->name,
448 ndr_flags,
449 struct_ptr);
452 if (ndr_flags & NDR_OUT) {
453 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
454 ndr_print_function_debug(call->ndr_print,
455 call->name,
456 ndr_flags,
457 struct_ptr);
462 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
463 NTSTATUS error,
464 const void *struct_ptr,
465 const struct ndr_interface_call *call)
467 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
468 call->name, nt_errstr(error)));
471 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
472 NTSTATUS error,
473 const DATA_BLOB *blob,
474 const struct ndr_interface_call *call)
476 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
477 struct dcerpc_bh_state);
478 const uint32_t num_examples = 20;
479 uint32_t i;
481 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
482 call->name, nt_errstr(error)));
484 if (hs->p->conn->packet_log_dir == NULL) return;
486 for (i=0;i<num_examples;i++) {
487 char *name=NULL;
488 int ret;
490 ret = asprintf(&name, "%s/rpclog/%s-out.%d",
491 hs->p->conn->packet_log_dir,
492 call->name, i);
493 if (ret == -1) {
494 return;
496 if (!file_exist(name)) {
497 if (file_save(name, blob->data, blob->length)) {
498 DEBUG(10,("Logged rpc packet to %s\n", name));
500 free(name);
501 break;
503 free(name);
507 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
508 TALLOC_CTX *mem_ctx,
509 const DATA_BLOB *blob,
510 const struct ndr_interface_call *call)
512 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
513 struct dcerpc_bh_state);
515 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
516 NTSTATUS status;
518 status = dcerpc_ndr_validate_in(hs->p->conn,
519 mem_ctx,
520 *blob,
521 call->struct_size,
522 call->ndr_push,
523 call->ndr_pull);
524 if (!NT_STATUS_IS_OK(status)) {
525 DEBUG(0,("Validation [in] failed for %s - %s\n",
526 call->name, nt_errstr(status)));
527 return status;
531 DEBUG(10,("rpc request data:\n"));
532 dump_data(10, blob->data, blob->length);
534 return NT_STATUS_OK;
537 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
538 struct ndr_pull *pull_in,
539 const void *_struct_ptr,
540 const struct ndr_interface_call *call)
542 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
543 struct dcerpc_bh_state);
544 void *struct_ptr = discard_const(_struct_ptr);
546 DEBUG(10,("rpc reply data:\n"));
547 dump_data(10, pull_in->data, pull_in->data_size);
549 if (pull_in->offset != pull_in->data_size) {
550 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
551 pull_in->data_size - pull_in->offset,
552 pull_in->offset, pull_in->offset,
553 call->name));
554 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
555 but it turns out that early versions of NT
556 (specifically NT3.1) add junk onto the end of rpc
557 packets, so if we want to interoperate at all with
558 those versions then we need to ignore this error */
561 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
562 NTSTATUS status;
564 status = dcerpc_ndr_validate_out(hs->p->conn,
565 pull_in,
566 struct_ptr,
567 call->struct_size,
568 call->ndr_push,
569 call->ndr_pull,
570 call->ndr_print);
571 if (!NT_STATUS_IS_OK(status)) {
572 DEBUG(2,("Validation [out] failed for %s - %s\n",
573 call->name, nt_errstr(status)));
574 return status;
578 return NT_STATUS_OK;
581 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
582 .name = "dcerpc",
583 .is_connected = dcerpc_bh_is_connected,
584 .set_timeout = dcerpc_bh_set_timeout,
585 .auth_info = dcerpc_bh_auth_info,
586 .raw_call_send = dcerpc_bh_raw_call_send,
587 .raw_call_recv = dcerpc_bh_raw_call_recv,
588 .disconnect_send = dcerpc_bh_disconnect_send,
589 .disconnect_recv = dcerpc_bh_disconnect_recv,
591 .push_bigendian = dcerpc_bh_push_bigendian,
592 .ref_alloc = dcerpc_bh_ref_alloc,
593 .use_ndr64 = dcerpc_bh_use_ndr64,
594 .do_ndr_print = dcerpc_bh_do_ndr_print,
595 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
596 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
597 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
598 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
601 /* initialise a dcerpc pipe. */
602 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
604 struct dcerpc_binding_handle *h;
605 struct dcerpc_bh_state *hs;
607 h = dcerpc_binding_handle_create(p,
608 &dcerpc_bh_ops,
609 NULL,
610 NULL, /* TODO */
611 &hs,
612 struct dcerpc_bh_state,
613 __location__);
614 if (h == NULL) {
615 return NULL;
617 hs->p = p;
619 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
621 return h;
624 /* initialise a dcerpc pipe. */
625 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
627 struct dcerpc_pipe *p;
629 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
630 if (!p) {
631 return NULL;
634 p->conn = dcerpc_connection_init(p, ev);
635 if (p->conn == NULL) {
636 talloc_free(p);
637 return NULL;
640 p->last_fault_code = 0;
641 p->context_id = 0;
642 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
643 p->binding = NULL;
645 ZERO_STRUCT(p->syntax);
646 ZERO_STRUCT(p->transfer_syntax);
648 if (DEBUGLVL(100)) {
649 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
652 p->binding_handle = dcerpc_pipe_binding_handle(p);
653 if (p->binding_handle == NULL) {
654 talloc_free(p);
655 return NULL;
658 return p;
663 choose the next call id to use
665 static uint32_t next_call_id(struct dcecli_connection *c)
667 c->call_id++;
668 if (c->call_id == 0) {
669 c->call_id++;
671 return c->call_id;
675 setup for a ndr pull, also setting up any flags from the binding string
677 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
678 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
680 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
682 if (ndr == NULL) return ndr;
684 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
685 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
688 if (c->flags & DCERPC_NDR_REF_ALLOC) {
689 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
692 if (c->flags & DCERPC_NDR64) {
693 ndr->flags |= LIBNDR_FLAG_NDR64;
696 return ndr;
700 parse a data blob into a ncacn_packet structure. This handles both
701 input and output packets
703 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
704 struct ncacn_packet *pkt)
706 struct ndr_pull *ndr;
707 enum ndr_err_code ndr_err;
709 ndr = ndr_pull_init_blob(blob, mem_ctx);
710 if (!ndr) {
711 return NT_STATUS_NO_MEMORY;
714 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
715 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
718 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
719 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
722 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
723 TALLOC_FREE(ndr);
724 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
725 return ndr_map_error2ntstatus(ndr_err);
728 if (pkt->frag_length != blob->length) {
729 return NT_STATUS_RPC_PROTOCOL_ERROR;
732 return NT_STATUS_OK;
736 parse the authentication information on a dcerpc response packet
738 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
739 DATA_BLOB *raw_packet,
740 struct ncacn_packet *pkt)
742 NTSTATUS status;
743 struct dcerpc_auth auth;
744 uint32_t auth_length;
746 status = dcerpc_verify_ncacn_packet_header(pkt, DCERPC_PKT_RESPONSE,
747 pkt->u.response.stub_and_verifier.length,
748 0, /* required_flags */
749 DCERPC_PFC_FLAG_FIRST |
750 DCERPC_PFC_FLAG_LAST);
751 if (!NT_STATUS_IS_OK(status)) {
752 return status;
755 switch (c->security_state.auth_level) {
756 case DCERPC_AUTH_LEVEL_PRIVACY:
757 case DCERPC_AUTH_LEVEL_INTEGRITY:
758 break;
760 case DCERPC_AUTH_LEVEL_CONNECT:
761 if (pkt->auth_length != 0) {
762 break;
764 return NT_STATUS_OK;
765 case DCERPC_AUTH_LEVEL_NONE:
766 if (pkt->auth_length != 0) {
767 return NT_STATUS_INVALID_NETWORK_RESPONSE;
769 return NT_STATUS_OK;
771 default:
772 return NT_STATUS_INVALID_LEVEL;
775 if (pkt->auth_length == 0) {
776 return NT_STATUS_INVALID_NETWORK_RESPONSE;
779 if (c->security_state.generic_state == NULL) {
780 return NT_STATUS_INTERNAL_ERROR;
783 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
784 &pkt->u.response.stub_and_verifier,
785 &auth, &auth_length, false);
786 NT_STATUS_NOT_OK_RETURN(status);
788 pkt->u.response.stub_and_verifier.length -= auth_length;
790 if (auth.auth_type != c->security_state.auth_type) {
791 return NT_STATUS_RPC_PROTOCOL_ERROR;
794 if (auth.auth_level != c->security_state.auth_level) {
795 return NT_STATUS_RPC_PROTOCOL_ERROR;
798 if (auth.auth_context_id != c->security_state.auth_context_id) {
799 return NT_STATUS_RPC_PROTOCOL_ERROR;
802 /* check signature or unseal the packet */
803 switch (c->security_state.auth_level) {
804 case DCERPC_AUTH_LEVEL_PRIVACY:
805 status = gensec_unseal_packet(c->security_state.generic_state,
806 raw_packet->data + DCERPC_REQUEST_LENGTH,
807 pkt->u.response.stub_and_verifier.length,
808 raw_packet->data,
809 raw_packet->length - auth.credentials.length,
810 &auth.credentials);
811 memcpy(pkt->u.response.stub_and_verifier.data,
812 raw_packet->data + DCERPC_REQUEST_LENGTH,
813 pkt->u.response.stub_and_verifier.length);
814 break;
816 case DCERPC_AUTH_LEVEL_INTEGRITY:
817 status = gensec_check_packet(c->security_state.generic_state,
818 pkt->u.response.stub_and_verifier.data,
819 pkt->u.response.stub_and_verifier.length,
820 raw_packet->data,
821 raw_packet->length - auth.credentials.length,
822 &auth.credentials);
823 break;
825 case DCERPC_AUTH_LEVEL_CONNECT:
826 /* for now we ignore possible signatures here */
827 status = NT_STATUS_OK;
828 break;
830 default:
831 status = NT_STATUS_INVALID_LEVEL;
832 break;
835 /* remove the indicated amount of padding */
836 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
837 return NT_STATUS_INFO_LENGTH_MISMATCH;
839 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
841 return status;
846 push a dcerpc request packet into a blob, possibly signing it.
848 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
849 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
850 size_t sig_size,
851 struct ncacn_packet *pkt)
853 NTSTATUS status;
854 struct ndr_push *ndr;
855 DATA_BLOB creds2;
856 size_t payload_length;
857 enum ndr_err_code ndr_err;
858 size_t hdr_size = DCERPC_REQUEST_LENGTH;
859 struct dcerpc_auth auth_info = {
860 .auth_type = c->security_state.auth_type,
861 .auth_level = c->security_state.auth_level,
862 .auth_context_id = c->security_state.auth_context_id,
865 switch (c->security_state.auth_level) {
866 case DCERPC_AUTH_LEVEL_PRIVACY:
867 case DCERPC_AUTH_LEVEL_INTEGRITY:
868 if (sig_size == 0) {
869 return NT_STATUS_INTERNAL_ERROR;
871 break;
873 case DCERPC_AUTH_LEVEL_CONNECT:
874 /* TODO: let the gensec mech decide if it wants to generate a signature */
875 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
877 case DCERPC_AUTH_LEVEL_NONE:
878 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
880 default:
881 return NT_STATUS_INVALID_LEVEL;
884 ndr = ndr_push_init_ctx(mem_ctx);
885 if (!ndr) {
886 return NT_STATUS_NO_MEMORY;
889 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
890 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
893 if (c->flags & DCERPC_NDR64) {
894 ndr->flags |= LIBNDR_FLAG_NDR64;
897 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
898 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
899 hdr_size += 16;
902 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
903 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
904 return ndr_map_error2ntstatus(ndr_err);
907 /* pad to 16 byte multiple in the payload portion of the
908 packet. This matches what w2k3 does. Note that we can't use
909 ndr_push_align() as that is relative to the start of the
910 whole packet, whereas w2k8 wants it relative to the start
911 of the stub */
912 auth_info.auth_pad_length =
913 DCERPC_AUTH_PAD_LENGTH(pkt->u.request.stub_and_verifier.length);
914 ndr_err = ndr_push_zero(ndr, auth_info.auth_pad_length);
915 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
916 return ndr_map_error2ntstatus(ndr_err);
919 payload_length = pkt->u.request.stub_and_verifier.length +
920 auth_info.auth_pad_length;
922 /* add the auth verifier */
923 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth_info);
924 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
925 return ndr_map_error2ntstatus(ndr_err);
928 /* extract the whole packet as a blob */
929 *blob = ndr_push_blob(ndr);
932 * Setup the frag and auth length in the packet buffer.
933 * This is needed if the GENSEC mech does AEAD signing
934 * of the packet headers. The signature itself will be
935 * appended later.
937 dcerpc_set_frag_length(blob, blob->length + sig_size);
938 dcerpc_set_auth_length(blob, sig_size);
940 /* sign or seal the packet */
941 switch (c->security_state.auth_level) {
942 case DCERPC_AUTH_LEVEL_PRIVACY:
943 status = gensec_seal_packet(c->security_state.generic_state,
944 mem_ctx,
945 blob->data + hdr_size,
946 payload_length,
947 blob->data,
948 blob->length,
949 &creds2);
950 if (!NT_STATUS_IS_OK(status)) {
951 return status;
953 break;
955 case DCERPC_AUTH_LEVEL_INTEGRITY:
956 status = gensec_sign_packet(c->security_state.generic_state,
957 mem_ctx,
958 blob->data + hdr_size,
959 payload_length,
960 blob->data,
961 blob->length,
962 &creds2);
963 if (!NT_STATUS_IS_OK(status)) {
964 return status;
966 break;
968 default:
969 status = NT_STATUS_INVALID_LEVEL;
970 break;
973 if (creds2.length != sig_size) {
974 /* this means the sig_size estimate for the signature
975 was incorrect. We have to correct the packet
976 sizes. That means we could go over the max fragment
977 length */
978 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
979 (unsigned) creds2.length,
980 (unsigned) sig_size,
981 (unsigned) auth_info.auth_pad_length,
982 (unsigned) pkt->u.request.stub_and_verifier.length));
983 dcerpc_set_frag_length(blob, blob->length + creds2.length);
984 dcerpc_set_auth_length(blob, creds2.length);
987 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
988 return NT_STATUS_NO_MEMORY;
991 return NT_STATUS_OK;
996 fill in the fixed values in a dcerpc header
998 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
1000 pkt->rpc_vers = 5;
1001 pkt->rpc_vers_minor = 0;
1002 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1003 pkt->drep[0] = 0;
1004 } else {
1005 pkt->drep[0] = DCERPC_DREP_LE;
1007 pkt->drep[1] = 0;
1008 pkt->drep[2] = 0;
1009 pkt->drep[3] = 0;
1013 map a bind nak reason to a NTSTATUS
1015 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
1017 switch (reason) {
1018 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
1019 return NT_STATUS_REVISION_MISMATCH;
1020 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
1021 return NT_STATUS_INVALID_PARAMETER;
1022 default:
1023 break;
1025 return NT_STATUS_UNSUCCESSFUL;
1028 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
1030 if (ack == NULL) {
1031 return NT_STATUS_RPC_PROTOCOL_ERROR;
1034 switch (ack->result) {
1035 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
1037 * We have not asked for this...
1039 return NT_STATUS_RPC_PROTOCOL_ERROR;
1040 default:
1041 break;
1044 switch (ack->reason.value) {
1045 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1046 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1047 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1048 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1049 default:
1050 break;
1052 return NT_STATUS_UNSUCCESSFUL;
1056 remove requests from the pending or queued queues
1058 static int dcerpc_req_dequeue(struct rpc_request *req)
1060 switch (req->state) {
1061 case RPC_REQUEST_QUEUED:
1062 DLIST_REMOVE(req->p->conn->request_queue, req);
1063 break;
1064 case RPC_REQUEST_PENDING:
1065 DLIST_REMOVE(req->p->conn->pending, req);
1066 break;
1067 case RPC_REQUEST_DONE:
1068 break;
1070 return 0;
1075 mark the dcerpc connection dead. All outstanding requests get an error
1077 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1079 if (conn->dead) return;
1081 conn->dead = true;
1083 TALLOC_FREE(conn->io_trigger);
1084 conn->io_trigger_pending = false;
1086 dcerpc_shutdown_pipe(conn, status);
1088 /* all pending requests get the error */
1089 while (conn->pending) {
1090 struct rpc_request *req = conn->pending;
1091 dcerpc_req_dequeue(req);
1092 req->state = RPC_REQUEST_DONE;
1093 req->status = status;
1094 if (req->async.callback) {
1095 req->async.callback(req);
1099 /* all requests, which are not shipped */
1100 while (conn->request_queue) {
1101 struct rpc_request *req = conn->request_queue;
1102 dcerpc_req_dequeue(req);
1103 req->state = RPC_REQUEST_DONE;
1104 req->status = status;
1105 if (req->async.callback) {
1106 req->async.callback(req);
1110 talloc_set_destructor(conn, NULL);
1111 if (conn->free_skipped) {
1112 talloc_free(conn);
1117 forward declarations of the recv_data handlers for the types of
1118 packets we need to handle
1120 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1121 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1124 receive a dcerpc reply from the transport. Here we work out what
1125 type of reply it is (normal request, bind or alter context) and
1126 dispatch to the appropriate handler
1128 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1130 struct ncacn_packet pkt;
1132 if (conn->dead) {
1133 return;
1136 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1137 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1140 /* the transport may be telling us of a severe error, such as
1141 a dropped socket */
1142 if (!NT_STATUS_IS_OK(status)) {
1143 data_blob_free(blob);
1144 dcerpc_connection_dead(conn, status);
1145 return;
1148 /* parse the basic packet to work out what type of response this is */
1149 status = ncacn_pull(conn, blob, blob->data, &pkt);
1150 if (!NT_STATUS_IS_OK(status)) {
1151 data_blob_free(blob);
1152 dcerpc_connection_dead(conn, status);
1153 return;
1156 dcerpc_request_recv_data(conn, blob, &pkt);
1160 handle timeouts of individual dcerpc requests
1162 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1163 struct timeval t, void *private_data)
1165 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1167 if (req->ignore_timeout) {
1168 dcerpc_req_dequeue(req);
1169 req->state = RPC_REQUEST_DONE;
1170 req->status = NT_STATUS_IO_TIMEOUT;
1171 if (req->async.callback) {
1172 req->async.callback(req);
1174 return;
1177 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1180 struct dcerpc_bind_state {
1181 struct tevent_context *ev;
1182 struct dcerpc_pipe *p;
1185 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1186 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1187 DATA_BLOB *raw_packet,
1188 struct ncacn_packet *pkt);
1190 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1191 struct tevent_context *ev,
1192 struct dcerpc_pipe *p,
1193 const struct ndr_syntax_id *syntax,
1194 const struct ndr_syntax_id *transfer_syntax)
1196 struct tevent_req *req;
1197 struct dcerpc_bind_state *state;
1198 struct ncacn_packet pkt;
1199 DATA_BLOB blob;
1200 NTSTATUS status;
1201 struct rpc_request *subreq;
1202 uint32_t flags;
1204 req = tevent_req_create(mem_ctx, &state,
1205 struct dcerpc_bind_state);
1206 if (req == NULL) {
1207 return NULL;
1210 state->ev = ev;
1211 state->p = p;
1213 p->syntax = *syntax;
1214 p->transfer_syntax = *transfer_syntax;
1216 flags = dcerpc_binding_get_flags(p->binding);
1218 init_ncacn_hdr(p->conn, &pkt);
1220 pkt.ptype = DCERPC_PKT_BIND;
1221 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1222 pkt.call_id = p->conn->call_id;
1223 pkt.auth_length = 0;
1225 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1226 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1229 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1230 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1233 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1234 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1235 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1236 pkt.u.bind.num_contexts = 1;
1237 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1238 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1239 return tevent_req_post(req, ev);
1241 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1242 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1243 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1244 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1245 pkt.u.bind.auth_info = data_blob(NULL, 0);
1247 /* construct the NDR form of the packet */
1248 status = ncacn_push_auth(&blob, state, &pkt,
1249 p->conn->security_state.tmp_auth_info.out);
1250 if (tevent_req_nterror(req, status)) {
1251 return tevent_req_post(req, ev);
1255 * we allocate a dcerpc_request so we can be in the same
1256 * request queue as normal requests
1258 subreq = talloc_zero(state, struct rpc_request);
1259 if (tevent_req_nomem(subreq, req)) {
1260 return tevent_req_post(req, ev);
1263 subreq->state = RPC_REQUEST_PENDING;
1264 subreq->call_id = pkt.call_id;
1265 subreq->async.private_data = req;
1266 subreq->async.callback = dcerpc_bind_fail_handler;
1267 subreq->p = p;
1268 subreq->recv_handler = dcerpc_bind_recv_handler;
1269 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1270 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1272 status = dcerpc_send_request(p->conn, &blob, true);
1273 if (tevent_req_nterror(req, status)) {
1274 return tevent_req_post(req, ev);
1277 tevent_add_timer(ev, subreq,
1278 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1279 dcerpc_timeout_handler, subreq);
1281 return req;
1284 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1286 struct tevent_req *req =
1287 talloc_get_type_abort(subreq->async.private_data,
1288 struct tevent_req);
1289 struct dcerpc_bind_state *state =
1290 tevent_req_data(req,
1291 struct dcerpc_bind_state);
1292 NTSTATUS status = subreq->status;
1294 TALLOC_FREE(subreq);
1297 * We trigger the callback in the next event run
1298 * because the code in this file might trigger
1299 * multiple request callbacks from within a single
1300 * while loop.
1302 * In order to avoid segfaults from within
1303 * dcerpc_connection_dead() we call
1304 * tevent_req_defer_callback().
1306 tevent_req_defer_callback(req, state->ev);
1308 tevent_req_nterror(req, status);
1311 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1312 DATA_BLOB *raw_packet,
1313 struct ncacn_packet *pkt)
1315 struct tevent_req *req =
1316 talloc_get_type_abort(subreq->async.private_data,
1317 struct tevent_req);
1318 struct dcerpc_bind_state *state =
1319 tevent_req_data(req,
1320 struct dcerpc_bind_state);
1321 struct dcecli_connection *conn = state->p->conn;
1322 struct dcecli_security *sec = &conn->security_state;
1323 struct dcerpc_binding *b = NULL;
1324 NTSTATUS status;
1325 uint32_t flags;
1328 * Note that pkt is allocated under raw_packet->data,
1329 * while raw_packet->data is a child of subreq.
1331 talloc_steal(state, raw_packet->data);
1332 TALLOC_FREE(subreq);
1335 * We trigger the callback in the next event run
1336 * because the code in this file might trigger
1337 * multiple request callbacks from within a single
1338 * while loop.
1340 * In order to avoid segfaults from within
1341 * dcerpc_connection_dead() we call
1342 * tevent_req_defer_callback().
1344 tevent_req_defer_callback(req, state->ev);
1346 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1347 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1349 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1350 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1352 tevent_req_nterror(req, status);
1353 return;
1356 status = dcerpc_verify_ncacn_packet_header(pkt,
1357 DCERPC_PKT_BIND_ACK,
1358 pkt->u.bind_ack.auth_info.length,
1359 DCERPC_PFC_FLAG_FIRST |
1360 DCERPC_PFC_FLAG_LAST,
1361 DCERPC_PFC_FLAG_CONC_MPX |
1362 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
1363 if (!NT_STATUS_IS_OK(status)) {
1364 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1365 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1366 return;
1369 if (pkt->u.bind_ack.num_results != 1) {
1370 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1371 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1372 return;
1375 if (pkt->u.bind_ack.ctx_list[0].result != 0) {
1376 status = dcerpc_map_ack_reason(&pkt->u.bind_ack.ctx_list[0]);
1377 DEBUG(2,("dcerpc: bind_ack failed - reason %d - %s\n",
1378 pkt->u.bind_ack.ctx_list[0].reason.value,
1379 nt_errstr(status)));
1380 tevent_req_nterror(req, status);
1381 return;
1385 * DCE-RPC 1.1 (c706) specifies
1386 * CONST_MUST_RCV_FRAG_SIZE as 1432
1388 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1389 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1390 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1391 return;
1393 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1394 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1395 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1396 return;
1398 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1399 pkt->u.bind_ack.max_xmit_frag);
1400 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1401 pkt->u.bind_ack.max_recv_frag);
1403 flags = dcerpc_binding_get_flags(state->p->binding);
1405 if ((flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1406 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1407 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1410 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1411 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1412 conn->flags |= DCERPC_HEADER_SIGNING;
1415 /* the bind_ack might contain a reply set of credentials */
1416 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
1417 uint32_t auth_length;
1419 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
1420 &pkt->u.bind_ack.auth_info,
1421 sec->tmp_auth_info.in,
1422 &auth_length, true);
1423 if (tevent_req_nterror(req, status)) {
1424 return;
1429 * We're the owner of the binding, so we're allowed to modify it.
1431 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1432 status = dcerpc_binding_set_assoc_group_id(b,
1433 pkt->u.bind_ack.assoc_group_id);
1434 if (tevent_req_nterror(req, status)) {
1435 return;
1438 tevent_req_done(req);
1441 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1443 return tevent_req_simple_recv_ntstatus(req);
1447 perform a continued bind (and auth3)
1449 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1450 TALLOC_CTX *mem_ctx)
1452 struct ncacn_packet pkt;
1453 NTSTATUS status;
1454 DATA_BLOB blob;
1455 uint32_t flags;
1457 flags = dcerpc_binding_get_flags(p->binding);
1459 init_ncacn_hdr(p->conn, &pkt);
1461 pkt.ptype = DCERPC_PKT_AUTH3;
1462 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1463 pkt.call_id = next_call_id(p->conn);
1464 pkt.auth_length = 0;
1465 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1467 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1468 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1471 /* construct the NDR form of the packet */
1472 status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1473 p->conn->security_state.tmp_auth_info.out);
1474 if (!NT_STATUS_IS_OK(status)) {
1475 return status;
1478 /* send it on its way */
1479 status = dcerpc_send_request(p->conn, &blob, false);
1480 if (!NT_STATUS_IS_OK(status)) {
1481 return status;
1484 return NT_STATUS_OK;
1489 process a fragment received from the transport layer during a
1490 request
1492 This function frees the data
1494 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1495 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1497 struct rpc_request *req;
1498 unsigned int length;
1499 NTSTATUS status = NT_STATUS_OK;
1502 if this is an authenticated connection then parse and check
1503 the auth info. We have to do this before finding the
1504 matching packet, as the request structure might have been
1505 removed due to a timeout, but if it has been we still need
1506 to run the auth routines so that we don't get the sign/seal
1507 info out of step with the server
1509 if (pkt->ptype == DCERPC_PKT_RESPONSE) {
1510 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1513 /* find the matching request */
1514 for (req=c->pending;req;req=req->next) {
1515 if (pkt->call_id == req->call_id) break;
1518 #if 0
1519 /* useful for testing certain vendors RPC servers */
1520 if (req == NULL && c->pending && pkt->call_id == 0) {
1521 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1522 req = c->pending;
1524 #endif
1526 if (req == NULL) {
1527 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1528 data_blob_free(raw_packet);
1529 return;
1532 talloc_steal(req, raw_packet->data);
1534 if (req->recv_handler != NULL) {
1535 dcerpc_req_dequeue(req);
1536 req->state = RPC_REQUEST_DONE;
1539 * We have to look at shipping further requests before calling
1540 * the async function, that one might close the pipe
1542 dcerpc_schedule_io_trigger(c);
1544 req->recv_handler(req, raw_packet, pkt);
1545 return;
1548 if (pkt->ptype == DCERPC_PKT_FAULT) {
1549 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1550 req->fault_code = pkt->u.fault.status;
1551 req->status = NT_STATUS_NET_WRITE_FAULT;
1552 goto req_done;
1555 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1556 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1557 (int)pkt->ptype));
1558 req->fault_code = DCERPC_FAULT_OTHER;
1559 req->status = NT_STATUS_NET_WRITE_FAULT;
1560 goto req_done;
1563 /* now check the status from the auth routines, and if it failed then fail
1564 this request accordingly */
1565 if (!NT_STATUS_IS_OK(status)) {
1566 req->status = status;
1567 goto req_done;
1570 length = pkt->u.response.stub_and_verifier.length;
1572 if (length > 0) {
1573 req->payload.data = talloc_realloc(req,
1574 req->payload.data,
1575 uint8_t,
1576 req->payload.length + length);
1577 if (!req->payload.data) {
1578 req->status = NT_STATUS_NO_MEMORY;
1579 goto req_done;
1581 memcpy(req->payload.data+req->payload.length,
1582 pkt->u.response.stub_and_verifier.data, length);
1583 req->payload.length += length;
1586 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1587 data_blob_free(raw_packet);
1588 dcerpc_send_read(c);
1589 return;
1592 if (req->verify_bitmask1) {
1593 req->p->conn->security_state.verified_bitmask1 = true;
1595 if (req->verify_pcontext) {
1596 req->p->verified_pcontext = true;
1599 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1600 req->flags |= DCERPC_PULL_BIGENDIAN;
1601 } else {
1602 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1605 req_done:
1606 data_blob_free(raw_packet);
1608 /* we've got the full payload */
1609 dcerpc_req_dequeue(req);
1610 req->state = RPC_REQUEST_DONE;
1613 * We have to look at shipping further requests before calling
1614 * the async function, that one might close the pipe
1616 dcerpc_schedule_io_trigger(c);
1618 if (req->async.callback) {
1619 req->async.callback(req);
1623 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1626 perform the send side of a async dcerpc request
1628 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1629 struct dcerpc_pipe *p,
1630 const struct GUID *object,
1631 uint16_t opnum,
1632 DATA_BLOB *stub_data)
1634 struct rpc_request *req;
1635 NTSTATUS status;
1637 req = talloc_zero(mem_ctx, struct rpc_request);
1638 if (req == NULL) {
1639 return NULL;
1642 req->p = p;
1643 req->call_id = next_call_id(p->conn);
1644 req->state = RPC_REQUEST_QUEUED;
1646 if (object != NULL) {
1647 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1648 if (req->object == NULL) {
1649 talloc_free(req);
1650 return NULL;
1654 req->opnum = opnum;
1655 req->request_data.length = stub_data->length;
1656 req->request_data.data = stub_data->data;
1658 status = dcerpc_request_prepare_vt(req);
1659 if (!NT_STATUS_IS_OK(status)) {
1660 talloc_free(req);
1661 return NULL;
1664 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1665 talloc_set_destructor(req, dcerpc_req_dequeue);
1667 dcerpc_schedule_io_trigger(p->conn);
1669 if (p->request_timeout) {
1670 tevent_add_timer(p->conn->event_ctx, req,
1671 timeval_current_ofs(p->request_timeout, 0),
1672 dcerpc_timeout_handler, req);
1675 return req;
1678 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1680 struct dcecli_security *sec = &req->p->conn->security_state;
1681 struct dcerpc_sec_verification_trailer *t;
1682 struct dcerpc_sec_vt *c = NULL;
1683 struct ndr_push *ndr = NULL;
1684 enum ndr_err_code ndr_err;
1686 if (sec->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
1687 return NT_STATUS_OK;
1690 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1691 if (t == NULL) {
1692 return NT_STATUS_NO_MEMORY;
1695 if (!sec->verified_bitmask1) {
1696 t->commands = talloc_realloc(t, t->commands,
1697 struct dcerpc_sec_vt,
1698 t->count.count + 1);
1699 if (t->commands == NULL) {
1700 return NT_STATUS_NO_MEMORY;
1702 c = &t->commands[t->count.count++];
1703 ZERO_STRUCTP(c);
1705 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1706 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1707 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1709 req->verify_bitmask1 = true;
1712 if (!req->p->verified_pcontext) {
1713 t->commands = talloc_realloc(t, t->commands,
1714 struct dcerpc_sec_vt,
1715 t->count.count + 1);
1716 if (t->commands == NULL) {
1717 return NT_STATUS_NO_MEMORY;
1719 c = &t->commands[t->count.count++];
1720 ZERO_STRUCTP(c);
1722 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1723 c->u.pcontext.abstract_syntax = req->p->syntax;
1724 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1726 req->verify_pcontext = true;
1729 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1730 t->commands = talloc_realloc(t, t->commands,
1731 struct dcerpc_sec_vt,
1732 t->count.count + 1);
1733 if (t->commands == NULL) {
1734 return NT_STATUS_NO_MEMORY;
1736 c = &t->commands[t->count.count++];
1737 ZERO_STRUCTP(c);
1739 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1740 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1741 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1742 c->u.header2.drep[0] = 0;
1743 } else {
1744 c->u.header2.drep[0] = DCERPC_DREP_LE;
1746 c->u.header2.drep[1] = 0;
1747 c->u.header2.drep[2] = 0;
1748 c->u.header2.drep[3] = 0;
1749 c->u.header2.call_id = req->call_id;
1750 c->u.header2.context_id = req->p->context_id;
1751 c->u.header2.opnum = req->opnum;
1754 if (t->count.count == 0) {
1755 TALLOC_FREE(t);
1756 return NT_STATUS_OK;
1759 c = &t->commands[t->count.count - 1];
1760 c->command |= DCERPC_SEC_VT_COMMAND_END;
1762 if (DEBUGLEVEL >= 10) {
1763 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1766 ndr = ndr_push_init_ctx(req);
1767 if (ndr == NULL) {
1768 return NT_STATUS_NO_MEMORY;
1772 * for now we just copy and append
1775 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1776 req->request_data.length);
1777 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1778 return ndr_map_error2ntstatus(ndr_err);
1781 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1782 NDR_SCALARS | NDR_BUFFERS,
1784 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1785 return ndr_map_error2ntstatus(ndr_err);
1787 req->request_data = ndr_push_blob(ndr);
1789 return NT_STATUS_OK;
1793 Send a request using the transport
1796 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1798 struct rpc_request *req;
1799 struct dcerpc_pipe *p;
1800 DATA_BLOB *stub_data;
1801 struct ncacn_packet pkt;
1802 DATA_BLOB blob;
1803 uint32_t remaining, chunk_size;
1804 bool first_packet = true;
1805 size_t sig_size = 0;
1806 bool need_async = false;
1807 bool can_async = true;
1809 req = c->request_queue;
1810 if (req == NULL) {
1811 return;
1814 p = req->p;
1815 stub_data = &req->request_data;
1817 if (c->pending) {
1818 need_async = true;
1821 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
1822 can_async = gensec_have_feature(c->security_state.generic_state,
1823 GENSEC_FEATURE_ASYNC_REPLIES);
1826 if (need_async && !can_async) {
1827 req->wait_for_sync = true;
1828 return;
1831 DLIST_REMOVE(c->request_queue, req);
1832 DLIST_ADD(c->pending, req);
1833 req->state = RPC_REQUEST_PENDING;
1835 init_ncacn_hdr(p->conn, &pkt);
1837 remaining = stub_data->length;
1839 /* we can write a full max_recv_frag size, minus the dcerpc
1840 request header size */
1841 chunk_size = p->conn->srv_max_recv_frag;
1842 chunk_size -= DCERPC_REQUEST_LENGTH;
1843 if (c->security_state.auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
1844 size_t max_payload = chunk_size;
1846 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1847 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1849 sig_size = gensec_sig_size(c->security_state.generic_state,
1850 max_payload);
1851 if (sig_size) {
1852 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1853 chunk_size -= sig_size;
1856 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1858 pkt.ptype = DCERPC_PKT_REQUEST;
1859 pkt.call_id = req->call_id;
1860 pkt.auth_length = 0;
1861 pkt.pfc_flags = 0;
1862 pkt.u.request.context_id = p->context_id;
1863 pkt.u.request.opnum = req->opnum;
1865 if (req->object) {
1866 pkt.u.request.object.object = *req->object;
1867 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1868 chunk_size -= ndr_size_GUID(req->object,0);
1871 /* we send a series of pdus without waiting for a reply */
1872 while (remaining > 0 || first_packet) {
1873 uint32_t chunk = MIN(chunk_size, remaining);
1874 bool last_frag = false;
1875 bool do_trans = false;
1877 first_packet = false;
1878 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1880 if (remaining == stub_data->length) {
1881 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1883 if (chunk == remaining) {
1884 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1885 last_frag = true;
1888 pkt.u.request.alloc_hint = remaining;
1889 pkt.u.request.stub_and_verifier.data = stub_data->data +
1890 (stub_data->length - remaining);
1891 pkt.u.request.stub_and_verifier.length = chunk;
1893 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1894 if (!NT_STATUS_IS_OK(req->status)) {
1895 req->state = RPC_REQUEST_DONE;
1896 DLIST_REMOVE(p->conn->pending, req);
1897 return;
1900 if (last_frag && !need_async) {
1901 do_trans = true;
1904 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1905 if (!NT_STATUS_IS_OK(req->status)) {
1906 req->state = RPC_REQUEST_DONE;
1907 DLIST_REMOVE(p->conn->pending, req);
1908 return;
1911 if (last_frag && !do_trans) {
1912 req->status = dcerpc_send_read(p->conn);
1913 if (!NT_STATUS_IS_OK(req->status)) {
1914 req->state = RPC_REQUEST_DONE;
1915 DLIST_REMOVE(p->conn->pending, req);
1916 return;
1920 remaining -= chunk;
1924 static void dcerpc_io_trigger(struct tevent_context *ctx,
1925 struct tevent_immediate *im,
1926 void *private_data)
1928 struct dcecli_connection *c =
1929 talloc_get_type_abort(private_data,
1930 struct dcecli_connection);
1932 c->io_trigger_pending = false;
1934 dcerpc_schedule_io_trigger(c);
1936 dcerpc_ship_next_request(c);
1939 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1941 if (c->dead) {
1942 return;
1945 if (c->request_queue == NULL) {
1946 return;
1949 if (c->request_queue->wait_for_sync && c->pending) {
1950 return;
1953 if (c->io_trigger_pending) {
1954 return;
1957 c->io_trigger_pending = true;
1959 tevent_schedule_immediate(c->io_trigger,
1960 c->event_ctx,
1961 dcerpc_io_trigger,
1966 perform the receive side of a async dcerpc request
1968 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1969 TALLOC_CTX *mem_ctx,
1970 DATA_BLOB *stub_data)
1972 NTSTATUS status;
1974 while (req->state != RPC_REQUEST_DONE) {
1975 struct tevent_context *ctx = req->p->conn->event_ctx;
1976 if (tevent_loop_once(ctx) != 0) {
1977 return NT_STATUS_CONNECTION_DISCONNECTED;
1980 *stub_data = req->payload;
1981 status = req->status;
1982 if (stub_data->data) {
1983 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1985 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1986 req->p->last_fault_code = req->fault_code;
1988 talloc_unlink(talloc_parent(req), req);
1989 return status;
1993 this is a paranoid NDR validator. For every packet we push onto the wire
1994 we pull it back again, then push it again. Then we compare the raw NDR data
1995 for that to the NDR we initially generated. If they don't match then we know
1996 we must have a bug in either the pull or push side of our code
1998 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1999 TALLOC_CTX *mem_ctx,
2000 DATA_BLOB blob,
2001 size_t struct_size,
2002 ndr_push_flags_fn_t ndr_push,
2003 ndr_pull_flags_fn_t ndr_pull)
2005 void *st;
2006 struct ndr_pull *pull;
2007 struct ndr_push *push;
2008 DATA_BLOB blob2;
2009 enum ndr_err_code ndr_err;
2011 st = talloc_size(mem_ctx, struct_size);
2012 if (!st) {
2013 return NT_STATUS_NO_MEMORY;
2016 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2017 if (!pull) {
2018 return NT_STATUS_NO_MEMORY;
2020 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2022 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2023 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
2026 if (c->flags & DCERPC_NDR64) {
2027 pull->flags |= LIBNDR_FLAG_NDR64;
2030 ndr_err = ndr_pull(pull, NDR_IN, st);
2031 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2032 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2033 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2034 "failed input validation pull - %s",
2035 nt_errstr(status));
2036 return ndr_map_error2ntstatus(ndr_err);
2039 push = ndr_push_init_ctx(mem_ctx);
2040 if (!push) {
2041 return NT_STATUS_NO_MEMORY;
2044 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2045 push->flags |= LIBNDR_FLAG_BIGENDIAN;
2048 if (c->flags & DCERPC_NDR64) {
2049 push->flags |= LIBNDR_FLAG_NDR64;
2052 ndr_err = ndr_push(push, NDR_IN, st);
2053 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2054 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2055 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2056 "failed input validation push - %s",
2057 nt_errstr(status));
2058 return ndr_map_error2ntstatus(ndr_err);
2061 blob2 = ndr_push_blob(push);
2063 if (data_blob_cmp(&blob, &blob2) != 0) {
2064 DEBUG(3,("original:\n"));
2065 dump_data(3, blob.data, blob.length);
2066 DEBUG(3,("secondary:\n"));
2067 dump_data(3, blob2.data, blob2.length);
2068 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2069 "failed input validation blobs doesn't match");
2070 return ndr_map_error2ntstatus(ndr_err);
2073 return NT_STATUS_OK;
2077 this is a paranoid NDR input validator. For every packet we pull
2078 from the wire we push it back again then pull and push it
2079 again. Then we compare the raw NDR data for that to the NDR we
2080 initially generated. If they don't match then we know we must have a
2081 bug in either the pull or push side of our code
2083 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
2084 struct ndr_pull *pull_in,
2085 void *struct_ptr,
2086 size_t struct_size,
2087 ndr_push_flags_fn_t ndr_push,
2088 ndr_pull_flags_fn_t ndr_pull,
2089 ndr_print_function_t ndr_print)
2091 void *st;
2092 struct ndr_pull *pull;
2093 struct ndr_push *push;
2094 DATA_BLOB blob, blob2;
2095 TALLOC_CTX *mem_ctx = pull_in;
2096 char *s1, *s2;
2097 enum ndr_err_code ndr_err;
2099 st = talloc_size(mem_ctx, struct_size);
2100 if (!st) {
2101 return NT_STATUS_NO_MEMORY;
2103 memcpy(st, struct_ptr, struct_size);
2105 push = ndr_push_init_ctx(mem_ctx);
2106 if (!push) {
2107 return NT_STATUS_NO_MEMORY;
2110 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2111 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2112 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2113 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2114 "failed output validation push - %s",
2115 nt_errstr(status));
2116 return ndr_map_error2ntstatus(ndr_err);
2119 blob = ndr_push_blob(push);
2121 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2122 if (!pull) {
2123 return NT_STATUS_NO_MEMORY;
2126 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2127 ndr_err = ndr_pull(pull, NDR_OUT, st);
2128 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2129 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2130 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2131 "failed output validation pull - %s",
2132 nt_errstr(status));
2133 return ndr_map_error2ntstatus(ndr_err);
2136 push = ndr_push_init_ctx(mem_ctx);
2137 if (!push) {
2138 return NT_STATUS_NO_MEMORY;
2141 ndr_err = ndr_push(push, NDR_OUT, st);
2142 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2143 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2144 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2145 "failed output validation push2 - %s",
2146 nt_errstr(status));
2147 return ndr_map_error2ntstatus(ndr_err);
2150 blob2 = ndr_push_blob(push);
2152 if (data_blob_cmp(&blob, &blob2) != 0) {
2153 DEBUG(3,("original:\n"));
2154 dump_data(3, blob.data, blob.length);
2155 DEBUG(3,("secondary:\n"));
2156 dump_data(3, blob2.data, blob2.length);
2157 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2158 "failed output validation blobs doesn't match");
2159 return ndr_map_error2ntstatus(ndr_err);
2162 /* this checks the printed forms of the two structures, which effectively
2163 tests all of the value() attributes */
2164 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2165 NDR_OUT, struct_ptr);
2166 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2167 NDR_OUT, st);
2168 if (strcmp(s1, s2) != 0) {
2169 #if 1
2170 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2171 #else
2172 /* this is sometimes useful */
2173 printf("VALIDATE ERROR\n");
2174 file_save("wire.dat", s1, strlen(s1));
2175 file_save("gen.dat", s2, strlen(s2));
2176 system("diff -u wire.dat gen.dat");
2177 #endif
2178 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2179 "failed output validation strings doesn't match");
2180 return ndr_map_error2ntstatus(ndr_err);
2183 return NT_STATUS_OK;
2187 a useful function for retrieving the server name we connected to
2189 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2191 return p->conn ? p->conn->server_name : NULL;
2196 get the dcerpc auth_level for a open connection
2198 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2200 uint8_t auth_level;
2202 if (c->flags & DCERPC_SEAL) {
2203 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2204 } else if (c->flags & DCERPC_SIGN) {
2205 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2206 } else if (c->flags & DCERPC_CONNECT) {
2207 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2208 } else {
2209 auth_level = DCERPC_AUTH_LEVEL_NONE;
2211 return auth_level;
2214 struct dcerpc_alter_context_state {
2215 struct tevent_context *ev;
2216 struct dcerpc_pipe *p;
2219 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2220 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2221 DATA_BLOB *raw_packet,
2222 struct ncacn_packet *pkt);
2224 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2225 struct tevent_context *ev,
2226 struct dcerpc_pipe *p,
2227 const struct ndr_syntax_id *syntax,
2228 const struct ndr_syntax_id *transfer_syntax)
2230 struct tevent_req *req;
2231 struct dcerpc_alter_context_state *state;
2232 struct ncacn_packet pkt;
2233 DATA_BLOB blob;
2234 NTSTATUS status;
2235 struct rpc_request *subreq;
2236 uint32_t flags;
2238 req = tevent_req_create(mem_ctx, &state,
2239 struct dcerpc_alter_context_state);
2240 if (req == NULL) {
2241 return NULL;
2244 state->ev = ev;
2245 state->p = p;
2247 p->syntax = *syntax;
2248 p->transfer_syntax = *transfer_syntax;
2250 flags = dcerpc_binding_get_flags(p->binding);
2252 init_ncacn_hdr(p->conn, &pkt);
2254 pkt.ptype = DCERPC_PKT_ALTER;
2255 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2256 pkt.call_id = p->conn->call_id;
2257 pkt.auth_length = 0;
2259 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2260 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2263 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2264 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2265 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2266 pkt.u.alter.num_contexts = 1;
2267 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2268 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2269 return tevent_req_post(req, ev);
2271 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2272 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2273 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2274 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2275 pkt.u.alter.auth_info = data_blob(NULL, 0);
2277 /* construct the NDR form of the packet */
2278 status = ncacn_push_auth(&blob, state, &pkt,
2279 p->conn->security_state.tmp_auth_info.out);
2280 if (tevent_req_nterror(req, status)) {
2281 return tevent_req_post(req, ev);
2285 * we allocate a dcerpc_request so we can be in the same
2286 * request queue as normal requests
2288 subreq = talloc_zero(state, struct rpc_request);
2289 if (tevent_req_nomem(subreq, req)) {
2290 return tevent_req_post(req, ev);
2293 subreq->state = RPC_REQUEST_PENDING;
2294 subreq->call_id = pkt.call_id;
2295 subreq->async.private_data = req;
2296 subreq->async.callback = dcerpc_alter_context_fail_handler;
2297 subreq->p = p;
2298 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2299 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2300 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2302 status = dcerpc_send_request(p->conn, &blob, true);
2303 if (tevent_req_nterror(req, status)) {
2304 return tevent_req_post(req, ev);
2307 tevent_add_timer(ev, subreq,
2308 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2309 dcerpc_timeout_handler, subreq);
2311 return req;
2314 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2316 struct tevent_req *req =
2317 talloc_get_type_abort(subreq->async.private_data,
2318 struct tevent_req);
2319 struct dcerpc_alter_context_state *state =
2320 tevent_req_data(req,
2321 struct dcerpc_alter_context_state);
2322 NTSTATUS status = subreq->status;
2324 TALLOC_FREE(subreq);
2327 * We trigger the callback in the next event run
2328 * because the code in this file might trigger
2329 * multiple request callbacks from within a single
2330 * while loop.
2332 * In order to avoid segfaults from within
2333 * dcerpc_connection_dead() we call
2334 * tevent_req_defer_callback().
2336 tevent_req_defer_callback(req, state->ev);
2338 tevent_req_nterror(req, status);
2341 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2342 DATA_BLOB *raw_packet,
2343 struct ncacn_packet *pkt)
2345 struct tevent_req *req =
2346 talloc_get_type_abort(subreq->async.private_data,
2347 struct tevent_req);
2348 struct dcerpc_alter_context_state *state =
2349 tevent_req_data(req,
2350 struct dcerpc_alter_context_state);
2351 struct dcecli_connection *conn = state->p->conn;
2352 struct dcecli_security *sec = &conn->security_state;
2353 NTSTATUS status;
2356 * Note that pkt is allocated under raw_packet->data,
2357 * while raw_packet->data is a child of subreq.
2359 talloc_steal(state, raw_packet->data);
2360 TALLOC_FREE(subreq);
2363 * We trigger the callback in the next event run
2364 * because the code in this file might trigger
2365 * multiple request callbacks from within a single
2366 * while loop.
2368 * In order to avoid segfaults from within
2369 * dcerpc_connection_dead() we call
2370 * tevent_req_defer_callback().
2372 tevent_req_defer_callback(req, state->ev);
2374 if (pkt->ptype == DCERPC_PKT_FAULT) {
2375 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2376 dcerpc_errstr(state, pkt->u.fault.status)));
2377 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2378 state->p->last_fault_code = pkt->u.fault.status;
2379 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2380 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2381 state->p->last_fault_code = pkt->u.fault.status;
2382 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2383 } else {
2384 state->p->last_fault_code = pkt->u.fault.status;
2385 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2386 tevent_req_nterror(req, status);
2388 return;
2391 status = dcerpc_verify_ncacn_packet_header(pkt,
2392 DCERPC_PKT_ALTER_RESP,
2393 pkt->u.alter_resp.auth_info.length,
2394 DCERPC_PFC_FLAG_FIRST |
2395 DCERPC_PFC_FLAG_LAST,
2396 DCERPC_PFC_FLAG_CONC_MPX |
2397 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
2398 if (!NT_STATUS_IS_OK(status)) {
2399 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2400 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2401 return;
2404 if (pkt->u.alter_resp.num_results != 1) {
2405 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2406 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2407 return;
2410 if (pkt->u.alter_resp.ctx_list[0].result != 0) {
2411 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2412 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2413 pkt->u.alter_resp.ctx_list[0].reason.value,
2414 nt_errstr(status)));
2415 tevent_req_nterror(req, status);
2416 return;
2419 /* the alter_resp might contain a reply set of credentials */
2420 if (pkt->auth_length != 0 && sec->tmp_auth_info.in != NULL) {
2421 uint32_t auth_length;
2423 status = dcerpc_pull_auth_trailer(pkt, sec->tmp_auth_info.mem,
2424 &pkt->u.alter_resp.auth_info,
2425 sec->tmp_auth_info.in,
2426 &auth_length, true);
2427 if (tevent_req_nterror(req, status)) {
2428 return;
2432 tevent_req_done(req);
2435 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2437 return tevent_req_simple_recv_ntstatus(req);
2441 send a dcerpc alter_context request
2443 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2444 TALLOC_CTX *mem_ctx,
2445 const struct ndr_syntax_id *syntax,
2446 const struct ndr_syntax_id *transfer_syntax)
2448 struct tevent_req *subreq;
2449 struct tevent_context *ev = p->conn->event_ctx;
2450 bool ok;
2452 /* TODO: create a new event context here */
2454 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2455 p, syntax, transfer_syntax);
2456 if (subreq == NULL) {
2457 return NT_STATUS_NO_MEMORY;
2460 ok = tevent_req_poll(subreq, ev);
2461 if (!ok) {
2462 NTSTATUS status;
2463 status = map_nt_error_from_unix_common(errno);
2464 return status;
2467 return dcerpc_alter_context_recv(subreq);
2470 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2472 if (c->transport.stream == NULL) {
2473 return;
2476 tevent_queue_stop(c->transport.write_queue);
2477 TALLOC_FREE(c->transport.read_subreq);
2478 TALLOC_FREE(c->transport.stream);
2480 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2481 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2484 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2485 status = NT_STATUS_END_OF_FILE;
2488 dcerpc_recv_data(c, NULL, status);
2493 shutdown SMB pipe connection
2495 struct dcerpc_shutdown_pipe_state {
2496 struct dcecli_connection *c;
2497 NTSTATUS status;
2500 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2502 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2504 struct dcerpc_shutdown_pipe_state *state;
2505 struct tevent_req *subreq;
2507 if (c->transport.stream == NULL) {
2508 return NT_STATUS_OK;
2511 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2512 if (state == NULL) {
2513 return NT_STATUS_NO_MEMORY;
2515 state->c = c;
2516 state->status = status;
2518 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2519 if (subreq == NULL) {
2520 return NT_STATUS_NO_MEMORY;
2522 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2524 return status;
2527 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2529 struct dcerpc_shutdown_pipe_state *state =
2530 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2531 struct dcecli_connection *c = state->c;
2532 NTSTATUS status = state->status;
2533 int error;
2536 * here we ignore the return values...
2538 tstream_disconnect_recv(subreq, &error);
2539 TALLOC_FREE(subreq);
2541 TALLOC_FREE(state);
2543 dcerpc_transport_dead(c, status);
2548 struct dcerpc_send_read_state {
2549 struct dcecli_connection *p;
2552 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2554 struct dcecli_connection *p = state->p;
2556 p->transport.read_subreq = NULL;
2558 return 0;
2561 static void dcerpc_send_read_done(struct tevent_req *subreq);
2563 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2565 struct dcerpc_send_read_state *state;
2567 if (p->transport.read_subreq != NULL) {
2568 p->transport.pending_reads++;
2569 return NT_STATUS_OK;
2572 state = talloc_zero(p, struct dcerpc_send_read_state);
2573 if (state == NULL) {
2574 return NT_STATUS_NO_MEMORY;
2576 state->p = p;
2578 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2580 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2581 p->event_ctx,
2582 p->transport.stream);
2583 if (p->transport.read_subreq == NULL) {
2584 return NT_STATUS_NO_MEMORY;
2586 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2588 return NT_STATUS_OK;
2591 static void dcerpc_send_read_done(struct tevent_req *subreq)
2593 struct dcerpc_send_read_state *state =
2594 tevent_req_callback_data(subreq,
2595 struct dcerpc_send_read_state);
2596 struct dcecli_connection *p = state->p;
2597 NTSTATUS status;
2598 struct ncacn_packet *pkt;
2599 DATA_BLOB blob;
2601 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2602 &pkt, &blob);
2603 TALLOC_FREE(subreq);
2604 if (!NT_STATUS_IS_OK(status)) {
2605 TALLOC_FREE(state);
2606 dcerpc_transport_dead(p, status);
2607 return;
2611 * here we steal into thet connection context,
2612 * but p->transport.recv_data() will steal or free it again
2614 talloc_steal(p, blob.data);
2615 TALLOC_FREE(state);
2617 if (p->transport.pending_reads > 0) {
2618 p->transport.pending_reads--;
2620 status = dcerpc_send_read(p);
2621 if (!NT_STATUS_IS_OK(status)) {
2622 dcerpc_transport_dead(p, status);
2623 return;
2627 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2630 struct dcerpc_send_request_state {
2631 struct dcecli_connection *p;
2632 DATA_BLOB blob;
2633 struct iovec iov;
2636 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2638 struct dcecli_connection *p = state->p;
2640 p->transport.read_subreq = NULL;
2642 return 0;
2645 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2646 static void dcerpc_send_request_done(struct tevent_req *subreq);
2648 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2649 bool trigger_read)
2651 struct dcerpc_send_request_state *state;
2652 struct tevent_req *subreq;
2653 bool use_trans = trigger_read;
2655 if (p->transport.stream == NULL) {
2656 return NT_STATUS_CONNECTION_DISCONNECTED;
2659 state = talloc_zero(p, struct dcerpc_send_request_state);
2660 if (state == NULL) {
2661 return NT_STATUS_NO_MEMORY;
2663 state->p = p;
2665 state->blob = data_blob_talloc(state, data->data, data->length);
2666 if (state->blob.data == NULL) {
2667 TALLOC_FREE(state);
2668 return NT_STATUS_NO_MEMORY;
2670 state->iov.iov_base = (void *)state->blob.data;
2671 state->iov.iov_len = state->blob.length;
2673 if (p->transport.read_subreq != NULL) {
2674 use_trans = false;
2677 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2678 use_trans = false;
2681 if (use_trans) {
2683 * we need to block reads until our write is
2684 * the next in the write queue.
2686 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2687 p->transport.write_queue);
2688 if (p->transport.read_subreq == NULL) {
2689 TALLOC_FREE(state);
2690 return NT_STATUS_NO_MEMORY;
2692 tevent_req_set_callback(p->transport.read_subreq,
2693 dcerpc_send_request_wait_done,
2694 state);
2696 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2698 trigger_read = false;
2701 subreq = tstream_writev_queue_send(state, p->event_ctx,
2702 p->transport.stream,
2703 p->transport.write_queue,
2704 &state->iov, 1);
2705 if (subreq == NULL) {
2706 TALLOC_FREE(state);
2707 return NT_STATUS_NO_MEMORY;
2709 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2711 if (trigger_read) {
2712 dcerpc_send_read(p);
2715 return NT_STATUS_OK;
2718 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2720 struct dcerpc_send_request_state *state =
2721 tevent_req_callback_data(subreq,
2722 struct dcerpc_send_request_state);
2723 struct dcecli_connection *p = state->p;
2724 NTSTATUS status;
2725 bool ok;
2727 p->transport.read_subreq = NULL;
2728 talloc_set_destructor(state, NULL);
2730 ok = tevent_queue_wait_recv(subreq);
2731 if (!ok) {
2732 TALLOC_FREE(state);
2733 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2734 return;
2737 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2738 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2739 if (!NT_STATUS_IS_OK(status)) {
2740 TALLOC_FREE(state);
2741 dcerpc_transport_dead(p, status);
2742 return;
2746 /* we free subreq after tstream_cli_np_use_trans */
2747 TALLOC_FREE(subreq);
2749 dcerpc_send_read(p);
2752 static void dcerpc_send_request_done(struct tevent_req *subreq)
2754 struct dcerpc_send_request_state *state =
2755 tevent_req_callback_data(subreq,
2756 struct dcerpc_send_request_state);
2757 int ret;
2758 int error;
2760 ret = tstream_writev_queue_recv(subreq, &error);
2761 TALLOC_FREE(subreq);
2762 if (ret == -1) {
2763 struct dcecli_connection *p = state->p;
2764 NTSTATUS status = map_nt_error_from_unix_common(error);
2766 TALLOC_FREE(state);
2767 dcerpc_transport_dead(p, status);
2768 return;
2771 TALLOC_FREE(state);