CVE-2015-5370: s4:librpc/rpc: avoid using c->security_state.auth_info in ncacn_pull_r...
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blobf470e9ed2ae3f5fdfa05145e4f3312ebbac05dcb
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.auth_info = NULL;
148 c->security_state.session_key = dcerpc_generic_session_key;
149 c->security_state.generic_state = NULL;
150 c->flags = 0;
152 * Windows uses 5840 for ncacn_ip_tcp,
153 * so we also use it (for every transport)
154 * by default. But we give the transport
155 * the chance to overwrite it.
157 c->srv_max_xmit_frag = 5840;
158 c->srv_max_recv_frag = 5840;
159 c->pending = NULL;
161 c->io_trigger = tevent_create_immediate(c);
162 if (c->io_trigger == NULL) {
163 talloc_free(c);
164 return NULL;
167 talloc_set_destructor(c, dcerpc_connection_destructor);
169 return c;
172 struct dcerpc_bh_state {
173 struct dcerpc_pipe *p;
176 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
178 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
179 struct dcerpc_bh_state);
181 if (!hs->p) {
182 return false;
185 if (!hs->p->conn) {
186 return false;
189 if (hs->p->conn->dead) {
190 return false;
193 return true;
196 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
197 uint32_t timeout)
199 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
200 struct dcerpc_bh_state);
201 uint32_t old;
203 if (!hs->p) {
204 return DCERPC_REQUEST_TIMEOUT;
207 old = hs->p->request_timeout;
208 hs->p->request_timeout = timeout;
210 return old;
213 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
214 enum dcerpc_AuthType *auth_type,
215 enum dcerpc_AuthLevel *auth_level)
217 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
218 struct dcerpc_bh_state);
220 if (hs->p == NULL) {
221 return;
224 if (hs->p->conn == NULL) {
225 return;
228 *auth_type = hs->p->conn->security_state.auth_type;
229 *auth_level = hs->p->conn->security_state.auth_level;
232 struct dcerpc_bh_raw_call_state {
233 struct tevent_context *ev;
234 struct dcerpc_binding_handle *h;
235 DATA_BLOB in_data;
236 DATA_BLOB out_data;
237 uint32_t out_flags;
240 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
242 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
243 struct tevent_context *ev,
244 struct dcerpc_binding_handle *h,
245 const struct GUID *object,
246 uint32_t opnum,
247 uint32_t in_flags,
248 const uint8_t *in_data,
249 size_t in_length)
251 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
252 struct dcerpc_bh_state);
253 struct tevent_req *req;
254 struct dcerpc_bh_raw_call_state *state;
255 bool ok;
256 struct rpc_request *subreq;
258 req = tevent_req_create(mem_ctx, &state,
259 struct dcerpc_bh_raw_call_state);
260 if (req == NULL) {
261 return NULL;
263 state->ev = ev;
264 state->h = h;
265 state->in_data.data = discard_const_p(uint8_t, in_data);
266 state->in_data.length = in_length;
268 ok = dcerpc_bh_is_connected(h);
269 if (!ok) {
270 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
271 return tevent_req_post(req, ev);
274 subreq = dcerpc_request_send(state,
275 hs->p,
276 object,
277 opnum,
278 &state->in_data);
279 if (tevent_req_nomem(subreq, req)) {
280 return tevent_req_post(req, ev);
282 subreq->async.callback = dcerpc_bh_raw_call_done;
283 subreq->async.private_data = req;
285 return req;
288 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
290 struct tevent_req *req =
291 talloc_get_type_abort(subreq->async.private_data,
292 struct tevent_req);
293 struct dcerpc_bh_raw_call_state *state =
294 tevent_req_data(req,
295 struct dcerpc_bh_raw_call_state);
296 NTSTATUS status;
297 uint32_t fault_code;
299 state->out_flags = 0;
300 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
301 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
304 fault_code = subreq->fault_code;
306 status = dcerpc_request_recv(subreq, state, &state->out_data);
307 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
308 status = dcerpc_fault_to_nt_status(fault_code);
312 * We trigger the callback in the next event run
313 * because the code in this file might trigger
314 * multiple request callbacks from within a single
315 * while loop.
317 * In order to avoid segfaults from within
318 * dcerpc_connection_dead() we call
319 * tevent_req_defer_callback().
321 tevent_req_defer_callback(req, state->ev);
323 if (!NT_STATUS_IS_OK(status)) {
324 tevent_req_nterror(req, status);
325 return;
328 tevent_req_done(req);
331 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
332 TALLOC_CTX *mem_ctx,
333 uint8_t **out_data,
334 size_t *out_length,
335 uint32_t *out_flags)
337 struct dcerpc_bh_raw_call_state *state =
338 tevent_req_data(req,
339 struct dcerpc_bh_raw_call_state);
340 NTSTATUS status;
342 if (tevent_req_is_nterror(req, &status)) {
343 tevent_req_received(req);
344 return status;
347 *out_data = talloc_move(mem_ctx, &state->out_data.data);
348 *out_length = state->out_data.length;
349 *out_flags = state->out_flags;
350 tevent_req_received(req);
351 return NT_STATUS_OK;
354 struct dcerpc_bh_disconnect_state {
355 uint8_t _dummy;
358 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
359 struct tevent_context *ev,
360 struct dcerpc_binding_handle *h)
362 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
363 struct dcerpc_bh_state);
364 struct tevent_req *req;
365 struct dcerpc_bh_disconnect_state *state;
366 bool ok;
368 req = tevent_req_create(mem_ctx, &state,
369 struct dcerpc_bh_disconnect_state);
370 if (req == NULL) {
371 return NULL;
374 ok = dcerpc_bh_is_connected(h);
375 if (!ok) {
376 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
377 return tevent_req_post(req, ev);
380 /* TODO: do a real disconnect ... */
381 hs->p = NULL;
383 tevent_req_done(req);
384 return tevent_req_post(req, ev);
387 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
389 NTSTATUS status;
391 if (tevent_req_is_nterror(req, &status)) {
392 tevent_req_received(req);
393 return status;
396 tevent_req_received(req);
397 return NT_STATUS_OK;
400 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
402 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
403 struct dcerpc_bh_state);
405 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
406 return true;
409 return false;
412 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
414 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
415 struct dcerpc_bh_state);
417 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
418 return true;
421 return false;
424 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
426 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
427 struct dcerpc_bh_state);
429 if (hs->p->conn->flags & DCERPC_NDR64) {
430 return true;
433 return false;
436 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
437 int ndr_flags,
438 const void *_struct_ptr,
439 const struct ndr_interface_call *call)
441 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
442 struct dcerpc_bh_state);
443 void *struct_ptr = discard_const(_struct_ptr);
445 if (ndr_flags & NDR_IN) {
446 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
447 ndr_print_function_debug(call->ndr_print,
448 call->name,
449 ndr_flags,
450 struct_ptr);
453 if (ndr_flags & NDR_OUT) {
454 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
455 ndr_print_function_debug(call->ndr_print,
456 call->name,
457 ndr_flags,
458 struct_ptr);
463 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
464 NTSTATUS error,
465 const void *struct_ptr,
466 const struct ndr_interface_call *call)
468 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
469 call->name, nt_errstr(error)));
472 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
473 NTSTATUS error,
474 const DATA_BLOB *blob,
475 const struct ndr_interface_call *call)
477 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
478 struct dcerpc_bh_state);
479 const uint32_t num_examples = 20;
480 uint32_t i;
482 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
483 call->name, nt_errstr(error)));
485 if (hs->p->conn->packet_log_dir == NULL) return;
487 for (i=0;i<num_examples;i++) {
488 char *name=NULL;
489 asprintf(&name, "%s/rpclog/%s-out.%d",
490 hs->p->conn->packet_log_dir,
491 call->name, i);
492 if (name == NULL) {
493 return;
495 if (!file_exist(name)) {
496 if (file_save(name, blob->data, blob->length)) {
497 DEBUG(10,("Logged rpc packet to %s\n", name));
499 free(name);
500 break;
502 free(name);
506 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
507 TALLOC_CTX *mem_ctx,
508 const DATA_BLOB *blob,
509 const struct ndr_interface_call *call)
511 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
512 struct dcerpc_bh_state);
514 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
515 NTSTATUS status;
517 status = dcerpc_ndr_validate_in(hs->p->conn,
518 mem_ctx,
519 *blob,
520 call->struct_size,
521 call->ndr_push,
522 call->ndr_pull);
523 if (!NT_STATUS_IS_OK(status)) {
524 DEBUG(0,("Validation [in] failed for %s - %s\n",
525 call->name, nt_errstr(status)));
526 return status;
530 DEBUG(10,("rpc request data:\n"));
531 dump_data(10, blob->data, blob->length);
533 return NT_STATUS_OK;
536 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
537 struct ndr_pull *pull_in,
538 const void *_struct_ptr,
539 const struct ndr_interface_call *call)
541 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
542 struct dcerpc_bh_state);
543 void *struct_ptr = discard_const(_struct_ptr);
545 DEBUG(10,("rpc reply data:\n"));
546 dump_data(10, pull_in->data, pull_in->data_size);
548 if (pull_in->offset != pull_in->data_size) {
549 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
550 pull_in->data_size - pull_in->offset,
551 pull_in->offset, pull_in->offset,
552 call->name));
553 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
554 but it turns out that early versions of NT
555 (specifically NT3.1) add junk onto the end of rpc
556 packets, so if we want to interoperate at all with
557 those versions then we need to ignore this error */
560 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
561 NTSTATUS status;
563 status = dcerpc_ndr_validate_out(hs->p->conn,
564 pull_in,
565 struct_ptr,
566 call->struct_size,
567 call->ndr_push,
568 call->ndr_pull,
569 call->ndr_print);
570 if (!NT_STATUS_IS_OK(status)) {
571 DEBUG(2,("Validation [out] failed for %s - %s\n",
572 call->name, nt_errstr(status)));
573 return status;
577 return NT_STATUS_OK;
580 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
581 .name = "dcerpc",
582 .is_connected = dcerpc_bh_is_connected,
583 .set_timeout = dcerpc_bh_set_timeout,
584 .auth_info = dcerpc_bh_auth_info,
585 .raw_call_send = dcerpc_bh_raw_call_send,
586 .raw_call_recv = dcerpc_bh_raw_call_recv,
587 .disconnect_send = dcerpc_bh_disconnect_send,
588 .disconnect_recv = dcerpc_bh_disconnect_recv,
590 .push_bigendian = dcerpc_bh_push_bigendian,
591 .ref_alloc = dcerpc_bh_ref_alloc,
592 .use_ndr64 = dcerpc_bh_use_ndr64,
593 .do_ndr_print = dcerpc_bh_do_ndr_print,
594 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
595 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
596 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
597 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
600 /* initialise a dcerpc pipe. */
601 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
603 struct dcerpc_binding_handle *h;
604 struct dcerpc_bh_state *hs;
606 h = dcerpc_binding_handle_create(p,
607 &dcerpc_bh_ops,
608 NULL,
609 NULL, /* TODO */
610 &hs,
611 struct dcerpc_bh_state,
612 __location__);
613 if (h == NULL) {
614 return NULL;
616 hs->p = p;
618 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
620 return h;
623 /* initialise a dcerpc pipe. */
624 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
626 struct dcerpc_pipe *p;
628 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
629 if (!p) {
630 return NULL;
633 p->conn = dcerpc_connection_init(p, ev);
634 if (p->conn == NULL) {
635 talloc_free(p);
636 return NULL;
639 p->last_fault_code = 0;
640 p->context_id = 0;
641 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
642 p->binding = NULL;
644 ZERO_STRUCT(p->syntax);
645 ZERO_STRUCT(p->transfer_syntax);
647 if (DEBUGLVL(100)) {
648 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
651 p->binding_handle = dcerpc_pipe_binding_handle(p);
652 if (p->binding_handle == NULL) {
653 talloc_free(p);
654 return NULL;
657 return p;
662 choose the next call id to use
664 static uint32_t next_call_id(struct dcecli_connection *c)
666 c->call_id++;
667 if (c->call_id == 0) {
668 c->call_id++;
670 return c->call_id;
674 setup for a ndr pull, also setting up any flags from the binding string
676 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
677 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
679 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
681 if (ndr == NULL) return ndr;
683 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
684 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
687 if (c->flags & DCERPC_NDR_REF_ALLOC) {
688 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
691 if (c->flags & DCERPC_NDR64) {
692 ndr->flags |= LIBNDR_FLAG_NDR64;
695 return ndr;
699 parse a data blob into a ncacn_packet structure. This handles both
700 input and output packets
702 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
703 struct ncacn_packet *pkt)
705 struct ndr_pull *ndr;
706 enum ndr_err_code ndr_err;
708 ndr = ndr_pull_init_blob(blob, mem_ctx);
709 if (!ndr) {
710 return NT_STATUS_NO_MEMORY;
713 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
714 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
717 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
718 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
721 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
722 TALLOC_FREE(ndr);
723 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
724 return ndr_map_error2ntstatus(ndr_err);
727 if (pkt->frag_length != blob->length) {
728 return NT_STATUS_RPC_PROTOCOL_ERROR;
731 return NT_STATUS_OK;
735 parse the authentication information on a dcerpc response packet
737 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
738 DATA_BLOB *raw_packet,
739 struct ncacn_packet *pkt)
741 NTSTATUS status;
742 struct dcerpc_auth auth;
743 uint32_t auth_length;
745 switch (c->security_state.auth_level) {
746 case DCERPC_AUTH_LEVEL_PRIVACY:
747 case DCERPC_AUTH_LEVEL_INTEGRITY:
748 break;
750 case DCERPC_AUTH_LEVEL_CONNECT:
751 if (pkt->auth_length != 0) {
752 break;
754 return NT_STATUS_OK;
755 case DCERPC_AUTH_LEVEL_NONE:
756 if (pkt->auth_length != 0) {
757 return NT_STATUS_INVALID_NETWORK_RESPONSE;
759 return NT_STATUS_OK;
761 default:
762 return NT_STATUS_INVALID_LEVEL;
765 if (pkt->auth_length == 0) {
766 return NT_STATUS_INVALID_NETWORK_RESPONSE;
769 if (c->security_state.generic_state == NULL) {
770 return NT_STATUS_INTERNAL_ERROR;
773 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
774 &pkt->u.response.stub_and_verifier,
775 &auth, &auth_length, false);
776 NT_STATUS_NOT_OK_RETURN(status);
778 pkt->u.response.stub_and_verifier.length -= auth_length;
780 /* check signature or unseal the packet */
781 switch (c->security_state.auth_level) {
782 case DCERPC_AUTH_LEVEL_PRIVACY:
783 status = gensec_unseal_packet(c->security_state.generic_state,
784 raw_packet->data + DCERPC_REQUEST_LENGTH,
785 pkt->u.response.stub_and_verifier.length,
786 raw_packet->data,
787 raw_packet->length - auth.credentials.length,
788 &auth.credentials);
789 memcpy(pkt->u.response.stub_and_verifier.data,
790 raw_packet->data + DCERPC_REQUEST_LENGTH,
791 pkt->u.response.stub_and_verifier.length);
792 break;
794 case DCERPC_AUTH_LEVEL_INTEGRITY:
795 status = gensec_check_packet(c->security_state.generic_state,
796 pkt->u.response.stub_and_verifier.data,
797 pkt->u.response.stub_and_verifier.length,
798 raw_packet->data,
799 raw_packet->length - auth.credentials.length,
800 &auth.credentials);
801 break;
803 case DCERPC_AUTH_LEVEL_CONNECT:
804 /* for now we ignore possible signatures here */
805 status = NT_STATUS_OK;
806 break;
808 default:
809 status = NT_STATUS_INVALID_LEVEL;
810 break;
813 /* remove the indicated amount of padding */
814 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
815 return NT_STATUS_INFO_LENGTH_MISMATCH;
817 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
819 return status;
824 push a dcerpc request packet into a blob, possibly signing it.
826 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
827 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
828 size_t sig_size,
829 struct ncacn_packet *pkt)
831 NTSTATUS status;
832 struct ndr_push *ndr;
833 DATA_BLOB creds2;
834 size_t payload_length;
835 enum ndr_err_code ndr_err;
836 size_t hdr_size = DCERPC_REQUEST_LENGTH;
837 struct dcerpc_auth auth_info = {
838 .auth_type = c->security_state.auth_type,
839 .auth_level = c->security_state.auth_level,
840 .auth_context_id = c->security_state.auth_context_id,
843 switch (c->security_state.auth_level) {
844 case DCERPC_AUTH_LEVEL_PRIVACY:
845 case DCERPC_AUTH_LEVEL_INTEGRITY:
846 if (sig_size == 0) {
847 return NT_STATUS_INTERNAL_ERROR;
849 break;
851 case DCERPC_AUTH_LEVEL_CONNECT:
852 /* TODO: let the gensec mech decide if it wants to generate a signature */
853 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
855 case DCERPC_AUTH_LEVEL_NONE:
856 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
858 default:
859 return NT_STATUS_INVALID_LEVEL;
862 ndr = ndr_push_init_ctx(mem_ctx);
863 if (!ndr) {
864 return NT_STATUS_NO_MEMORY;
867 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
868 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
871 if (c->flags & DCERPC_NDR64) {
872 ndr->flags |= LIBNDR_FLAG_NDR64;
875 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
876 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
877 hdr_size += 16;
880 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
881 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
882 return ndr_map_error2ntstatus(ndr_err);
885 /* pad to 16 byte multiple in the payload portion of the
886 packet. This matches what w2k3 does. Note that we can't use
887 ndr_push_align() as that is relative to the start of the
888 whole packet, whereas w2k8 wants it relative to the start
889 of the stub */
890 auth_info.auth_pad_length =
891 DCERPC_AUTH_PAD_LENGTH(pkt->u.request.stub_and_verifier.length);
892 ndr_err = ndr_push_zero(ndr, auth_info.auth_pad_length);
893 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
894 return ndr_map_error2ntstatus(ndr_err);
897 payload_length = pkt->u.request.stub_and_verifier.length +
898 auth_info.auth_pad_length;
900 /* add the auth verifier */
901 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth_info);
902 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
903 return ndr_map_error2ntstatus(ndr_err);
906 /* extract the whole packet as a blob */
907 *blob = ndr_push_blob(ndr);
910 * Setup the frag and auth length in the packet buffer.
911 * This is needed if the GENSEC mech does AEAD signing
912 * of the packet headers. The signature itself will be
913 * appended later.
915 dcerpc_set_frag_length(blob, blob->length + sig_size);
916 dcerpc_set_auth_length(blob, sig_size);
918 /* sign or seal the packet */
919 switch (c->security_state.auth_level) {
920 case DCERPC_AUTH_LEVEL_PRIVACY:
921 status = gensec_seal_packet(c->security_state.generic_state,
922 mem_ctx,
923 blob->data + hdr_size,
924 payload_length,
925 blob->data,
926 blob->length,
927 &creds2);
928 if (!NT_STATUS_IS_OK(status)) {
929 return status;
931 break;
933 case DCERPC_AUTH_LEVEL_INTEGRITY:
934 status = gensec_sign_packet(c->security_state.generic_state,
935 mem_ctx,
936 blob->data + hdr_size,
937 payload_length,
938 blob->data,
939 blob->length,
940 &creds2);
941 if (!NT_STATUS_IS_OK(status)) {
942 return status;
944 break;
946 default:
947 status = NT_STATUS_INVALID_LEVEL;
948 break;
951 if (creds2.length != sig_size) {
952 /* this means the sig_size estimate for the signature
953 was incorrect. We have to correct the packet
954 sizes. That means we could go over the max fragment
955 length */
956 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
957 (unsigned) creds2.length,
958 (unsigned) sig_size,
959 (unsigned) auth_info.auth_pad_length,
960 (unsigned) pkt->u.request.stub_and_verifier.length));
961 dcerpc_set_frag_length(blob, blob->length + creds2.length);
962 dcerpc_set_auth_length(blob, creds2.length);
965 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
966 return NT_STATUS_NO_MEMORY;
969 return NT_STATUS_OK;
974 fill in the fixed values in a dcerpc header
976 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
978 pkt->rpc_vers = 5;
979 pkt->rpc_vers_minor = 0;
980 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
981 pkt->drep[0] = 0;
982 } else {
983 pkt->drep[0] = DCERPC_DREP_LE;
985 pkt->drep[1] = 0;
986 pkt->drep[2] = 0;
987 pkt->drep[3] = 0;
991 map a bind nak reason to a NTSTATUS
993 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
995 switch (reason) {
996 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
997 return NT_STATUS_REVISION_MISMATCH;
998 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
999 return NT_STATUS_INVALID_PARAMETER;
1000 default:
1001 break;
1003 return NT_STATUS_UNSUCCESSFUL;
1006 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
1008 if (ack == NULL) {
1009 return NT_STATUS_RPC_PROTOCOL_ERROR;
1012 switch (ack->result) {
1013 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
1015 * We have not asked for this...
1017 return NT_STATUS_RPC_PROTOCOL_ERROR;
1018 default:
1019 break;
1022 switch (ack->reason.value) {
1023 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1024 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1025 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1026 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1027 default:
1028 break;
1030 return NT_STATUS_UNSUCCESSFUL;
1034 remove requests from the pending or queued queues
1036 static int dcerpc_req_dequeue(struct rpc_request *req)
1038 switch (req->state) {
1039 case RPC_REQUEST_QUEUED:
1040 DLIST_REMOVE(req->p->conn->request_queue, req);
1041 break;
1042 case RPC_REQUEST_PENDING:
1043 DLIST_REMOVE(req->p->conn->pending, req);
1044 break;
1045 case RPC_REQUEST_DONE:
1046 break;
1048 return 0;
1053 mark the dcerpc connection dead. All outstanding requests get an error
1055 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1057 if (conn->dead) return;
1059 conn->dead = true;
1061 TALLOC_FREE(conn->io_trigger);
1062 conn->io_trigger_pending = false;
1064 dcerpc_shutdown_pipe(conn, status);
1066 /* all pending requests get the error */
1067 while (conn->pending) {
1068 struct rpc_request *req = conn->pending;
1069 dcerpc_req_dequeue(req);
1070 req->state = RPC_REQUEST_DONE;
1071 req->status = status;
1072 if (req->async.callback) {
1073 req->async.callback(req);
1077 /* all requests, which are not shipped */
1078 while (conn->request_queue) {
1079 struct rpc_request *req = conn->request_queue;
1080 dcerpc_req_dequeue(req);
1081 req->state = RPC_REQUEST_DONE;
1082 req->status = status;
1083 if (req->async.callback) {
1084 req->async.callback(req);
1088 talloc_set_destructor(conn, NULL);
1089 if (conn->free_skipped) {
1090 talloc_free(conn);
1095 forward declarations of the recv_data handlers for the types of
1096 packets we need to handle
1098 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1099 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1102 receive a dcerpc reply from the transport. Here we work out what
1103 type of reply it is (normal request, bind or alter context) and
1104 dispatch to the appropriate handler
1106 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1108 struct ncacn_packet pkt;
1110 if (conn->dead) {
1111 return;
1114 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1115 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1118 /* the transport may be telling us of a severe error, such as
1119 a dropped socket */
1120 if (!NT_STATUS_IS_OK(status)) {
1121 data_blob_free(blob);
1122 dcerpc_connection_dead(conn, status);
1123 return;
1126 /* parse the basic packet to work out what type of response this is */
1127 status = ncacn_pull(conn, blob, blob->data, &pkt);
1128 if (!NT_STATUS_IS_OK(status)) {
1129 data_blob_free(blob);
1130 dcerpc_connection_dead(conn, status);
1131 return;
1134 dcerpc_request_recv_data(conn, blob, &pkt);
1138 handle timeouts of individual dcerpc requests
1140 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1141 struct timeval t, void *private_data)
1143 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1145 if (req->ignore_timeout) {
1146 dcerpc_req_dequeue(req);
1147 req->state = RPC_REQUEST_DONE;
1148 req->status = NT_STATUS_IO_TIMEOUT;
1149 if (req->async.callback) {
1150 req->async.callback(req);
1152 return;
1155 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1158 struct dcerpc_bind_state {
1159 struct tevent_context *ev;
1160 struct dcerpc_pipe *p;
1163 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1164 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1165 DATA_BLOB *raw_packet,
1166 struct ncacn_packet *pkt);
1168 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1169 struct tevent_context *ev,
1170 struct dcerpc_pipe *p,
1171 const struct ndr_syntax_id *syntax,
1172 const struct ndr_syntax_id *transfer_syntax)
1174 struct tevent_req *req;
1175 struct dcerpc_bind_state *state;
1176 struct ncacn_packet pkt;
1177 DATA_BLOB blob;
1178 NTSTATUS status;
1179 struct rpc_request *subreq;
1180 uint32_t flags;
1182 req = tevent_req_create(mem_ctx, &state,
1183 struct dcerpc_bind_state);
1184 if (req == NULL) {
1185 return NULL;
1188 state->ev = ev;
1189 state->p = p;
1191 p->syntax = *syntax;
1192 p->transfer_syntax = *transfer_syntax;
1194 flags = dcerpc_binding_get_flags(p->binding);
1196 init_ncacn_hdr(p->conn, &pkt);
1198 pkt.ptype = DCERPC_PKT_BIND;
1199 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1200 pkt.call_id = p->conn->call_id;
1201 pkt.auth_length = 0;
1203 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1204 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1207 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1208 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1211 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1212 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1213 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1214 pkt.u.bind.num_contexts = 1;
1215 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1216 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1217 return tevent_req_post(req, ev);
1219 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1220 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1221 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1222 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1223 pkt.u.bind.auth_info = data_blob(NULL, 0);
1225 /* construct the NDR form of the packet */
1226 status = ncacn_push_auth(&blob, state, &pkt,
1227 p->conn->security_state.auth_info);
1228 if (tevent_req_nterror(req, status)) {
1229 return tevent_req_post(req, ev);
1233 * we allocate a dcerpc_request so we can be in the same
1234 * request queue as normal requests
1236 subreq = talloc_zero(state, struct rpc_request);
1237 if (tevent_req_nomem(subreq, req)) {
1238 return tevent_req_post(req, ev);
1241 subreq->state = RPC_REQUEST_PENDING;
1242 subreq->call_id = pkt.call_id;
1243 subreq->async.private_data = req;
1244 subreq->async.callback = dcerpc_bind_fail_handler;
1245 subreq->p = p;
1246 subreq->recv_handler = dcerpc_bind_recv_handler;
1247 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1248 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1250 status = dcerpc_send_request(p->conn, &blob, true);
1251 if (tevent_req_nterror(req, status)) {
1252 return tevent_req_post(req, ev);
1255 tevent_add_timer(ev, subreq,
1256 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1257 dcerpc_timeout_handler, subreq);
1259 return req;
1262 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1264 struct tevent_req *req =
1265 talloc_get_type_abort(subreq->async.private_data,
1266 struct tevent_req);
1267 struct dcerpc_bind_state *state =
1268 tevent_req_data(req,
1269 struct dcerpc_bind_state);
1270 NTSTATUS status = subreq->status;
1272 TALLOC_FREE(subreq);
1275 * We trigger the callback in the next event run
1276 * because the code in this file might trigger
1277 * multiple request callbacks from within a single
1278 * while loop.
1280 * In order to avoid segfaults from within
1281 * dcerpc_connection_dead() we call
1282 * tevent_req_defer_callback().
1284 tevent_req_defer_callback(req, state->ev);
1286 tevent_req_nterror(req, status);
1289 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1290 DATA_BLOB *raw_packet,
1291 struct ncacn_packet *pkt)
1293 struct tevent_req *req =
1294 talloc_get_type_abort(subreq->async.private_data,
1295 struct tevent_req);
1296 struct dcerpc_bind_state *state =
1297 tevent_req_data(req,
1298 struct dcerpc_bind_state);
1299 struct dcecli_connection *conn = state->p->conn;
1300 struct dcerpc_binding *b = NULL;
1301 NTSTATUS status;
1302 uint32_t flags;
1305 * Note that pkt is allocated under raw_packet->data,
1306 * while raw_packet->data is a child of subreq.
1308 talloc_steal(state, raw_packet->data);
1309 TALLOC_FREE(subreq);
1312 * We trigger the callback in the next event run
1313 * because the code in this file might trigger
1314 * multiple request callbacks from within a single
1315 * while loop.
1317 * In order to avoid segfaults from within
1318 * dcerpc_connection_dead() we call
1319 * tevent_req_defer_callback().
1321 tevent_req_defer_callback(req, state->ev);
1323 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1324 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1326 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1327 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1329 tevent_req_nterror(req, status);
1330 return;
1333 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1334 (pkt->u.bind_ack.num_results == 0) ||
1335 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1336 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1337 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1338 return;
1342 * DCE-RPC 1.1 (c706) specifies
1343 * CONST_MUST_RCV_FRAG_SIZE as 1432
1345 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1346 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1347 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1348 return;
1350 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1351 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1352 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1353 return;
1355 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1356 pkt->u.bind_ack.max_xmit_frag);
1357 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1358 pkt->u.bind_ack.max_recv_frag);
1360 flags = dcerpc_binding_get_flags(state->p->binding);
1362 if ((flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1363 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1364 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1367 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1368 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1369 conn->flags |= DCERPC_HEADER_SIGNING;
1372 /* the bind_ack might contain a reply set of credentials */
1373 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1374 uint32_t auth_length;
1376 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1377 conn->security_state.auth_info, &auth_length, true);
1378 if (tevent_req_nterror(req, status)) {
1379 return;
1384 * We're the owner of the binding, so we're allowed to modify it.
1386 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1387 status = dcerpc_binding_set_assoc_group_id(b,
1388 pkt->u.bind_ack.assoc_group_id);
1389 if (tevent_req_nterror(req, status)) {
1390 return;
1393 tevent_req_done(req);
1396 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1398 return tevent_req_simple_recv_ntstatus(req);
1402 perform a continued bind (and auth3)
1404 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1405 TALLOC_CTX *mem_ctx)
1407 struct ncacn_packet pkt;
1408 NTSTATUS status;
1409 DATA_BLOB blob;
1410 uint32_t flags;
1412 flags = dcerpc_binding_get_flags(p->binding);
1414 init_ncacn_hdr(p->conn, &pkt);
1416 pkt.ptype = DCERPC_PKT_AUTH3;
1417 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1418 pkt.call_id = next_call_id(p->conn);
1419 pkt.auth_length = 0;
1420 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1422 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1423 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1426 /* construct the NDR form of the packet */
1427 status = ncacn_push_auth(&blob, mem_ctx,
1428 &pkt,
1429 p->conn->security_state.auth_info);
1430 if (!NT_STATUS_IS_OK(status)) {
1431 return status;
1434 /* send it on its way */
1435 status = dcerpc_send_request(p->conn, &blob, false);
1436 if (!NT_STATUS_IS_OK(status)) {
1437 return status;
1440 return NT_STATUS_OK;
1445 process a fragment received from the transport layer during a
1446 request
1448 This function frees the data
1450 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1451 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1453 struct rpc_request *req;
1454 unsigned int length;
1455 NTSTATUS status = NT_STATUS_OK;
1458 if this is an authenticated connection then parse and check
1459 the auth info. We have to do this before finding the
1460 matching packet, as the request structure might have been
1461 removed due to a timeout, but if it has been we still need
1462 to run the auth routines so that we don't get the sign/seal
1463 info out of step with the server
1465 if (c->security_state.auth_info && c->security_state.generic_state &&
1466 pkt->ptype == DCERPC_PKT_RESPONSE) {
1467 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1470 /* find the matching request */
1471 for (req=c->pending;req;req=req->next) {
1472 if (pkt->call_id == req->call_id) break;
1475 #if 0
1476 /* useful for testing certain vendors RPC servers */
1477 if (req == NULL && c->pending && pkt->call_id == 0) {
1478 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1479 req = c->pending;
1481 #endif
1483 if (req == NULL) {
1484 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1485 data_blob_free(raw_packet);
1486 return;
1489 talloc_steal(req, raw_packet->data);
1491 if (req->recv_handler != NULL) {
1492 dcerpc_req_dequeue(req);
1493 req->state = RPC_REQUEST_DONE;
1496 * We have to look at shipping further requests before calling
1497 * the async function, that one might close the pipe
1499 dcerpc_schedule_io_trigger(c);
1501 req->recv_handler(req, raw_packet, pkt);
1502 return;
1505 if (pkt->ptype == DCERPC_PKT_FAULT) {
1506 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1507 req->fault_code = pkt->u.fault.status;
1508 req->status = NT_STATUS_NET_WRITE_FAULT;
1509 goto req_done;
1512 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1513 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1514 (int)pkt->ptype));
1515 req->fault_code = DCERPC_FAULT_OTHER;
1516 req->status = NT_STATUS_NET_WRITE_FAULT;
1517 goto req_done;
1520 /* now check the status from the auth routines, and if it failed then fail
1521 this request accordingly */
1522 if (!NT_STATUS_IS_OK(status)) {
1523 req->status = status;
1524 goto req_done;
1527 length = pkt->u.response.stub_and_verifier.length;
1529 if (length > 0) {
1530 req->payload.data = talloc_realloc(req,
1531 req->payload.data,
1532 uint8_t,
1533 req->payload.length + length);
1534 if (!req->payload.data) {
1535 req->status = NT_STATUS_NO_MEMORY;
1536 goto req_done;
1538 memcpy(req->payload.data+req->payload.length,
1539 pkt->u.response.stub_and_verifier.data, length);
1540 req->payload.length += length;
1543 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1544 data_blob_free(raw_packet);
1545 dcerpc_send_read(c);
1546 return;
1549 if (req->verify_bitmask1) {
1550 req->p->conn->security_state.verified_bitmask1 = true;
1552 if (req->verify_pcontext) {
1553 req->p->verified_pcontext = true;
1556 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1557 req->flags |= DCERPC_PULL_BIGENDIAN;
1558 } else {
1559 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1562 req_done:
1563 data_blob_free(raw_packet);
1565 /* we've got the full payload */
1566 dcerpc_req_dequeue(req);
1567 req->state = RPC_REQUEST_DONE;
1570 * We have to look at shipping further requests before calling
1571 * the async function, that one might close the pipe
1573 dcerpc_schedule_io_trigger(c);
1575 if (req->async.callback) {
1576 req->async.callback(req);
1580 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req);
1583 perform the send side of a async dcerpc request
1585 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1586 struct dcerpc_pipe *p,
1587 const struct GUID *object,
1588 uint16_t opnum,
1589 DATA_BLOB *stub_data)
1591 struct rpc_request *req;
1592 NTSTATUS status;
1594 req = talloc_zero(mem_ctx, struct rpc_request);
1595 if (req == NULL) {
1596 return NULL;
1599 req->p = p;
1600 req->call_id = next_call_id(p->conn);
1601 req->state = RPC_REQUEST_QUEUED;
1603 if (object != NULL) {
1604 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1605 if (req->object == NULL) {
1606 talloc_free(req);
1607 return NULL;
1611 req->opnum = opnum;
1612 req->request_data.length = stub_data->length;
1613 req->request_data.data = stub_data->data;
1615 status = dcerpc_request_prepare_vt(req);
1616 if (!NT_STATUS_IS_OK(status)) {
1617 talloc_free(req);
1618 return NULL;
1621 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1622 talloc_set_destructor(req, dcerpc_req_dequeue);
1624 dcerpc_schedule_io_trigger(p->conn);
1626 if (p->request_timeout) {
1627 tevent_add_timer(p->conn->event_ctx, req,
1628 timeval_current_ofs(p->request_timeout, 0),
1629 dcerpc_timeout_handler, req);
1632 return req;
1635 static NTSTATUS dcerpc_request_prepare_vt(struct rpc_request *req)
1637 struct dcecli_security *sec = &req->p->conn->security_state;
1638 struct dcerpc_sec_verification_trailer *t;
1639 struct dcerpc_sec_vt *c = NULL;
1640 struct ndr_push *ndr = NULL;
1641 enum ndr_err_code ndr_err;
1643 if (sec->auth_info == NULL) {
1644 return NT_STATUS_OK;
1647 if (sec->auth_info->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
1648 return NT_STATUS_OK;
1651 t = talloc_zero(req, struct dcerpc_sec_verification_trailer);
1652 if (t == NULL) {
1653 return NT_STATUS_NO_MEMORY;
1656 if (!sec->verified_bitmask1) {
1657 t->commands = talloc_realloc(t, t->commands,
1658 struct dcerpc_sec_vt,
1659 t->count.count + 1);
1660 if (t->commands == NULL) {
1661 return NT_STATUS_NO_MEMORY;
1663 c = &t->commands[t->count.count++];
1664 ZERO_STRUCTP(c);
1666 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1667 if (req->p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1668 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1670 req->verify_bitmask1 = true;
1673 if (!req->p->verified_pcontext) {
1674 t->commands = talloc_realloc(t, t->commands,
1675 struct dcerpc_sec_vt,
1676 t->count.count + 1);
1677 if (t->commands == NULL) {
1678 return NT_STATUS_NO_MEMORY;
1680 c = &t->commands[t->count.count++];
1681 ZERO_STRUCTP(c);
1683 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1684 c->u.pcontext.abstract_syntax = req->p->syntax;
1685 c->u.pcontext.transfer_syntax = req->p->transfer_syntax;
1687 req->verify_pcontext = true;
1690 if (!(req->p->conn->flags & DCERPC_HEADER_SIGNING)) {
1691 t->commands = talloc_realloc(t, t->commands,
1692 struct dcerpc_sec_vt,
1693 t->count.count + 1);
1694 if (t->commands == NULL) {
1695 return NT_STATUS_NO_MEMORY;
1697 c = &t->commands[t->count.count++];
1698 ZERO_STRUCTP(c);
1700 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1701 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1702 if (req->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1703 c->u.header2.drep[0] = 0;
1704 } else {
1705 c->u.header2.drep[0] = DCERPC_DREP_LE;
1707 c->u.header2.drep[1] = 0;
1708 c->u.header2.drep[2] = 0;
1709 c->u.header2.drep[3] = 0;
1710 c->u.header2.call_id = req->call_id;
1711 c->u.header2.context_id = req->p->context_id;
1712 c->u.header2.opnum = req->opnum;
1715 if (t->count.count == 0) {
1716 TALLOC_FREE(t);
1717 return NT_STATUS_OK;
1720 c = &t->commands[t->count.count - 1];
1721 c->command |= DCERPC_SEC_VT_COMMAND_END;
1723 if (DEBUGLEVEL >= 10) {
1724 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1727 ndr = ndr_push_init_ctx(req);
1728 if (ndr == NULL) {
1729 return NT_STATUS_NO_MEMORY;
1733 * for now we just copy and append
1736 ndr_err = ndr_push_bytes(ndr, req->request_data.data,
1737 req->request_data.length);
1738 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1739 return ndr_map_error2ntstatus(ndr_err);
1742 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1743 NDR_SCALARS | NDR_BUFFERS,
1745 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1746 return ndr_map_error2ntstatus(ndr_err);
1748 req->request_data = ndr_push_blob(ndr);
1750 return NT_STATUS_OK;
1754 Send a request using the transport
1757 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1759 struct rpc_request *req;
1760 struct dcerpc_pipe *p;
1761 DATA_BLOB *stub_data;
1762 struct ncacn_packet pkt;
1763 DATA_BLOB blob;
1764 uint32_t remaining, chunk_size;
1765 bool first_packet = true;
1766 size_t sig_size = 0;
1767 bool need_async = false;
1768 bool can_async = true;
1770 req = c->request_queue;
1771 if (req == NULL) {
1772 return;
1775 p = req->p;
1776 stub_data = &req->request_data;
1778 if (c->pending) {
1779 need_async = true;
1782 if (c->security_state.auth_info &&
1783 c->security_state.generic_state)
1785 struct gensec_security *gensec = c->security_state.generic_state;
1787 switch (c->security_state.auth_info->auth_level) {
1788 case DCERPC_AUTH_LEVEL_PRIVACY:
1789 case DCERPC_AUTH_LEVEL_INTEGRITY:
1790 can_async = gensec_have_feature(gensec,
1791 GENSEC_FEATURE_ASYNC_REPLIES);
1792 break;
1793 case DCERPC_AUTH_LEVEL_CONNECT:
1794 case DCERPC_AUTH_LEVEL_NONE:
1795 can_async = true;
1796 break;
1797 default:
1798 can_async = false;
1799 break;
1803 if (need_async && !can_async) {
1804 req->wait_for_sync = true;
1805 return;
1808 DLIST_REMOVE(c->request_queue, req);
1809 DLIST_ADD(c->pending, req);
1810 req->state = RPC_REQUEST_PENDING;
1812 init_ncacn_hdr(p->conn, &pkt);
1814 remaining = stub_data->length;
1816 /* we can write a full max_recv_frag size, minus the dcerpc
1817 request header size */
1818 chunk_size = p->conn->srv_max_recv_frag;
1819 chunk_size -= DCERPC_REQUEST_LENGTH;
1820 if (c->security_state.auth_info &&
1821 c->security_state.generic_state) {
1822 size_t max_payload = chunk_size;
1824 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1825 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1827 sig_size = gensec_sig_size(c->security_state.generic_state,
1828 max_payload);
1829 if (sig_size) {
1830 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1831 chunk_size -= sig_size;
1834 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1836 pkt.ptype = DCERPC_PKT_REQUEST;
1837 pkt.call_id = req->call_id;
1838 pkt.auth_length = 0;
1839 pkt.pfc_flags = 0;
1840 pkt.u.request.context_id = p->context_id;
1841 pkt.u.request.opnum = req->opnum;
1843 if (req->object) {
1844 pkt.u.request.object.object = *req->object;
1845 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1846 chunk_size -= ndr_size_GUID(req->object,0);
1849 /* we send a series of pdus without waiting for a reply */
1850 while (remaining > 0 || first_packet) {
1851 uint32_t chunk = MIN(chunk_size, remaining);
1852 bool last_frag = false;
1853 bool do_trans = false;
1855 first_packet = false;
1856 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1858 if (remaining == stub_data->length) {
1859 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1861 if (chunk == remaining) {
1862 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1863 last_frag = true;
1866 pkt.u.request.alloc_hint = remaining;
1867 pkt.u.request.stub_and_verifier.data = stub_data->data +
1868 (stub_data->length - remaining);
1869 pkt.u.request.stub_and_verifier.length = chunk;
1871 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
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 && !need_async) {
1879 do_trans = true;
1882 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1883 if (!NT_STATUS_IS_OK(req->status)) {
1884 req->state = RPC_REQUEST_DONE;
1885 DLIST_REMOVE(p->conn->pending, req);
1886 return;
1889 if (last_frag && !do_trans) {
1890 req->status = dcerpc_send_read(p->conn);
1891 if (!NT_STATUS_IS_OK(req->status)) {
1892 req->state = RPC_REQUEST_DONE;
1893 DLIST_REMOVE(p->conn->pending, req);
1894 return;
1898 remaining -= chunk;
1902 static void dcerpc_io_trigger(struct tevent_context *ctx,
1903 struct tevent_immediate *im,
1904 void *private_data)
1906 struct dcecli_connection *c =
1907 talloc_get_type_abort(private_data,
1908 struct dcecli_connection);
1910 c->io_trigger_pending = false;
1912 dcerpc_schedule_io_trigger(c);
1914 dcerpc_ship_next_request(c);
1917 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1919 if (c->dead) {
1920 return;
1923 if (c->request_queue == NULL) {
1924 return;
1927 if (c->request_queue->wait_for_sync && c->pending) {
1928 return;
1931 if (c->io_trigger_pending) {
1932 return;
1935 c->io_trigger_pending = true;
1937 tevent_schedule_immediate(c->io_trigger,
1938 c->event_ctx,
1939 dcerpc_io_trigger,
1944 perform the receive side of a async dcerpc request
1946 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1947 TALLOC_CTX *mem_ctx,
1948 DATA_BLOB *stub_data)
1950 NTSTATUS status;
1952 while (req->state != RPC_REQUEST_DONE) {
1953 struct tevent_context *ctx = req->p->conn->event_ctx;
1954 if (tevent_loop_once(ctx) != 0) {
1955 return NT_STATUS_CONNECTION_DISCONNECTED;
1958 *stub_data = req->payload;
1959 status = req->status;
1960 if (stub_data->data) {
1961 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1963 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1964 req->p->last_fault_code = req->fault_code;
1966 talloc_unlink(talloc_parent(req), req);
1967 return status;
1971 this is a paranoid NDR validator. For every packet we push onto the wire
1972 we pull it back again, then push it again. Then we compare the raw NDR data
1973 for that to the NDR we initially generated. If they don't match then we know
1974 we must have a bug in either the pull or push side of our code
1976 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1977 TALLOC_CTX *mem_ctx,
1978 DATA_BLOB blob,
1979 size_t struct_size,
1980 ndr_push_flags_fn_t ndr_push,
1981 ndr_pull_flags_fn_t ndr_pull)
1983 void *st;
1984 struct ndr_pull *pull;
1985 struct ndr_push *push;
1986 DATA_BLOB blob2;
1987 enum ndr_err_code ndr_err;
1989 st = talloc_size(mem_ctx, struct_size);
1990 if (!st) {
1991 return NT_STATUS_NO_MEMORY;
1994 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1995 if (!pull) {
1996 return NT_STATUS_NO_MEMORY;
1998 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2000 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2001 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
2004 if (c->flags & DCERPC_NDR64) {
2005 pull->flags |= LIBNDR_FLAG_NDR64;
2008 ndr_err = ndr_pull(pull, NDR_IN, st);
2009 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2010 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2011 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2012 "failed input validation pull - %s",
2013 nt_errstr(status));
2014 return ndr_map_error2ntstatus(ndr_err);
2017 push = ndr_push_init_ctx(mem_ctx);
2018 if (!push) {
2019 return NT_STATUS_NO_MEMORY;
2022 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
2023 push->flags |= LIBNDR_FLAG_BIGENDIAN;
2026 if (c->flags & DCERPC_NDR64) {
2027 push->flags |= LIBNDR_FLAG_NDR64;
2030 ndr_err = ndr_push(push, 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 push - %s",
2035 nt_errstr(status));
2036 return ndr_map_error2ntstatus(ndr_err);
2039 blob2 = ndr_push_blob(push);
2041 if (data_blob_cmp(&blob, &blob2) != 0) {
2042 DEBUG(3,("original:\n"));
2043 dump_data(3, blob.data, blob.length);
2044 DEBUG(3,("secondary:\n"));
2045 dump_data(3, blob2.data, blob2.length);
2046 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2047 "failed input validation blobs doesn't match");
2048 return ndr_map_error2ntstatus(ndr_err);
2051 return NT_STATUS_OK;
2055 this is a paranoid NDR input validator. For every packet we pull
2056 from the wire we push it back again then pull and push it
2057 again. Then we compare the raw NDR data for that to the NDR we
2058 initially generated. If they don't match then we know we must have a
2059 bug in either the pull or push side of our code
2061 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
2062 struct ndr_pull *pull_in,
2063 void *struct_ptr,
2064 size_t struct_size,
2065 ndr_push_flags_fn_t ndr_push,
2066 ndr_pull_flags_fn_t ndr_pull,
2067 ndr_print_function_t ndr_print)
2069 void *st;
2070 struct ndr_pull *pull;
2071 struct ndr_push *push;
2072 DATA_BLOB blob, blob2;
2073 TALLOC_CTX *mem_ctx = pull_in;
2074 char *s1, *s2;
2075 enum ndr_err_code ndr_err;
2077 st = talloc_size(mem_ctx, struct_size);
2078 if (!st) {
2079 return NT_STATUS_NO_MEMORY;
2081 memcpy(st, struct_ptr, struct_size);
2083 push = ndr_push_init_ctx(mem_ctx);
2084 if (!push) {
2085 return NT_STATUS_NO_MEMORY;
2088 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
2089 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2090 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2091 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2092 "failed output validation push - %s",
2093 nt_errstr(status));
2094 return ndr_map_error2ntstatus(ndr_err);
2097 blob = ndr_push_blob(push);
2099 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
2100 if (!pull) {
2101 return NT_STATUS_NO_MEMORY;
2104 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
2105 ndr_err = ndr_pull(pull, NDR_OUT, st);
2106 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2107 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2108 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
2109 "failed output validation pull - %s",
2110 nt_errstr(status));
2111 return ndr_map_error2ntstatus(ndr_err);
2114 push = ndr_push_init_ctx(mem_ctx);
2115 if (!push) {
2116 return NT_STATUS_NO_MEMORY;
2119 ndr_err = ndr_push(push, NDR_OUT, st);
2120 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2121 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2122 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2123 "failed output validation push2 - %s",
2124 nt_errstr(status));
2125 return ndr_map_error2ntstatus(ndr_err);
2128 blob2 = ndr_push_blob(push);
2130 if (data_blob_cmp(&blob, &blob2) != 0) {
2131 DEBUG(3,("original:\n"));
2132 dump_data(3, blob.data, blob.length);
2133 DEBUG(3,("secondary:\n"));
2134 dump_data(3, blob2.data, blob2.length);
2135 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2136 "failed output validation blobs doesn't match");
2137 return ndr_map_error2ntstatus(ndr_err);
2140 /* this checks the printed forms of the two structures, which effectively
2141 tests all of the value() attributes */
2142 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2143 NDR_OUT, struct_ptr);
2144 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2145 NDR_OUT, st);
2146 if (strcmp(s1, s2) != 0) {
2147 #if 1
2148 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2149 #else
2150 /* this is sometimes useful */
2151 printf("VALIDATE ERROR\n");
2152 file_save("wire.dat", s1, strlen(s1));
2153 file_save("gen.dat", s2, strlen(s2));
2154 system("diff -u wire.dat gen.dat");
2155 #endif
2156 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2157 "failed output validation strings doesn't match");
2158 return ndr_map_error2ntstatus(ndr_err);
2161 return NT_STATUS_OK;
2165 a useful function for retrieving the server name we connected to
2167 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2169 return p->conn ? p->conn->server_name : NULL;
2174 get the dcerpc auth_level for a open connection
2176 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2178 uint8_t auth_level;
2180 if (c->flags & DCERPC_SEAL) {
2181 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2182 } else if (c->flags & DCERPC_SIGN) {
2183 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2184 } else if (c->flags & DCERPC_CONNECT) {
2185 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2186 } else {
2187 auth_level = DCERPC_AUTH_LEVEL_NONE;
2189 return auth_level;
2192 struct dcerpc_alter_context_state {
2193 struct tevent_context *ev;
2194 struct dcerpc_pipe *p;
2197 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2198 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2199 DATA_BLOB *raw_packet,
2200 struct ncacn_packet *pkt);
2202 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2203 struct tevent_context *ev,
2204 struct dcerpc_pipe *p,
2205 const struct ndr_syntax_id *syntax,
2206 const struct ndr_syntax_id *transfer_syntax)
2208 struct tevent_req *req;
2209 struct dcerpc_alter_context_state *state;
2210 struct ncacn_packet pkt;
2211 DATA_BLOB blob;
2212 NTSTATUS status;
2213 struct rpc_request *subreq;
2214 uint32_t flags;
2216 req = tevent_req_create(mem_ctx, &state,
2217 struct dcerpc_alter_context_state);
2218 if (req == NULL) {
2219 return NULL;
2222 state->ev = ev;
2223 state->p = p;
2225 p->syntax = *syntax;
2226 p->transfer_syntax = *transfer_syntax;
2228 flags = dcerpc_binding_get_flags(p->binding);
2230 init_ncacn_hdr(p->conn, &pkt);
2232 pkt.ptype = DCERPC_PKT_ALTER;
2233 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2234 pkt.call_id = p->conn->call_id;
2235 pkt.auth_length = 0;
2237 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2238 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2241 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2242 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2243 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2244 pkt.u.alter.num_contexts = 1;
2245 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2246 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2247 return tevent_req_post(req, ev);
2249 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2250 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2251 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2252 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2253 pkt.u.alter.auth_info = data_blob(NULL, 0);
2255 /* construct the NDR form of the packet */
2256 status = ncacn_push_auth(&blob, state, &pkt,
2257 p->conn->security_state.auth_info);
2258 if (tevent_req_nterror(req, status)) {
2259 return tevent_req_post(req, ev);
2263 * we allocate a dcerpc_request so we can be in the same
2264 * request queue as normal requests
2266 subreq = talloc_zero(state, struct rpc_request);
2267 if (tevent_req_nomem(subreq, req)) {
2268 return tevent_req_post(req, ev);
2271 subreq->state = RPC_REQUEST_PENDING;
2272 subreq->call_id = pkt.call_id;
2273 subreq->async.private_data = req;
2274 subreq->async.callback = dcerpc_alter_context_fail_handler;
2275 subreq->p = p;
2276 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2277 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2278 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2280 status = dcerpc_send_request(p->conn, &blob, true);
2281 if (tevent_req_nterror(req, status)) {
2282 return tevent_req_post(req, ev);
2285 tevent_add_timer(ev, subreq,
2286 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2287 dcerpc_timeout_handler, subreq);
2289 return req;
2292 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2294 struct tevent_req *req =
2295 talloc_get_type_abort(subreq->async.private_data,
2296 struct tevent_req);
2297 struct dcerpc_alter_context_state *state =
2298 tevent_req_data(req,
2299 struct dcerpc_alter_context_state);
2300 NTSTATUS status = subreq->status;
2302 TALLOC_FREE(subreq);
2305 * We trigger the callback in the next event run
2306 * because the code in this file might trigger
2307 * multiple request callbacks from within a single
2308 * while loop.
2310 * In order to avoid segfaults from within
2311 * dcerpc_connection_dead() we call
2312 * tevent_req_defer_callback().
2314 tevent_req_defer_callback(req, state->ev);
2316 tevent_req_nterror(req, status);
2319 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2320 DATA_BLOB *raw_packet,
2321 struct ncacn_packet *pkt)
2323 struct tevent_req *req =
2324 talloc_get_type_abort(subreq->async.private_data,
2325 struct tevent_req);
2326 struct dcerpc_alter_context_state *state =
2327 tevent_req_data(req,
2328 struct dcerpc_alter_context_state);
2329 struct dcecli_connection *conn = state->p->conn;
2330 NTSTATUS status;
2333 * Note that pkt is allocated under raw_packet->data,
2334 * while raw_packet->data is a child of subreq.
2336 talloc_steal(state, raw_packet->data);
2337 TALLOC_FREE(subreq);
2340 * We trigger the callback in the next event run
2341 * because the code in this file might trigger
2342 * multiple request callbacks from within a single
2343 * while loop.
2345 * In order to avoid segfaults from within
2346 * dcerpc_connection_dead() we call
2347 * tevent_req_defer_callback().
2349 tevent_req_defer_callback(req, state->ev);
2351 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2352 pkt->u.alter_resp.num_results == 1 &&
2353 pkt->u.alter_resp.ctx_list[0].result != 0) {
2354 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2355 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2356 pkt->u.alter_resp.ctx_list[0].reason.value,
2357 nt_errstr(status)));
2358 tevent_req_nterror(req, status);
2359 return;
2362 if (pkt->ptype == DCERPC_PKT_FAULT) {
2363 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2364 dcerpc_errstr(state, pkt->u.fault.status)));
2365 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2366 state->p->last_fault_code = pkt->u.fault.status;
2367 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2368 } else if (pkt->u.fault.status == DCERPC_FAULT_SEC_PKG_ERROR) {
2369 state->p->last_fault_code = pkt->u.fault.status;
2370 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2371 } else {
2372 state->p->last_fault_code = pkt->u.fault.status;
2373 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2374 tevent_req_nterror(req, status);
2376 return;
2379 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2380 pkt->u.alter_resp.num_results == 0 ||
2381 pkt->u.alter_resp.ctx_list[0].result != 0) {
2382 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2383 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2384 return;
2387 /* the alter_resp might contain a reply set of credentials */
2388 if (conn->security_state.auth_info &&
2389 pkt->u.alter_resp.auth_info.length) {
2390 uint32_t auth_length;
2392 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2393 conn->security_state.auth_info, &auth_length, true);
2394 if (tevent_req_nterror(req, status)) {
2395 return;
2399 tevent_req_done(req);
2402 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2404 return tevent_req_simple_recv_ntstatus(req);
2408 send a dcerpc alter_context request
2410 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2411 TALLOC_CTX *mem_ctx,
2412 const struct ndr_syntax_id *syntax,
2413 const struct ndr_syntax_id *transfer_syntax)
2415 struct tevent_req *subreq;
2416 struct tevent_context *ev = p->conn->event_ctx;
2417 bool ok;
2419 /* TODO: create a new event context here */
2421 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2422 p, syntax, transfer_syntax);
2423 if (subreq == NULL) {
2424 return NT_STATUS_NO_MEMORY;
2427 ok = tevent_req_poll(subreq, ev);
2428 if (!ok) {
2429 NTSTATUS status;
2430 status = map_nt_error_from_unix_common(errno);
2431 return status;
2434 return dcerpc_alter_context_recv(subreq);
2437 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2439 if (c->transport.stream == NULL) {
2440 return;
2443 tevent_queue_stop(c->transport.write_queue);
2444 TALLOC_FREE(c->transport.read_subreq);
2445 TALLOC_FREE(c->transport.stream);
2447 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2448 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2451 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2452 status = NT_STATUS_END_OF_FILE;
2455 dcerpc_recv_data(c, NULL, status);
2460 shutdown SMB pipe connection
2462 struct dcerpc_shutdown_pipe_state {
2463 struct dcecli_connection *c;
2464 NTSTATUS status;
2467 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2469 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2471 struct dcerpc_shutdown_pipe_state *state;
2472 struct tevent_req *subreq;
2474 if (c->transport.stream == NULL) {
2475 return NT_STATUS_OK;
2478 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2479 if (state == NULL) {
2480 return NT_STATUS_NO_MEMORY;
2482 state->c = c;
2483 state->status = status;
2485 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2486 if (subreq == NULL) {
2487 return NT_STATUS_NO_MEMORY;
2489 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2491 return status;
2494 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2496 struct dcerpc_shutdown_pipe_state *state =
2497 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2498 struct dcecli_connection *c = state->c;
2499 NTSTATUS status = state->status;
2500 int error;
2503 * here we ignore the return values...
2505 tstream_disconnect_recv(subreq, &error);
2506 TALLOC_FREE(subreq);
2508 TALLOC_FREE(state);
2510 dcerpc_transport_dead(c, status);
2515 struct dcerpc_send_read_state {
2516 struct dcecli_connection *p;
2519 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2521 struct dcecli_connection *p = state->p;
2523 p->transport.read_subreq = NULL;
2525 return 0;
2528 static void dcerpc_send_read_done(struct tevent_req *subreq);
2530 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2532 struct dcerpc_send_read_state *state;
2534 if (p->transport.read_subreq != NULL) {
2535 p->transport.pending_reads++;
2536 return NT_STATUS_OK;
2539 state = talloc_zero(p, struct dcerpc_send_read_state);
2540 if (state == NULL) {
2541 return NT_STATUS_NO_MEMORY;
2543 state->p = p;
2545 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2547 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2548 p->event_ctx,
2549 p->transport.stream);
2550 if (p->transport.read_subreq == NULL) {
2551 return NT_STATUS_NO_MEMORY;
2553 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2555 return NT_STATUS_OK;
2558 static void dcerpc_send_read_done(struct tevent_req *subreq)
2560 struct dcerpc_send_read_state *state =
2561 tevent_req_callback_data(subreq,
2562 struct dcerpc_send_read_state);
2563 struct dcecli_connection *p = state->p;
2564 NTSTATUS status;
2565 struct ncacn_packet *pkt;
2566 DATA_BLOB blob;
2568 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2569 &pkt, &blob);
2570 TALLOC_FREE(subreq);
2571 if (!NT_STATUS_IS_OK(status)) {
2572 TALLOC_FREE(state);
2573 dcerpc_transport_dead(p, status);
2574 return;
2578 * here we steal into thet connection context,
2579 * but p->transport.recv_data() will steal or free it again
2581 talloc_steal(p, blob.data);
2582 TALLOC_FREE(state);
2584 if (p->transport.pending_reads > 0) {
2585 p->transport.pending_reads--;
2587 status = dcerpc_send_read(p);
2588 if (!NT_STATUS_IS_OK(status)) {
2589 dcerpc_transport_dead(p, status);
2590 return;
2594 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2597 struct dcerpc_send_request_state {
2598 struct dcecli_connection *p;
2599 DATA_BLOB blob;
2600 struct iovec iov;
2603 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2605 struct dcecli_connection *p = state->p;
2607 p->transport.read_subreq = NULL;
2609 return 0;
2612 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2613 static void dcerpc_send_request_done(struct tevent_req *subreq);
2615 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2616 bool trigger_read)
2618 struct dcerpc_send_request_state *state;
2619 struct tevent_req *subreq;
2620 bool use_trans = trigger_read;
2622 if (p->transport.stream == NULL) {
2623 return NT_STATUS_CONNECTION_DISCONNECTED;
2626 state = talloc_zero(p, struct dcerpc_send_request_state);
2627 if (state == NULL) {
2628 return NT_STATUS_NO_MEMORY;
2630 state->p = p;
2632 state->blob = data_blob_talloc(state, data->data, data->length);
2633 if (state->blob.data == NULL) {
2634 TALLOC_FREE(state);
2635 return NT_STATUS_NO_MEMORY;
2637 state->iov.iov_base = (void *)state->blob.data;
2638 state->iov.iov_len = state->blob.length;
2640 if (p->transport.read_subreq != NULL) {
2641 use_trans = false;
2644 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2645 use_trans = false;
2648 if (use_trans) {
2650 * we need to block reads until our write is
2651 * the next in the write queue.
2653 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2654 p->transport.write_queue);
2655 if (p->transport.read_subreq == NULL) {
2656 TALLOC_FREE(state);
2657 return NT_STATUS_NO_MEMORY;
2659 tevent_req_set_callback(p->transport.read_subreq,
2660 dcerpc_send_request_wait_done,
2661 state);
2663 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2665 trigger_read = false;
2668 subreq = tstream_writev_queue_send(state, p->event_ctx,
2669 p->transport.stream,
2670 p->transport.write_queue,
2671 &state->iov, 1);
2672 if (subreq == NULL) {
2673 TALLOC_FREE(state);
2674 return NT_STATUS_NO_MEMORY;
2676 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2678 if (trigger_read) {
2679 dcerpc_send_read(p);
2682 return NT_STATUS_OK;
2685 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2687 struct dcerpc_send_request_state *state =
2688 tevent_req_callback_data(subreq,
2689 struct dcerpc_send_request_state);
2690 struct dcecli_connection *p = state->p;
2691 NTSTATUS status;
2692 bool ok;
2694 p->transport.read_subreq = NULL;
2695 talloc_set_destructor(state, NULL);
2697 ok = tevent_queue_wait_recv(subreq);
2698 if (!ok) {
2699 TALLOC_FREE(state);
2700 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2701 return;
2704 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2705 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2706 if (!NT_STATUS_IS_OK(status)) {
2707 TALLOC_FREE(state);
2708 dcerpc_transport_dead(p, status);
2709 return;
2713 /* we free subreq after tstream_cli_np_use_trans */
2714 TALLOC_FREE(subreq);
2716 dcerpc_send_read(p);
2719 static void dcerpc_send_request_done(struct tevent_req *subreq)
2721 struct dcerpc_send_request_state *state =
2722 tevent_req_callback_data(subreq,
2723 struct dcerpc_send_request_state);
2724 int ret;
2725 int error;
2727 ret = tstream_writev_queue_recv(subreq, &error);
2728 TALLOC_FREE(subreq);
2729 if (ret == -1) {
2730 struct dcecli_connection *p = state->p;
2731 NTSTATUS status = map_nt_error_from_unix_common(error);
2733 TALLOC_FREE(state);
2734 dcerpc_transport_dead(p, status);
2735 return;
2738 TALLOC_FREE(state);