param: replace P_OCTAL variable setting with s3 version which uses sscanf
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blobbe9a44c1c9e7d2ace15db630dcd1efc1b56e125e
1 /*
2 Unix SMB/CIFS implementation.
3 raw dcerpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "system/filesys.h"
25 #include "../lib/util/dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/rpc/dcerpc.h"
28 #include "librpc/rpc/dcerpc_proto.h"
29 #include "librpc/gen_ndr/ndr_misc.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
33 #include "lib/util/tevent_ntstatus.h"
34 #include "librpc/rpc/rpc_common.h"
35 #include "lib/tsocket/tsocket.h"
36 #include "libcli/smb/tstream_smbXcli_np.h"
39 enum rpc_request_state {
40 RPC_REQUEST_QUEUED,
41 RPC_REQUEST_PENDING,
42 RPC_REQUEST_DONE
46 handle for an async dcerpc request
48 struct rpc_request {
49 struct rpc_request *next, *prev;
50 struct dcerpc_pipe *p;
51 NTSTATUS status;
52 uint32_t call_id;
53 enum rpc_request_state state;
54 DATA_BLOB payload;
55 uint32_t flags;
56 uint32_t fault_code;
58 /* this is used to distinguish bind and alter_context requests
59 from normal requests */
60 void (*recv_handler)(struct rpc_request *conn,
61 DATA_BLOB *blob, struct ncacn_packet *pkt);
63 const struct GUID *object;
64 uint16_t opnum;
65 DATA_BLOB request_data;
66 bool ignore_timeout;
67 bool wait_for_sync;
69 struct {
70 void (*callback)(struct rpc_request *);
71 void *private_data;
72 } async;
75 _PUBLIC_ NTSTATUS dcerpc_init(void)
77 return gensec_init();
80 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
81 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c);
83 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
84 struct dcerpc_pipe *p,
85 const struct GUID *object,
86 uint16_t opnum,
87 DATA_BLOB *stub_data);
88 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
89 TALLOC_CTX *mem_ctx,
90 DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
92 TALLOC_CTX *mem_ctx,
93 DATA_BLOB blob,
94 size_t struct_size,
95 ndr_push_flags_fn_t ndr_push,
96 ndr_pull_flags_fn_t ndr_pull);
97 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
98 struct ndr_pull *pull_in,
99 void *struct_ptr,
100 size_t struct_size,
101 ndr_push_flags_fn_t ndr_push,
102 ndr_pull_flags_fn_t ndr_pull,
103 ndr_print_function_t ndr_print);
104 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *p, NTSTATUS status);
105 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
106 bool trigger_read);
107 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p);
109 /* destroy a dcerpc connection */
110 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
112 if (conn->dead) {
113 conn->free_skipped = true;
114 return -1;
116 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
117 return 0;
121 /* initialise a dcerpc connection.
122 the event context is optional
124 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
125 struct tevent_context *ev)
127 struct dcecli_connection *c;
129 c = talloc_zero(mem_ctx, struct dcecli_connection);
130 if (!c) {
131 return NULL;
134 c->event_ctx = ev;
136 if (c->event_ctx == NULL) {
137 talloc_free(c);
138 return NULL;
141 c->call_id = 1;
142 c->security_state.auth_info = NULL;
143 c->security_state.session_key = dcerpc_generic_session_key;
144 c->security_state.generic_state = NULL;
145 c->flags = 0;
147 * Windows uses 5840 for ncacn_ip_tcp,
148 * so we also use it (for every transport)
149 * by default. But we give the transport
150 * the chance to overwrite it.
152 c->srv_max_xmit_frag = 5840;
153 c->srv_max_recv_frag = 5840;
154 c->pending = NULL;
156 c->io_trigger = tevent_create_immediate(c);
157 if (c->io_trigger == NULL) {
158 talloc_free(c);
159 return NULL;
162 talloc_set_destructor(c, dcerpc_connection_destructor);
164 return c;
167 struct dcerpc_bh_state {
168 struct dcerpc_pipe *p;
171 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
173 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
174 struct dcerpc_bh_state);
176 if (!hs->p) {
177 return false;
180 if (!hs->p->conn) {
181 return false;
184 if (hs->p->conn->dead) {
185 return false;
188 return true;
191 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
192 uint32_t timeout)
194 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
195 struct dcerpc_bh_state);
196 uint32_t old;
198 if (!hs->p) {
199 return DCERPC_REQUEST_TIMEOUT;
202 old = hs->p->request_timeout;
203 hs->p->request_timeout = timeout;
205 return old;
208 static void dcerpc_bh_auth_info(struct dcerpc_binding_handle *h,
209 enum dcerpc_AuthType *auth_type,
210 enum dcerpc_AuthLevel *auth_level)
212 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
213 struct dcerpc_bh_state);
215 if (hs->p == NULL) {
216 return;
219 if (hs->p->conn == NULL) {
220 return;
223 if (hs->p->conn->security_state.auth_info == NULL) {
224 return;
227 *auth_type = hs->p->conn->security_state.auth_info->auth_type;
228 *auth_level = hs->p->conn->security_state.auth_info->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 asprintf(&name, "%s/rpclog/%s-out.%d",
489 hs->p->conn->packet_log_dir,
490 call->name, i);
491 if (name == NULL) {
492 return;
494 if (!file_exist(name)) {
495 if (file_save(name, blob->data, blob->length)) {
496 DEBUG(10,("Logged rpc packet to %s\n", name));
498 free(name);
499 break;
501 free(name);
505 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
506 TALLOC_CTX *mem_ctx,
507 const DATA_BLOB *blob,
508 const struct ndr_interface_call *call)
510 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
511 struct dcerpc_bh_state);
513 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
514 NTSTATUS status;
516 status = dcerpc_ndr_validate_in(hs->p->conn,
517 mem_ctx,
518 *blob,
519 call->struct_size,
520 call->ndr_push,
521 call->ndr_pull);
522 if (!NT_STATUS_IS_OK(status)) {
523 DEBUG(0,("Validation [in] failed for %s - %s\n",
524 call->name, nt_errstr(status)));
525 return status;
529 DEBUG(10,("rpc request data:\n"));
530 dump_data(10, blob->data, blob->length);
532 return NT_STATUS_OK;
535 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
536 struct ndr_pull *pull_in,
537 const void *_struct_ptr,
538 const struct ndr_interface_call *call)
540 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
541 struct dcerpc_bh_state);
542 void *struct_ptr = discard_const(_struct_ptr);
544 DEBUG(10,("rpc reply data:\n"));
545 dump_data(10, pull_in->data, pull_in->data_size);
547 if (pull_in->offset != pull_in->data_size) {
548 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
549 pull_in->data_size - pull_in->offset,
550 pull_in->offset, pull_in->offset,
551 call->name));
552 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
553 but it turns out that early versions of NT
554 (specifically NT3.1) add junk onto the end of rpc
555 packets, so if we want to interoperate at all with
556 those versions then we need to ignore this error */
559 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
560 NTSTATUS status;
562 status = dcerpc_ndr_validate_out(hs->p->conn,
563 pull_in,
564 struct_ptr,
565 call->struct_size,
566 call->ndr_push,
567 call->ndr_pull,
568 call->ndr_print);
569 if (!NT_STATUS_IS_OK(status)) {
570 DEBUG(2,("Validation [out] failed for %s - %s\n",
571 call->name, nt_errstr(status)));
572 return status;
576 return NT_STATUS_OK;
579 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
580 .name = "dcerpc",
581 .is_connected = dcerpc_bh_is_connected,
582 .set_timeout = dcerpc_bh_set_timeout,
583 .auth_info = dcerpc_bh_auth_info,
584 .raw_call_send = dcerpc_bh_raw_call_send,
585 .raw_call_recv = dcerpc_bh_raw_call_recv,
586 .disconnect_send = dcerpc_bh_disconnect_send,
587 .disconnect_recv = dcerpc_bh_disconnect_recv,
589 .push_bigendian = dcerpc_bh_push_bigendian,
590 .ref_alloc = dcerpc_bh_ref_alloc,
591 .use_ndr64 = dcerpc_bh_use_ndr64,
592 .do_ndr_print = dcerpc_bh_do_ndr_print,
593 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
594 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
595 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
596 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
599 /* initialise a dcerpc pipe. */
600 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
602 struct dcerpc_binding_handle *h;
603 struct dcerpc_bh_state *hs;
605 h = dcerpc_binding_handle_create(p,
606 &dcerpc_bh_ops,
607 NULL,
608 NULL, /* TODO */
609 &hs,
610 struct dcerpc_bh_state,
611 __location__);
612 if (h == NULL) {
613 return NULL;
615 hs->p = p;
617 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
619 return h;
622 /* initialise a dcerpc pipe. */
623 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
625 struct dcerpc_pipe *p;
627 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
628 if (!p) {
629 return NULL;
632 p->conn = dcerpc_connection_init(p, ev);
633 if (p->conn == NULL) {
634 talloc_free(p);
635 return NULL;
638 p->last_fault_code = 0;
639 p->context_id = 0;
640 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
641 p->binding = NULL;
643 ZERO_STRUCT(p->syntax);
644 ZERO_STRUCT(p->transfer_syntax);
646 if (DEBUGLVL(100)) {
647 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
650 p->binding_handle = dcerpc_pipe_binding_handle(p);
651 if (p->binding_handle == NULL) {
652 talloc_free(p);
653 return NULL;
656 return p;
661 choose the next call id to use
663 static uint32_t next_call_id(struct dcecli_connection *c)
665 c->call_id++;
666 if (c->call_id == 0) {
667 c->call_id++;
669 return c->call_id;
673 setup for a ndr pull, also setting up any flags from the binding string
675 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
676 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
678 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
680 if (ndr == NULL) return ndr;
682 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
683 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
686 if (c->flags & DCERPC_NDR_REF_ALLOC) {
687 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
690 if (c->flags & DCERPC_NDR64) {
691 ndr->flags |= LIBNDR_FLAG_NDR64;
694 return ndr;
698 parse a data blob into a ncacn_packet structure. This handles both
699 input and output packets
701 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
702 struct ncacn_packet *pkt)
704 struct ndr_pull *ndr;
705 enum ndr_err_code ndr_err;
707 ndr = ndr_pull_init_blob(blob, mem_ctx);
708 if (!ndr) {
709 return NT_STATUS_NO_MEMORY;
712 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
713 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
716 if (CVAL(blob->data, DCERPC_PFC_OFFSET) & DCERPC_PFC_FLAG_OBJECT_UUID) {
717 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
720 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
721 TALLOC_FREE(ndr);
722 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
723 return ndr_map_error2ntstatus(ndr_err);
726 if (pkt->frag_length != blob->length) {
727 return NT_STATUS_RPC_PROTOCOL_ERROR;
730 return NT_STATUS_OK;
734 parse the authentication information on a dcerpc response packet
736 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
737 DATA_BLOB *raw_packet,
738 struct ncacn_packet *pkt)
740 NTSTATUS status;
741 struct dcerpc_auth auth;
742 uint32_t auth_length;
744 if (!c->security_state.auth_info ||
745 !c->security_state.generic_state) {
746 return NT_STATUS_OK;
749 switch (c->security_state.auth_info->auth_level) {
750 case DCERPC_AUTH_LEVEL_PRIVACY:
751 case DCERPC_AUTH_LEVEL_INTEGRITY:
752 break;
754 case DCERPC_AUTH_LEVEL_CONNECT:
755 if (pkt->auth_length != 0) {
756 break;
758 return NT_STATUS_OK;
759 case DCERPC_AUTH_LEVEL_NONE:
760 if (pkt->auth_length != 0) {
761 return NT_STATUS_INVALID_NETWORK_RESPONSE;
763 return NT_STATUS_OK;
765 default:
766 return NT_STATUS_INVALID_LEVEL;
769 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
770 &pkt->u.response.stub_and_verifier,
771 &auth, &auth_length, false);
772 NT_STATUS_NOT_OK_RETURN(status);
774 pkt->u.response.stub_and_verifier.length -= auth_length;
776 /* check signature or unseal the packet */
777 switch (c->security_state.auth_info->auth_level) {
778 case DCERPC_AUTH_LEVEL_PRIVACY:
779 status = gensec_unseal_packet(c->security_state.generic_state,
780 raw_packet->data + DCERPC_REQUEST_LENGTH,
781 pkt->u.response.stub_and_verifier.length,
782 raw_packet->data,
783 raw_packet->length - auth.credentials.length,
784 &auth.credentials);
785 memcpy(pkt->u.response.stub_and_verifier.data,
786 raw_packet->data + DCERPC_REQUEST_LENGTH,
787 pkt->u.response.stub_and_verifier.length);
788 break;
790 case DCERPC_AUTH_LEVEL_INTEGRITY:
791 status = gensec_check_packet(c->security_state.generic_state,
792 pkt->u.response.stub_and_verifier.data,
793 pkt->u.response.stub_and_verifier.length,
794 raw_packet->data,
795 raw_packet->length - auth.credentials.length,
796 &auth.credentials);
797 break;
799 case DCERPC_AUTH_LEVEL_CONNECT:
800 /* for now we ignore possible signatures here */
801 status = NT_STATUS_OK;
802 break;
804 default:
805 status = NT_STATUS_INVALID_LEVEL;
806 break;
809 /* remove the indicated amount of padding */
810 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
811 return NT_STATUS_INFO_LENGTH_MISMATCH;
813 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
815 return status;
820 push a dcerpc request packet into a blob, possibly signing it.
822 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
823 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
824 size_t sig_size,
825 struct ncacn_packet *pkt)
827 NTSTATUS status;
828 struct ndr_push *ndr;
829 DATA_BLOB creds2;
830 size_t payload_length;
831 enum ndr_err_code ndr_err;
832 size_t hdr_size = DCERPC_REQUEST_LENGTH;
834 /* non-signed packets are simpler */
835 if (sig_size == 0) {
836 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
839 switch (c->security_state.auth_info->auth_level) {
840 case DCERPC_AUTH_LEVEL_PRIVACY:
841 case DCERPC_AUTH_LEVEL_INTEGRITY:
842 break;
844 case DCERPC_AUTH_LEVEL_CONNECT:
845 /* TODO: let the gensec mech decide if it wants to generate a signature */
846 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
848 case DCERPC_AUTH_LEVEL_NONE:
849 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
851 default:
852 return NT_STATUS_INVALID_LEVEL;
855 ndr = ndr_push_init_ctx(mem_ctx);
856 if (!ndr) {
857 return NT_STATUS_NO_MEMORY;
860 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
861 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
864 if (c->flags & DCERPC_NDR64) {
865 ndr->flags |= LIBNDR_FLAG_NDR64;
868 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
869 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
870 hdr_size += 16;
873 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
874 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
875 return ndr_map_error2ntstatus(ndr_err);
878 /* pad to 16 byte multiple in the payload portion of the
879 packet. This matches what w2k3 does. Note that we can't use
880 ndr_push_align() as that is relative to the start of the
881 whole packet, whereas w2k8 wants it relative to the start
882 of the stub */
883 c->security_state.auth_info->auth_pad_length =
884 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
885 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
886 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
887 return ndr_map_error2ntstatus(ndr_err);
890 payload_length = pkt->u.request.stub_and_verifier.length +
891 c->security_state.auth_info->auth_pad_length;
893 /* we start without signature, it will appended later */
894 c->security_state.auth_info->credentials = data_blob(NULL,0);
896 /* add the auth verifier */
897 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
898 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
899 return ndr_map_error2ntstatus(ndr_err);
902 /* extract the whole packet as a blob */
903 *blob = ndr_push_blob(ndr);
906 * Setup the frag and auth length in the packet buffer.
907 * This is needed if the GENSEC mech does AEAD signing
908 * of the packet headers. The signature itself will be
909 * appended later.
911 dcerpc_set_frag_length(blob, blob->length + sig_size);
912 dcerpc_set_auth_length(blob, sig_size);
914 /* sign or seal the packet */
915 switch (c->security_state.auth_info->auth_level) {
916 case DCERPC_AUTH_LEVEL_PRIVACY:
917 status = gensec_seal_packet(c->security_state.generic_state,
918 mem_ctx,
919 blob->data + hdr_size,
920 payload_length,
921 blob->data,
922 blob->length,
923 &creds2);
924 if (!NT_STATUS_IS_OK(status)) {
925 return status;
927 break;
929 case DCERPC_AUTH_LEVEL_INTEGRITY:
930 status = gensec_sign_packet(c->security_state.generic_state,
931 mem_ctx,
932 blob->data + hdr_size,
933 payload_length,
934 blob->data,
935 blob->length,
936 &creds2);
937 if (!NT_STATUS_IS_OK(status)) {
938 return status;
940 break;
942 default:
943 status = NT_STATUS_INVALID_LEVEL;
944 break;
947 if (creds2.length != sig_size) {
948 /* this means the sig_size estimate for the signature
949 was incorrect. We have to correct the packet
950 sizes. That means we could go over the max fragment
951 length */
952 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
953 (unsigned) creds2.length,
954 (unsigned) sig_size,
955 (unsigned) c->security_state.auth_info->auth_pad_length,
956 (unsigned) pkt->u.request.stub_and_verifier.length));
957 dcerpc_set_frag_length(blob, blob->length + creds2.length);
958 dcerpc_set_auth_length(blob, creds2.length);
961 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
962 return NT_STATUS_NO_MEMORY;
965 return NT_STATUS_OK;
970 fill in the fixed values in a dcerpc header
972 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
974 pkt->rpc_vers = 5;
975 pkt->rpc_vers_minor = 0;
976 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
977 pkt->drep[0] = 0;
978 } else {
979 pkt->drep[0] = DCERPC_DREP_LE;
981 pkt->drep[1] = 0;
982 pkt->drep[2] = 0;
983 pkt->drep[3] = 0;
987 map a bind nak reason to a NTSTATUS
989 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
991 switch (reason) {
992 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
993 return NT_STATUS_REVISION_MISMATCH;
994 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
995 return NT_STATUS_INVALID_PARAMETER;
996 default:
997 break;
999 return NT_STATUS_UNSUCCESSFUL;
1002 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
1004 if (ack == NULL) {
1005 return NT_STATUS_RPC_PROTOCOL_ERROR;
1008 switch (ack->result) {
1009 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
1011 * We have not asked for this...
1013 return NT_STATUS_RPC_PROTOCOL_ERROR;
1014 default:
1015 break;
1018 switch (ack->reason.value) {
1019 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1020 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1021 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1022 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1023 default:
1024 break;
1026 return NT_STATUS_UNSUCCESSFUL;
1030 remove requests from the pending or queued queues
1032 static int dcerpc_req_dequeue(struct rpc_request *req)
1034 switch (req->state) {
1035 case RPC_REQUEST_QUEUED:
1036 DLIST_REMOVE(req->p->conn->request_queue, req);
1037 break;
1038 case RPC_REQUEST_PENDING:
1039 DLIST_REMOVE(req->p->conn->pending, req);
1040 break;
1041 case RPC_REQUEST_DONE:
1042 break;
1044 return 0;
1049 mark the dcerpc connection dead. All outstanding requests get an error
1051 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1053 if (conn->dead) return;
1055 conn->dead = true;
1057 TALLOC_FREE(conn->io_trigger);
1058 conn->io_trigger_pending = false;
1060 dcerpc_shutdown_pipe(conn, status);
1062 /* all pending requests get the error */
1063 while (conn->pending) {
1064 struct rpc_request *req = conn->pending;
1065 dcerpc_req_dequeue(req);
1066 req->state = RPC_REQUEST_DONE;
1067 req->status = status;
1068 if (req->async.callback) {
1069 req->async.callback(req);
1073 /* all requests, which are not shipped */
1074 while (conn->request_queue) {
1075 struct rpc_request *req = conn->request_queue;
1076 dcerpc_req_dequeue(req);
1077 req->state = RPC_REQUEST_DONE;
1078 req->status = status;
1079 if (req->async.callback) {
1080 req->async.callback(req);
1084 talloc_set_destructor(conn, NULL);
1085 if (conn->free_skipped) {
1086 talloc_free(conn);
1091 forward declarations of the recv_data handlers for the types of
1092 packets we need to handle
1094 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1095 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1098 receive a dcerpc reply from the transport. Here we work out what
1099 type of reply it is (normal request, bind or alter context) and
1100 dispatch to the appropriate handler
1102 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1104 struct ncacn_packet pkt;
1106 if (conn->dead) {
1107 return;
1110 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1111 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1114 /* the transport may be telling us of a severe error, such as
1115 a dropped socket */
1116 if (!NT_STATUS_IS_OK(status)) {
1117 data_blob_free(blob);
1118 dcerpc_connection_dead(conn, status);
1119 return;
1122 /* parse the basic packet to work out what type of response this is */
1123 status = ncacn_pull(conn, blob, blob->data, &pkt);
1124 if (!NT_STATUS_IS_OK(status)) {
1125 data_blob_free(blob);
1126 dcerpc_connection_dead(conn, status);
1127 return;
1130 dcerpc_request_recv_data(conn, blob, &pkt);
1134 handle timeouts of individual dcerpc requests
1136 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1137 struct timeval t, void *private_data)
1139 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1141 if (req->ignore_timeout) {
1142 dcerpc_req_dequeue(req);
1143 req->state = RPC_REQUEST_DONE;
1144 req->status = NT_STATUS_IO_TIMEOUT;
1145 if (req->async.callback) {
1146 req->async.callback(req);
1148 return;
1151 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1154 struct dcerpc_bind_state {
1155 struct tevent_context *ev;
1156 struct dcerpc_pipe *p;
1159 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1160 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1161 DATA_BLOB *raw_packet,
1162 struct ncacn_packet *pkt);
1164 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1165 struct tevent_context *ev,
1166 struct dcerpc_pipe *p,
1167 const struct ndr_syntax_id *syntax,
1168 const struct ndr_syntax_id *transfer_syntax)
1170 struct tevent_req *req;
1171 struct dcerpc_bind_state *state;
1172 struct ncacn_packet pkt;
1173 DATA_BLOB blob;
1174 NTSTATUS status;
1175 struct rpc_request *subreq;
1176 uint32_t flags;
1178 req = tevent_req_create(mem_ctx, &state,
1179 struct dcerpc_bind_state);
1180 if (req == NULL) {
1181 return NULL;
1184 state->ev = ev;
1185 state->p = p;
1187 p->syntax = *syntax;
1188 p->transfer_syntax = *transfer_syntax;
1190 flags = dcerpc_binding_get_flags(p->binding);
1192 init_ncacn_hdr(p->conn, &pkt);
1194 pkt.ptype = DCERPC_PKT_BIND;
1195 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1196 pkt.call_id = p->conn->call_id;
1197 pkt.auth_length = 0;
1199 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1200 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1203 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1204 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1207 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1208 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1209 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1210 pkt.u.bind.num_contexts = 1;
1211 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1212 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1213 return tevent_req_post(req, ev);
1215 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1216 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1217 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1218 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1219 pkt.u.bind.auth_info = data_blob(NULL, 0);
1221 /* construct the NDR form of the packet */
1222 status = ncacn_push_auth(&blob, state, &pkt,
1223 p->conn->security_state.auth_info);
1224 if (tevent_req_nterror(req, status)) {
1225 return tevent_req_post(req, ev);
1229 * we allocate a dcerpc_request so we can be in the same
1230 * request queue as normal requests
1232 subreq = talloc_zero(state, struct rpc_request);
1233 if (tevent_req_nomem(subreq, req)) {
1234 return tevent_req_post(req, ev);
1237 subreq->state = RPC_REQUEST_PENDING;
1238 subreq->call_id = pkt.call_id;
1239 subreq->async.private_data = req;
1240 subreq->async.callback = dcerpc_bind_fail_handler;
1241 subreq->p = p;
1242 subreq->recv_handler = dcerpc_bind_recv_handler;
1243 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1244 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1246 status = dcerpc_send_request(p->conn, &blob, true);
1247 if (tevent_req_nterror(req, status)) {
1248 return tevent_req_post(req, ev);
1251 tevent_add_timer(ev, subreq,
1252 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1253 dcerpc_timeout_handler, subreq);
1255 return req;
1258 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1260 struct tevent_req *req =
1261 talloc_get_type_abort(subreq->async.private_data,
1262 struct tevent_req);
1263 struct dcerpc_bind_state *state =
1264 tevent_req_data(req,
1265 struct dcerpc_bind_state);
1266 NTSTATUS status = subreq->status;
1268 TALLOC_FREE(subreq);
1271 * We trigger the callback in the next event run
1272 * because the code in this file might trigger
1273 * multiple request callbacks from within a single
1274 * while loop.
1276 * In order to avoid segfaults from within
1277 * dcerpc_connection_dead() we call
1278 * tevent_req_defer_callback().
1280 tevent_req_defer_callback(req, state->ev);
1282 tevent_req_nterror(req, status);
1285 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1286 DATA_BLOB *raw_packet,
1287 struct ncacn_packet *pkt)
1289 struct tevent_req *req =
1290 talloc_get_type_abort(subreq->async.private_data,
1291 struct tevent_req);
1292 struct dcerpc_bind_state *state =
1293 tevent_req_data(req,
1294 struct dcerpc_bind_state);
1295 struct dcecli_connection *conn = state->p->conn;
1296 struct dcerpc_binding *b = NULL;
1297 NTSTATUS status;
1298 uint32_t flags;
1301 * Note that pkt is allocated under raw_packet->data,
1302 * while raw_packet->data is a child of subreq.
1304 talloc_steal(state, raw_packet->data);
1305 TALLOC_FREE(subreq);
1308 * We trigger the callback in the next event run
1309 * because the code in this file might trigger
1310 * multiple request callbacks from within a single
1311 * while loop.
1313 * In order to avoid segfaults from within
1314 * dcerpc_connection_dead() we call
1315 * tevent_req_defer_callback().
1317 tevent_req_defer_callback(req, state->ev);
1319 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1320 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1322 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1323 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1325 tevent_req_nterror(req, status);
1326 return;
1329 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1330 (pkt->u.bind_ack.num_results == 0) ||
1331 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1332 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1333 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1334 return;
1338 * DCE-RPC 1.1 (c706) specifies
1339 * CONST_MUST_RCV_FRAG_SIZE as 1432
1341 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1342 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1343 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1344 return;
1346 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1347 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1348 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1349 return;
1351 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1352 pkt->u.bind_ack.max_xmit_frag);
1353 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1354 pkt->u.bind_ack.max_recv_frag);
1356 flags = dcerpc_binding_get_flags(state->p->binding);
1358 if ((flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1359 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1360 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1363 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1364 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1365 conn->flags |= DCERPC_HEADER_SIGNING;
1368 /* the bind_ack might contain a reply set of credentials */
1369 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1370 uint32_t auth_length;
1372 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1373 conn->security_state.auth_info, &auth_length, true);
1374 if (tevent_req_nterror(req, status)) {
1375 return;
1380 * We're the owner of the binding, so we're allowed to modify it.
1382 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1383 status = dcerpc_binding_set_assoc_group_id(b,
1384 pkt->u.bind_ack.assoc_group_id);
1385 if (tevent_req_nterror(req, status)) {
1386 return;
1389 tevent_req_done(req);
1392 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1394 return tevent_req_simple_recv_ntstatus(req);
1398 perform a continued bind (and auth3)
1400 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1401 TALLOC_CTX *mem_ctx)
1403 struct ncacn_packet pkt;
1404 NTSTATUS status;
1405 DATA_BLOB blob;
1406 uint32_t flags;
1408 flags = dcerpc_binding_get_flags(p->binding);
1410 init_ncacn_hdr(p->conn, &pkt);
1412 pkt.ptype = DCERPC_PKT_AUTH3;
1413 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1414 pkt.call_id = next_call_id(p->conn);
1415 pkt.auth_length = 0;
1416 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1418 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1419 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1422 /* construct the NDR form of the packet */
1423 status = ncacn_push_auth(&blob, mem_ctx,
1424 &pkt,
1425 p->conn->security_state.auth_info);
1426 if (!NT_STATUS_IS_OK(status)) {
1427 return status;
1430 /* send it on its way */
1431 status = dcerpc_send_request(p->conn, &blob, false);
1432 if (!NT_STATUS_IS_OK(status)) {
1433 return status;
1436 return NT_STATUS_OK;
1441 process a fragment received from the transport layer during a
1442 request
1444 This function frees the data
1446 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1447 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1449 struct rpc_request *req;
1450 unsigned int length;
1451 NTSTATUS status = NT_STATUS_OK;
1454 if this is an authenticated connection then parse and check
1455 the auth info. We have to do this before finding the
1456 matching packet, as the request structure might have been
1457 removed due to a timeout, but if it has been we still need
1458 to run the auth routines so that we don't get the sign/seal
1459 info out of step with the server
1461 if (c->security_state.auth_info && c->security_state.generic_state &&
1462 pkt->ptype == DCERPC_PKT_RESPONSE) {
1463 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1466 /* find the matching request */
1467 for (req=c->pending;req;req=req->next) {
1468 if (pkt->call_id == req->call_id) break;
1471 #if 0
1472 /* useful for testing certain vendors RPC servers */
1473 if (req == NULL && c->pending && pkt->call_id == 0) {
1474 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1475 req = c->pending;
1477 #endif
1479 if (req == NULL) {
1480 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1481 data_blob_free(raw_packet);
1482 return;
1485 talloc_steal(req, raw_packet->data);
1487 if (req->recv_handler != NULL) {
1488 dcerpc_req_dequeue(req);
1489 req->state = RPC_REQUEST_DONE;
1492 * We have to look at shipping further requests before calling
1493 * the async function, that one might close the pipe
1495 dcerpc_schedule_io_trigger(c);
1497 req->recv_handler(req, raw_packet, pkt);
1498 return;
1501 if (pkt->ptype == DCERPC_PKT_FAULT) {
1502 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1503 req->fault_code = pkt->u.fault.status;
1504 req->status = NT_STATUS_NET_WRITE_FAULT;
1505 goto req_done;
1508 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1509 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1510 (int)pkt->ptype));
1511 req->fault_code = DCERPC_FAULT_OTHER;
1512 req->status = NT_STATUS_NET_WRITE_FAULT;
1513 goto req_done;
1516 /* now check the status from the auth routines, and if it failed then fail
1517 this request accordingly */
1518 if (!NT_STATUS_IS_OK(status)) {
1519 req->status = status;
1520 goto req_done;
1523 length = pkt->u.response.stub_and_verifier.length;
1525 if (length > 0) {
1526 req->payload.data = talloc_realloc(req,
1527 req->payload.data,
1528 uint8_t,
1529 req->payload.length + length);
1530 if (!req->payload.data) {
1531 req->status = NT_STATUS_NO_MEMORY;
1532 goto req_done;
1534 memcpy(req->payload.data+req->payload.length,
1535 pkt->u.response.stub_and_verifier.data, length);
1536 req->payload.length += length;
1539 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1540 data_blob_free(raw_packet);
1541 dcerpc_send_read(c);
1542 return;
1545 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1546 req->flags |= DCERPC_PULL_BIGENDIAN;
1547 } else {
1548 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1551 req_done:
1552 data_blob_free(raw_packet);
1554 /* we've got the full payload */
1555 dcerpc_req_dequeue(req);
1556 req->state = RPC_REQUEST_DONE;
1559 * We have to look at shipping further requests before calling
1560 * the async function, that one might close the pipe
1562 dcerpc_schedule_io_trigger(c);
1564 if (req->async.callback) {
1565 req->async.callback(req);
1570 perform the send side of a async dcerpc request
1572 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1573 struct dcerpc_pipe *p,
1574 const struct GUID *object,
1575 uint16_t opnum,
1576 DATA_BLOB *stub_data)
1578 struct rpc_request *req;
1580 req = talloc_zero(mem_ctx, struct rpc_request);
1581 if (req == NULL) {
1582 return NULL;
1585 req->p = p;
1586 req->call_id = next_call_id(p->conn);
1587 req->state = RPC_REQUEST_QUEUED;
1589 if (object != NULL) {
1590 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1591 if (req->object == NULL) {
1592 talloc_free(req);
1593 return NULL;
1597 req->opnum = opnum;
1598 req->request_data.length = stub_data->length;
1599 req->request_data.data = stub_data->data;
1601 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1602 talloc_set_destructor(req, dcerpc_req_dequeue);
1604 dcerpc_schedule_io_trigger(p->conn);
1606 if (p->request_timeout) {
1607 tevent_add_timer(p->conn->event_ctx, req,
1608 timeval_current_ofs(p->request_timeout, 0),
1609 dcerpc_timeout_handler, req);
1612 return req;
1616 Send a request using the transport
1619 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1621 struct rpc_request *req;
1622 struct dcerpc_pipe *p;
1623 DATA_BLOB *stub_data;
1624 struct ncacn_packet pkt;
1625 DATA_BLOB blob;
1626 uint32_t remaining, chunk_size;
1627 bool first_packet = true;
1628 size_t sig_size = 0;
1629 bool need_async = false;
1630 bool can_async = true;
1632 req = c->request_queue;
1633 if (req == NULL) {
1634 return;
1637 p = req->p;
1638 stub_data = &req->request_data;
1640 if (c->pending) {
1641 need_async = true;
1644 if (c->security_state.auth_info &&
1645 c->security_state.generic_state)
1647 struct gensec_security *gensec = c->security_state.generic_state;
1649 switch (c->security_state.auth_info->auth_level) {
1650 case DCERPC_AUTH_LEVEL_PRIVACY:
1651 case DCERPC_AUTH_LEVEL_INTEGRITY:
1652 can_async = gensec_have_feature(gensec,
1653 GENSEC_FEATURE_ASYNC_REPLIES);
1654 break;
1655 case DCERPC_AUTH_LEVEL_CONNECT:
1656 case DCERPC_AUTH_LEVEL_NONE:
1657 can_async = true;
1658 break;
1659 default:
1660 can_async = false;
1661 break;
1665 if (need_async && !can_async) {
1666 req->wait_for_sync = true;
1667 return;
1670 DLIST_REMOVE(c->request_queue, req);
1671 DLIST_ADD(c->pending, req);
1672 req->state = RPC_REQUEST_PENDING;
1674 init_ncacn_hdr(p->conn, &pkt);
1676 remaining = stub_data->length;
1678 /* we can write a full max_recv_frag size, minus the dcerpc
1679 request header size */
1680 chunk_size = p->conn->srv_max_recv_frag;
1681 chunk_size -= DCERPC_REQUEST_LENGTH;
1682 if (c->security_state.auth_info &&
1683 c->security_state.generic_state) {
1684 sig_size = gensec_sig_size(c->security_state.generic_state,
1685 p->conn->srv_max_recv_frag);
1686 if (sig_size) {
1687 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1688 chunk_size -= sig_size;
1691 chunk_size -= (chunk_size % 16);
1693 pkt.ptype = DCERPC_PKT_REQUEST;
1694 pkt.call_id = req->call_id;
1695 pkt.auth_length = 0;
1696 pkt.pfc_flags = 0;
1697 pkt.u.request.context_id = p->context_id;
1698 pkt.u.request.opnum = req->opnum;
1700 if (req->object) {
1701 pkt.u.request.object.object = *req->object;
1702 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1703 chunk_size -= ndr_size_GUID(req->object,0);
1706 /* we send a series of pdus without waiting for a reply */
1707 while (remaining > 0 || first_packet) {
1708 uint32_t chunk = MIN(chunk_size, remaining);
1709 bool last_frag = false;
1710 bool do_trans = false;
1712 first_packet = false;
1713 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1715 if (remaining == stub_data->length) {
1716 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1718 if (chunk == remaining) {
1719 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1720 last_frag = true;
1723 pkt.u.request.alloc_hint = remaining;
1724 pkt.u.request.stub_and_verifier.data = stub_data->data +
1725 (stub_data->length - remaining);
1726 pkt.u.request.stub_and_verifier.length = chunk;
1728 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1729 if (!NT_STATUS_IS_OK(req->status)) {
1730 req->state = RPC_REQUEST_DONE;
1731 DLIST_REMOVE(p->conn->pending, req);
1732 return;
1735 if (last_frag && !need_async) {
1736 do_trans = true;
1739 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1740 if (!NT_STATUS_IS_OK(req->status)) {
1741 req->state = RPC_REQUEST_DONE;
1742 DLIST_REMOVE(p->conn->pending, req);
1743 return;
1746 if (last_frag && !do_trans) {
1747 req->status = dcerpc_send_read(p->conn);
1748 if (!NT_STATUS_IS_OK(req->status)) {
1749 req->state = RPC_REQUEST_DONE;
1750 DLIST_REMOVE(p->conn->pending, req);
1751 return;
1755 remaining -= chunk;
1759 static void dcerpc_io_trigger(struct tevent_context *ctx,
1760 struct tevent_immediate *im,
1761 void *private_data)
1763 struct dcecli_connection *c =
1764 talloc_get_type_abort(private_data,
1765 struct dcecli_connection);
1767 c->io_trigger_pending = false;
1769 dcerpc_schedule_io_trigger(c);
1771 dcerpc_ship_next_request(c);
1774 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1776 if (c->dead) {
1777 return;
1780 if (c->request_queue == NULL) {
1781 return;
1784 if (c->request_queue->wait_for_sync && c->pending) {
1785 return;
1788 if (c->io_trigger_pending) {
1789 return;
1792 c->io_trigger_pending = true;
1794 tevent_schedule_immediate(c->io_trigger,
1795 c->event_ctx,
1796 dcerpc_io_trigger,
1801 perform the receive side of a async dcerpc request
1803 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1804 TALLOC_CTX *mem_ctx,
1805 DATA_BLOB *stub_data)
1807 NTSTATUS status;
1809 while (req->state != RPC_REQUEST_DONE) {
1810 struct tevent_context *ctx = req->p->conn->event_ctx;
1811 if (tevent_loop_once(ctx) != 0) {
1812 return NT_STATUS_CONNECTION_DISCONNECTED;
1815 *stub_data = req->payload;
1816 status = req->status;
1817 if (stub_data->data) {
1818 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1820 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1821 req->p->last_fault_code = req->fault_code;
1823 talloc_unlink(talloc_parent(req), req);
1824 return status;
1828 this is a paranoid NDR validator. For every packet we push onto the wire
1829 we pull it back again, then push it again. Then we compare the raw NDR data
1830 for that to the NDR we initially generated. If they don't match then we know
1831 we must have a bug in either the pull or push side of our code
1833 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1834 TALLOC_CTX *mem_ctx,
1835 DATA_BLOB blob,
1836 size_t struct_size,
1837 ndr_push_flags_fn_t ndr_push,
1838 ndr_pull_flags_fn_t ndr_pull)
1840 void *st;
1841 struct ndr_pull *pull;
1842 struct ndr_push *push;
1843 DATA_BLOB blob2;
1844 enum ndr_err_code ndr_err;
1846 st = talloc_size(mem_ctx, struct_size);
1847 if (!st) {
1848 return NT_STATUS_NO_MEMORY;
1851 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1852 if (!pull) {
1853 return NT_STATUS_NO_MEMORY;
1855 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1857 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1858 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1861 if (c->flags & DCERPC_NDR64) {
1862 pull->flags |= LIBNDR_FLAG_NDR64;
1865 ndr_err = ndr_pull(pull, NDR_IN, st);
1866 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1867 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1868 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1869 "failed input validation pull - %s",
1870 nt_errstr(status));
1871 return ndr_map_error2ntstatus(ndr_err);
1874 push = ndr_push_init_ctx(mem_ctx);
1875 if (!push) {
1876 return NT_STATUS_NO_MEMORY;
1879 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1880 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1883 if (c->flags & DCERPC_NDR64) {
1884 push->flags |= LIBNDR_FLAG_NDR64;
1887 ndr_err = ndr_push(push, NDR_IN, st);
1888 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1889 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1890 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1891 "failed input validation push - %s",
1892 nt_errstr(status));
1893 return ndr_map_error2ntstatus(ndr_err);
1896 blob2 = ndr_push_blob(push);
1898 if (data_blob_cmp(&blob, &blob2) != 0) {
1899 DEBUG(3,("original:\n"));
1900 dump_data(3, blob.data, blob.length);
1901 DEBUG(3,("secondary:\n"));
1902 dump_data(3, blob2.data, blob2.length);
1903 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1904 "failed input validation blobs doesn't match");
1905 return ndr_map_error2ntstatus(ndr_err);
1908 return NT_STATUS_OK;
1912 this is a paranoid NDR input validator. For every packet we pull
1913 from the wire we push it back again then pull and push it
1914 again. Then we compare the raw NDR data for that to the NDR we
1915 initially generated. If they don't match then we know we must have a
1916 bug in either the pull or push side of our code
1918 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1919 struct ndr_pull *pull_in,
1920 void *struct_ptr,
1921 size_t struct_size,
1922 ndr_push_flags_fn_t ndr_push,
1923 ndr_pull_flags_fn_t ndr_pull,
1924 ndr_print_function_t ndr_print)
1926 void *st;
1927 struct ndr_pull *pull;
1928 struct ndr_push *push;
1929 DATA_BLOB blob, blob2;
1930 TALLOC_CTX *mem_ctx = pull_in;
1931 char *s1, *s2;
1932 enum ndr_err_code ndr_err;
1934 st = talloc_size(mem_ctx, struct_size);
1935 if (!st) {
1936 return NT_STATUS_NO_MEMORY;
1938 memcpy(st, struct_ptr, struct_size);
1940 push = ndr_push_init_ctx(mem_ctx);
1941 if (!push) {
1942 return NT_STATUS_NO_MEMORY;
1945 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1946 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1947 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1948 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1949 "failed output validation push - %s",
1950 nt_errstr(status));
1951 return ndr_map_error2ntstatus(ndr_err);
1954 blob = ndr_push_blob(push);
1956 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1957 if (!pull) {
1958 return NT_STATUS_NO_MEMORY;
1961 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1962 ndr_err = ndr_pull(pull, NDR_OUT, st);
1963 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1964 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1965 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1966 "failed output validation pull - %s",
1967 nt_errstr(status));
1968 return ndr_map_error2ntstatus(ndr_err);
1971 push = ndr_push_init_ctx(mem_ctx);
1972 if (!push) {
1973 return NT_STATUS_NO_MEMORY;
1976 ndr_err = ndr_push(push, NDR_OUT, st);
1977 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1978 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1979 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1980 "failed output validation push2 - %s",
1981 nt_errstr(status));
1982 return ndr_map_error2ntstatus(ndr_err);
1985 blob2 = ndr_push_blob(push);
1987 if (data_blob_cmp(&blob, &blob2) != 0) {
1988 DEBUG(3,("original:\n"));
1989 dump_data(3, blob.data, blob.length);
1990 DEBUG(3,("secondary:\n"));
1991 dump_data(3, blob2.data, blob2.length);
1992 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1993 "failed output validation blobs doesn't match");
1994 return ndr_map_error2ntstatus(ndr_err);
1997 /* this checks the printed forms of the two structures, which effectively
1998 tests all of the value() attributes */
1999 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2000 NDR_OUT, struct_ptr);
2001 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2002 NDR_OUT, st);
2003 if (strcmp(s1, s2) != 0) {
2004 #if 1
2005 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2006 #else
2007 /* this is sometimes useful */
2008 printf("VALIDATE ERROR\n");
2009 file_save("wire.dat", s1, strlen(s1));
2010 file_save("gen.dat", s2, strlen(s2));
2011 system("diff -u wire.dat gen.dat");
2012 #endif
2013 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2014 "failed output validation strings doesn't match");
2015 return ndr_map_error2ntstatus(ndr_err);
2018 return NT_STATUS_OK;
2022 a useful function for retrieving the server name we connected to
2024 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2026 return p->conn ? p->conn->server_name : NULL;
2031 get the dcerpc auth_level for a open connection
2033 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2035 uint8_t auth_level;
2037 if (c->flags & DCERPC_SEAL) {
2038 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2039 } else if (c->flags & DCERPC_SIGN) {
2040 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2041 } else if (c->flags & DCERPC_CONNECT) {
2042 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2043 } else {
2044 auth_level = DCERPC_AUTH_LEVEL_NONE;
2046 return auth_level;
2049 struct dcerpc_alter_context_state {
2050 struct tevent_context *ev;
2051 struct dcerpc_pipe *p;
2054 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2055 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2056 DATA_BLOB *raw_packet,
2057 struct ncacn_packet *pkt);
2059 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2060 struct tevent_context *ev,
2061 struct dcerpc_pipe *p,
2062 const struct ndr_syntax_id *syntax,
2063 const struct ndr_syntax_id *transfer_syntax)
2065 struct tevent_req *req;
2066 struct dcerpc_alter_context_state *state;
2067 struct ncacn_packet pkt;
2068 DATA_BLOB blob;
2069 NTSTATUS status;
2070 struct rpc_request *subreq;
2071 uint32_t flags;
2073 req = tevent_req_create(mem_ctx, &state,
2074 struct dcerpc_alter_context_state);
2075 if (req == NULL) {
2076 return NULL;
2079 state->ev = ev;
2080 state->p = p;
2082 p->syntax = *syntax;
2083 p->transfer_syntax = *transfer_syntax;
2085 flags = dcerpc_binding_get_flags(p->binding);
2087 init_ncacn_hdr(p->conn, &pkt);
2089 pkt.ptype = DCERPC_PKT_ALTER;
2090 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2091 pkt.call_id = p->conn->call_id;
2092 pkt.auth_length = 0;
2094 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2095 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2098 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2099 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2100 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2101 pkt.u.alter.num_contexts = 1;
2102 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2103 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2104 return tevent_req_post(req, ev);
2106 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2107 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2108 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2109 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2110 pkt.u.alter.auth_info = data_blob(NULL, 0);
2112 /* construct the NDR form of the packet */
2113 status = ncacn_push_auth(&blob, state, &pkt,
2114 p->conn->security_state.auth_info);
2115 if (tevent_req_nterror(req, status)) {
2116 return tevent_req_post(req, ev);
2120 * we allocate a dcerpc_request so we can be in the same
2121 * request queue as normal requests
2123 subreq = talloc_zero(state, struct rpc_request);
2124 if (tevent_req_nomem(subreq, req)) {
2125 return tevent_req_post(req, ev);
2128 subreq->state = RPC_REQUEST_PENDING;
2129 subreq->call_id = pkt.call_id;
2130 subreq->async.private_data = req;
2131 subreq->async.callback = dcerpc_alter_context_fail_handler;
2132 subreq->p = p;
2133 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2134 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2135 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2137 status = dcerpc_send_request(p->conn, &blob, true);
2138 if (tevent_req_nterror(req, status)) {
2139 return tevent_req_post(req, ev);
2142 tevent_add_timer(ev, subreq,
2143 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2144 dcerpc_timeout_handler, subreq);
2146 return req;
2149 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2151 struct tevent_req *req =
2152 talloc_get_type_abort(subreq->async.private_data,
2153 struct tevent_req);
2154 struct dcerpc_alter_context_state *state =
2155 tevent_req_data(req,
2156 struct dcerpc_alter_context_state);
2157 NTSTATUS status = subreq->status;
2159 TALLOC_FREE(subreq);
2162 * We trigger the callback in the next event run
2163 * because the code in this file might trigger
2164 * multiple request callbacks from within a single
2165 * while loop.
2167 * In order to avoid segfaults from within
2168 * dcerpc_connection_dead() we call
2169 * tevent_req_defer_callback().
2171 tevent_req_defer_callback(req, state->ev);
2173 tevent_req_nterror(req, status);
2176 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2177 DATA_BLOB *raw_packet,
2178 struct ncacn_packet *pkt)
2180 struct tevent_req *req =
2181 talloc_get_type_abort(subreq->async.private_data,
2182 struct tevent_req);
2183 struct dcerpc_alter_context_state *state =
2184 tevent_req_data(req,
2185 struct dcerpc_alter_context_state);
2186 struct dcecli_connection *conn = state->p->conn;
2187 NTSTATUS status;
2190 * Note that pkt is allocated under raw_packet->data,
2191 * while raw_packet->data is a child of subreq.
2193 talloc_steal(state, raw_packet->data);
2194 TALLOC_FREE(subreq);
2197 * We trigger the callback in the next event run
2198 * because the code in this file might trigger
2199 * multiple request callbacks from within a single
2200 * while loop.
2202 * In order to avoid segfaults from within
2203 * dcerpc_connection_dead() we call
2204 * tevent_req_defer_callback().
2206 tevent_req_defer_callback(req, state->ev);
2208 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2209 pkt->u.alter_resp.num_results == 1 &&
2210 pkt->u.alter_resp.ctx_list[0].result != 0) {
2211 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2212 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2213 pkt->u.alter_resp.ctx_list[0].reason.value,
2214 nt_errstr(status)));
2215 tevent_req_nterror(req, status);
2216 return;
2219 if (pkt->ptype == DCERPC_PKT_FAULT) {
2220 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2221 dcerpc_errstr(state, pkt->u.fault.status)));
2222 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2223 state->p->last_fault_code = pkt->u.fault.status;
2224 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2225 } else {
2226 state->p->last_fault_code = pkt->u.fault.status;
2227 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2228 tevent_req_nterror(req, status);
2230 return;
2233 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2234 pkt->u.alter_resp.num_results == 0 ||
2235 pkt->u.alter_resp.ctx_list[0].result != 0) {
2236 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2237 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2238 return;
2241 /* the alter_resp might contain a reply set of credentials */
2242 if (conn->security_state.auth_info &&
2243 pkt->u.alter_resp.auth_info.length) {
2244 uint32_t auth_length;
2246 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2247 conn->security_state.auth_info, &auth_length, true);
2248 if (tevent_req_nterror(req, status)) {
2249 return;
2253 tevent_req_done(req);
2256 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2258 return tevent_req_simple_recv_ntstatus(req);
2262 send a dcerpc alter_context request
2264 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2265 TALLOC_CTX *mem_ctx,
2266 const struct ndr_syntax_id *syntax,
2267 const struct ndr_syntax_id *transfer_syntax)
2269 struct tevent_req *subreq;
2270 struct tevent_context *ev = p->conn->event_ctx;
2271 bool ok;
2273 /* TODO: create a new event context here */
2275 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2276 p, syntax, transfer_syntax);
2277 if (subreq == NULL) {
2278 return NT_STATUS_NO_MEMORY;
2281 ok = tevent_req_poll(subreq, ev);
2282 if (!ok) {
2283 NTSTATUS status;
2284 status = map_nt_error_from_unix_common(errno);
2285 return status;
2288 return dcerpc_alter_context_recv(subreq);
2291 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2293 if (c->transport.stream == NULL) {
2294 return;
2297 tevent_queue_stop(c->transport.write_queue);
2298 TALLOC_FREE(c->transport.read_subreq);
2299 TALLOC_FREE(c->transport.stream);
2301 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2302 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2305 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2306 status = NT_STATUS_END_OF_FILE;
2309 dcerpc_recv_data(c, NULL, status);
2314 shutdown SMB pipe connection
2316 struct dcerpc_shutdown_pipe_state {
2317 struct dcecli_connection *c;
2318 NTSTATUS status;
2321 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2323 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2325 struct dcerpc_shutdown_pipe_state *state;
2326 struct tevent_req *subreq;
2328 if (c->transport.stream == NULL) {
2329 return NT_STATUS_OK;
2332 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2333 if (state == NULL) {
2334 return NT_STATUS_NO_MEMORY;
2336 state->c = c;
2337 state->status = status;
2339 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2340 if (subreq == NULL) {
2341 return NT_STATUS_NO_MEMORY;
2343 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2345 return status;
2348 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2350 struct dcerpc_shutdown_pipe_state *state =
2351 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2352 struct dcecli_connection *c = state->c;
2353 NTSTATUS status = state->status;
2354 int error;
2357 * here we ignore the return values...
2359 tstream_disconnect_recv(subreq, &error);
2360 TALLOC_FREE(subreq);
2362 TALLOC_FREE(state);
2364 dcerpc_transport_dead(c, status);
2369 struct dcerpc_send_read_state {
2370 struct dcecli_connection *p;
2373 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2375 struct dcecli_connection *p = state->p;
2377 p->transport.read_subreq = NULL;
2379 return 0;
2382 static void dcerpc_send_read_done(struct tevent_req *subreq);
2384 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2386 struct dcerpc_send_read_state *state;
2388 if (p->transport.read_subreq != NULL) {
2389 p->transport.pending_reads++;
2390 return NT_STATUS_OK;
2393 state = talloc_zero(p, struct dcerpc_send_read_state);
2394 if (state == NULL) {
2395 return NT_STATUS_NO_MEMORY;
2397 state->p = p;
2399 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2401 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2402 p->event_ctx,
2403 p->transport.stream);
2404 if (p->transport.read_subreq == NULL) {
2405 return NT_STATUS_NO_MEMORY;
2407 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2409 return NT_STATUS_OK;
2412 static void dcerpc_send_read_done(struct tevent_req *subreq)
2414 struct dcerpc_send_read_state *state =
2415 tevent_req_callback_data(subreq,
2416 struct dcerpc_send_read_state);
2417 struct dcecli_connection *p = state->p;
2418 NTSTATUS status;
2419 struct ncacn_packet *pkt;
2420 DATA_BLOB blob;
2422 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2423 &pkt, &blob);
2424 TALLOC_FREE(subreq);
2425 if (!NT_STATUS_IS_OK(status)) {
2426 TALLOC_FREE(state);
2427 dcerpc_transport_dead(p, status);
2428 return;
2432 * here we steal into thet connection context,
2433 * but p->transport.recv_data() will steal or free it again
2435 talloc_steal(p, blob.data);
2436 TALLOC_FREE(state);
2438 if (p->transport.pending_reads > 0) {
2439 p->transport.pending_reads--;
2441 status = dcerpc_send_read(p);
2442 if (!NT_STATUS_IS_OK(status)) {
2443 dcerpc_transport_dead(p, status);
2444 return;
2448 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2451 struct dcerpc_send_request_state {
2452 struct dcecli_connection *p;
2453 DATA_BLOB blob;
2454 struct iovec iov;
2457 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2459 struct dcecli_connection *p = state->p;
2461 p->transport.read_subreq = NULL;
2463 return 0;
2466 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2467 static void dcerpc_send_request_done(struct tevent_req *subreq);
2469 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2470 bool trigger_read)
2472 struct dcerpc_send_request_state *state;
2473 struct tevent_req *subreq;
2474 bool use_trans = trigger_read;
2476 if (p->transport.stream == NULL) {
2477 return NT_STATUS_CONNECTION_DISCONNECTED;
2480 state = talloc_zero(p, struct dcerpc_send_request_state);
2481 if (state == NULL) {
2482 return NT_STATUS_NO_MEMORY;
2484 state->p = p;
2486 state->blob = data_blob_talloc(state, data->data, data->length);
2487 if (state->blob.data == NULL) {
2488 TALLOC_FREE(state);
2489 return NT_STATUS_NO_MEMORY;
2491 state->iov.iov_base = (void *)state->blob.data;
2492 state->iov.iov_len = state->blob.length;
2494 if (p->transport.read_subreq != NULL) {
2495 use_trans = false;
2498 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2499 use_trans = false;
2502 if (use_trans) {
2504 * we need to block reads until our write is
2505 * the next in the write queue.
2507 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2508 p->transport.write_queue);
2509 if (p->transport.read_subreq == NULL) {
2510 TALLOC_FREE(state);
2511 return NT_STATUS_NO_MEMORY;
2513 tevent_req_set_callback(p->transport.read_subreq,
2514 dcerpc_send_request_wait_done,
2515 state);
2517 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2519 trigger_read = false;
2522 subreq = tstream_writev_queue_send(state, p->event_ctx,
2523 p->transport.stream,
2524 p->transport.write_queue,
2525 &state->iov, 1);
2526 if (subreq == NULL) {
2527 TALLOC_FREE(state);
2528 return NT_STATUS_NO_MEMORY;
2530 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2532 if (trigger_read) {
2533 dcerpc_send_read(p);
2536 return NT_STATUS_OK;
2539 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2541 struct dcerpc_send_request_state *state =
2542 tevent_req_callback_data(subreq,
2543 struct dcerpc_send_request_state);
2544 struct dcecli_connection *p = state->p;
2545 NTSTATUS status;
2546 bool ok;
2548 p->transport.read_subreq = NULL;
2549 talloc_set_destructor(state, NULL);
2551 ok = tevent_queue_wait_recv(subreq);
2552 if (!ok) {
2553 TALLOC_FREE(state);
2554 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2555 return;
2558 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2559 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2560 if (!NT_STATUS_IS_OK(status)) {
2561 TALLOC_FREE(state);
2562 dcerpc_transport_dead(p, status);
2563 return;
2567 /* we free subreq after tstream_cli_np_use_trans */
2568 TALLOC_FREE(subreq);
2570 dcerpc_send_read(p);
2573 static void dcerpc_send_request_done(struct tevent_req *subreq)
2575 struct dcerpc_send_request_state *state =
2576 tevent_req_callback_data(subreq,
2577 struct dcerpc_send_request_state);
2578 int ret;
2579 int error;
2581 ret = tstream_writev_queue_recv(subreq, &error);
2582 TALLOC_FREE(subreq);
2583 if (ret == -1) {
2584 struct dcecli_connection *p = state->p;
2585 NTSTATUS status = map_nt_error_from_unix_common(error);
2587 TALLOC_FREE(state);
2588 dcerpc_transport_dead(p, status);
2589 return;
2592 TALLOC_FREE(state);