s4:librpc/rpc: let ncacn_push_request_sign() handle sig_size == 0 with auth_info...
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blobf1c6d474ec657508ea43b391627e4cb9e8db427b
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 (c->security_state.auth_info == NULL) {
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 if (sig_size == 0) {
843 return NT_STATUS_INTERNAL_ERROR;
845 break;
847 case DCERPC_AUTH_LEVEL_CONNECT:
848 /* TODO: let the gensec mech decide if it wants to generate a signature */
849 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
851 case DCERPC_AUTH_LEVEL_NONE:
852 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
854 default:
855 return NT_STATUS_INVALID_LEVEL;
858 ndr = ndr_push_init_ctx(mem_ctx);
859 if (!ndr) {
860 return NT_STATUS_NO_MEMORY;
863 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
864 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
867 if (c->flags & DCERPC_NDR64) {
868 ndr->flags |= LIBNDR_FLAG_NDR64;
871 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
872 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
873 hdr_size += 16;
876 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
877 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
878 return ndr_map_error2ntstatus(ndr_err);
881 /* pad to 16 byte multiple in the payload portion of the
882 packet. This matches what w2k3 does. Note that we can't use
883 ndr_push_align() as that is relative to the start of the
884 whole packet, whereas w2k8 wants it relative to the start
885 of the stub */
886 c->security_state.auth_info->auth_pad_length =
887 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
888 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
889 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
890 return ndr_map_error2ntstatus(ndr_err);
893 payload_length = pkt->u.request.stub_and_verifier.length +
894 c->security_state.auth_info->auth_pad_length;
896 /* we start without signature, it will appended later */
897 c->security_state.auth_info->credentials = data_blob(NULL,0);
899 /* add the auth verifier */
900 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
901 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
902 return ndr_map_error2ntstatus(ndr_err);
905 /* extract the whole packet as a blob */
906 *blob = ndr_push_blob(ndr);
909 * Setup the frag and auth length in the packet buffer.
910 * This is needed if the GENSEC mech does AEAD signing
911 * of the packet headers. The signature itself will be
912 * appended later.
914 dcerpc_set_frag_length(blob, blob->length + sig_size);
915 dcerpc_set_auth_length(blob, sig_size);
917 /* sign or seal the packet */
918 switch (c->security_state.auth_info->auth_level) {
919 case DCERPC_AUTH_LEVEL_PRIVACY:
920 status = gensec_seal_packet(c->security_state.generic_state,
921 mem_ctx,
922 blob->data + hdr_size,
923 payload_length,
924 blob->data,
925 blob->length,
926 &creds2);
927 if (!NT_STATUS_IS_OK(status)) {
928 return status;
930 break;
932 case DCERPC_AUTH_LEVEL_INTEGRITY:
933 status = gensec_sign_packet(c->security_state.generic_state,
934 mem_ctx,
935 blob->data + hdr_size,
936 payload_length,
937 blob->data,
938 blob->length,
939 &creds2);
940 if (!NT_STATUS_IS_OK(status)) {
941 return status;
943 break;
945 default:
946 status = NT_STATUS_INVALID_LEVEL;
947 break;
950 if (creds2.length != sig_size) {
951 /* this means the sig_size estimate for the signature
952 was incorrect. We have to correct the packet
953 sizes. That means we could go over the max fragment
954 length */
955 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
956 (unsigned) creds2.length,
957 (unsigned) sig_size,
958 (unsigned) c->security_state.auth_info->auth_pad_length,
959 (unsigned) pkt->u.request.stub_and_verifier.length));
960 dcerpc_set_frag_length(blob, blob->length + creds2.length);
961 dcerpc_set_auth_length(blob, creds2.length);
964 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
965 return NT_STATUS_NO_MEMORY;
968 return NT_STATUS_OK;
973 fill in the fixed values in a dcerpc header
975 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
977 pkt->rpc_vers = 5;
978 pkt->rpc_vers_minor = 0;
979 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
980 pkt->drep[0] = 0;
981 } else {
982 pkt->drep[0] = DCERPC_DREP_LE;
984 pkt->drep[1] = 0;
985 pkt->drep[2] = 0;
986 pkt->drep[3] = 0;
990 map a bind nak reason to a NTSTATUS
992 static NTSTATUS dcerpc_map_nak_reason(enum dcerpc_bind_nak_reason reason)
994 switch (reason) {
995 case DCERPC_BIND_NAK_REASON_PROTOCOL_VERSION_NOT_SUPPORTED:
996 return NT_STATUS_REVISION_MISMATCH;
997 case DCERPC_BIND_NAK_REASON_INVALID_AUTH_TYPE:
998 return NT_STATUS_INVALID_PARAMETER;
999 default:
1000 break;
1002 return NT_STATUS_UNSUCCESSFUL;
1005 static NTSTATUS dcerpc_map_ack_reason(const struct dcerpc_ack_ctx *ack)
1007 if (ack == NULL) {
1008 return NT_STATUS_RPC_PROTOCOL_ERROR;
1011 switch (ack->result) {
1012 case DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK:
1014 * We have not asked for this...
1016 return NT_STATUS_RPC_PROTOCOL_ERROR;
1017 default:
1018 break;
1021 switch (ack->reason.value) {
1022 case DCERPC_BIND_ACK_REASON_ABSTRACT_SYNTAX_NOT_SUPPORTED:
1023 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1024 case DCERPC_BIND_ACK_REASON_TRANSFER_SYNTAXES_NOT_SUPPORTED:
1025 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
1026 default:
1027 break;
1029 return NT_STATUS_UNSUCCESSFUL;
1033 remove requests from the pending or queued queues
1035 static int dcerpc_req_dequeue(struct rpc_request *req)
1037 switch (req->state) {
1038 case RPC_REQUEST_QUEUED:
1039 DLIST_REMOVE(req->p->conn->request_queue, req);
1040 break;
1041 case RPC_REQUEST_PENDING:
1042 DLIST_REMOVE(req->p->conn->pending, req);
1043 break;
1044 case RPC_REQUEST_DONE:
1045 break;
1047 return 0;
1052 mark the dcerpc connection dead. All outstanding requests get an error
1054 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
1056 if (conn->dead) return;
1058 conn->dead = true;
1060 TALLOC_FREE(conn->io_trigger);
1061 conn->io_trigger_pending = false;
1063 dcerpc_shutdown_pipe(conn, status);
1065 /* all pending requests get the error */
1066 while (conn->pending) {
1067 struct rpc_request *req = conn->pending;
1068 dcerpc_req_dequeue(req);
1069 req->state = RPC_REQUEST_DONE;
1070 req->status = status;
1071 if (req->async.callback) {
1072 req->async.callback(req);
1076 /* all requests, which are not shipped */
1077 while (conn->request_queue) {
1078 struct rpc_request *req = conn->request_queue;
1079 dcerpc_req_dequeue(req);
1080 req->state = RPC_REQUEST_DONE;
1081 req->status = status;
1082 if (req->async.callback) {
1083 req->async.callback(req);
1087 talloc_set_destructor(conn, NULL);
1088 if (conn->free_skipped) {
1089 talloc_free(conn);
1094 forward declarations of the recv_data handlers for the types of
1095 packets we need to handle
1097 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1098 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1101 receive a dcerpc reply from the transport. Here we work out what
1102 type of reply it is (normal request, bind or alter context) and
1103 dispatch to the appropriate handler
1105 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1107 struct ncacn_packet pkt;
1109 if (conn->dead) {
1110 return;
1113 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1114 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1117 /* the transport may be telling us of a severe error, such as
1118 a dropped socket */
1119 if (!NT_STATUS_IS_OK(status)) {
1120 data_blob_free(blob);
1121 dcerpc_connection_dead(conn, status);
1122 return;
1125 /* parse the basic packet to work out what type of response this is */
1126 status = ncacn_pull(conn, blob, blob->data, &pkt);
1127 if (!NT_STATUS_IS_OK(status)) {
1128 data_blob_free(blob);
1129 dcerpc_connection_dead(conn, status);
1130 return;
1133 dcerpc_request_recv_data(conn, blob, &pkt);
1137 handle timeouts of individual dcerpc requests
1139 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1140 struct timeval t, void *private_data)
1142 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1144 if (req->ignore_timeout) {
1145 dcerpc_req_dequeue(req);
1146 req->state = RPC_REQUEST_DONE;
1147 req->status = NT_STATUS_IO_TIMEOUT;
1148 if (req->async.callback) {
1149 req->async.callback(req);
1151 return;
1154 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1157 struct dcerpc_bind_state {
1158 struct tevent_context *ev;
1159 struct dcerpc_pipe *p;
1162 static void dcerpc_bind_fail_handler(struct rpc_request *subreq);
1163 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1164 DATA_BLOB *raw_packet,
1165 struct ncacn_packet *pkt);
1167 struct tevent_req *dcerpc_bind_send(TALLOC_CTX *mem_ctx,
1168 struct tevent_context *ev,
1169 struct dcerpc_pipe *p,
1170 const struct ndr_syntax_id *syntax,
1171 const struct ndr_syntax_id *transfer_syntax)
1173 struct tevent_req *req;
1174 struct dcerpc_bind_state *state;
1175 struct ncacn_packet pkt;
1176 DATA_BLOB blob;
1177 NTSTATUS status;
1178 struct rpc_request *subreq;
1179 uint32_t flags;
1181 req = tevent_req_create(mem_ctx, &state,
1182 struct dcerpc_bind_state);
1183 if (req == NULL) {
1184 return NULL;
1187 state->ev = ev;
1188 state->p = p;
1190 p->syntax = *syntax;
1191 p->transfer_syntax = *transfer_syntax;
1193 flags = dcerpc_binding_get_flags(p->binding);
1195 init_ncacn_hdr(p->conn, &pkt);
1197 pkt.ptype = DCERPC_PKT_BIND;
1198 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1199 pkt.call_id = p->conn->call_id;
1200 pkt.auth_length = 0;
1202 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1203 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1206 if (p->conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) {
1207 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1210 pkt.u.bind.max_xmit_frag = p->conn->srv_max_xmit_frag;
1211 pkt.u.bind.max_recv_frag = p->conn->srv_max_recv_frag;
1212 pkt.u.bind.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
1213 pkt.u.bind.num_contexts = 1;
1214 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1215 if (tevent_req_nomem(pkt.u.bind.ctx_list, req)) {
1216 return tevent_req_post(req, ev);
1218 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1219 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1220 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1221 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1222 pkt.u.bind.auth_info = data_blob(NULL, 0);
1224 /* construct the NDR form of the packet */
1225 status = ncacn_push_auth(&blob, state, &pkt,
1226 p->conn->security_state.auth_info);
1227 if (tevent_req_nterror(req, status)) {
1228 return tevent_req_post(req, ev);
1232 * we allocate a dcerpc_request so we can be in the same
1233 * request queue as normal requests
1235 subreq = talloc_zero(state, struct rpc_request);
1236 if (tevent_req_nomem(subreq, req)) {
1237 return tevent_req_post(req, ev);
1240 subreq->state = RPC_REQUEST_PENDING;
1241 subreq->call_id = pkt.call_id;
1242 subreq->async.private_data = req;
1243 subreq->async.callback = dcerpc_bind_fail_handler;
1244 subreq->p = p;
1245 subreq->recv_handler = dcerpc_bind_recv_handler;
1246 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
1247 talloc_set_destructor(subreq, dcerpc_req_dequeue);
1249 status = dcerpc_send_request(p->conn, &blob, true);
1250 if (tevent_req_nterror(req, status)) {
1251 return tevent_req_post(req, ev);
1254 tevent_add_timer(ev, subreq,
1255 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1256 dcerpc_timeout_handler, subreq);
1258 return req;
1261 static void dcerpc_bind_fail_handler(struct rpc_request *subreq)
1263 struct tevent_req *req =
1264 talloc_get_type_abort(subreq->async.private_data,
1265 struct tevent_req);
1266 struct dcerpc_bind_state *state =
1267 tevent_req_data(req,
1268 struct dcerpc_bind_state);
1269 NTSTATUS status = subreq->status;
1271 TALLOC_FREE(subreq);
1274 * We trigger the callback in the next event run
1275 * because the code in this file might trigger
1276 * multiple request callbacks from within a single
1277 * while loop.
1279 * In order to avoid segfaults from within
1280 * dcerpc_connection_dead() we call
1281 * tevent_req_defer_callback().
1283 tevent_req_defer_callback(req, state->ev);
1285 tevent_req_nterror(req, status);
1288 static void dcerpc_bind_recv_handler(struct rpc_request *subreq,
1289 DATA_BLOB *raw_packet,
1290 struct ncacn_packet *pkt)
1292 struct tevent_req *req =
1293 talloc_get_type_abort(subreq->async.private_data,
1294 struct tevent_req);
1295 struct dcerpc_bind_state *state =
1296 tevent_req_data(req,
1297 struct dcerpc_bind_state);
1298 struct dcecli_connection *conn = state->p->conn;
1299 struct dcerpc_binding *b = NULL;
1300 NTSTATUS status;
1301 uint32_t flags;
1304 * Note that pkt is allocated under raw_packet->data,
1305 * while raw_packet->data is a child of subreq.
1307 talloc_steal(state, raw_packet->data);
1308 TALLOC_FREE(subreq);
1311 * We trigger the callback in the next event run
1312 * because the code in this file might trigger
1313 * multiple request callbacks from within a single
1314 * while loop.
1316 * In order to avoid segfaults from within
1317 * dcerpc_connection_dead() we call
1318 * tevent_req_defer_callback().
1320 tevent_req_defer_callback(req, state->ev);
1322 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1323 status = dcerpc_map_nak_reason(pkt->u.bind_nak.reject_reason);
1325 DEBUG(2,("dcerpc: bind_nak reason %d - %s\n",
1326 pkt->u.bind_nak.reject_reason, nt_errstr(status)));
1328 tevent_req_nterror(req, status);
1329 return;
1332 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1333 (pkt->u.bind_ack.num_results == 0) ||
1334 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1335 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1336 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1337 return;
1341 * DCE-RPC 1.1 (c706) specifies
1342 * CONST_MUST_RCV_FRAG_SIZE as 1432
1344 if (pkt->u.bind_ack.max_xmit_frag < 1432) {
1345 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1346 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1347 return;
1349 if (pkt->u.bind_ack.max_recv_frag < 1432) {
1350 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1351 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
1352 return;
1354 conn->srv_max_xmit_frag = MIN(conn->srv_max_xmit_frag,
1355 pkt->u.bind_ack.max_xmit_frag);
1356 conn->srv_max_recv_frag = MIN(conn->srv_max_recv_frag,
1357 pkt->u.bind_ack.max_recv_frag);
1359 flags = dcerpc_binding_get_flags(state->p->binding);
1361 if ((flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1362 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1363 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1366 if ((conn->flags & DCERPC_PROPOSE_HEADER_SIGNING) &&
1367 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1368 conn->flags |= DCERPC_HEADER_SIGNING;
1371 /* the bind_ack might contain a reply set of credentials */
1372 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1373 uint32_t auth_length;
1375 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1376 conn->security_state.auth_info, &auth_length, true);
1377 if (tevent_req_nterror(req, status)) {
1378 return;
1383 * We're the owner of the binding, so we're allowed to modify it.
1385 b = discard_const_p(struct dcerpc_binding, state->p->binding);
1386 status = dcerpc_binding_set_assoc_group_id(b,
1387 pkt->u.bind_ack.assoc_group_id);
1388 if (tevent_req_nterror(req, status)) {
1389 return;
1392 tevent_req_done(req);
1395 NTSTATUS dcerpc_bind_recv(struct tevent_req *req)
1397 return tevent_req_simple_recv_ntstatus(req);
1401 perform a continued bind (and auth3)
1403 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1404 TALLOC_CTX *mem_ctx)
1406 struct ncacn_packet pkt;
1407 NTSTATUS status;
1408 DATA_BLOB blob;
1409 uint32_t flags;
1411 flags = dcerpc_binding_get_flags(p->binding);
1413 init_ncacn_hdr(p->conn, &pkt);
1415 pkt.ptype = DCERPC_PKT_AUTH3;
1416 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1417 pkt.call_id = next_call_id(p->conn);
1418 pkt.auth_length = 0;
1419 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1421 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
1422 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1425 /* construct the NDR form of the packet */
1426 status = ncacn_push_auth(&blob, mem_ctx,
1427 &pkt,
1428 p->conn->security_state.auth_info);
1429 if (!NT_STATUS_IS_OK(status)) {
1430 return status;
1433 /* send it on its way */
1434 status = dcerpc_send_request(p->conn, &blob, false);
1435 if (!NT_STATUS_IS_OK(status)) {
1436 return status;
1439 return NT_STATUS_OK;
1444 process a fragment received from the transport layer during a
1445 request
1447 This function frees the data
1449 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1450 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1452 struct rpc_request *req;
1453 unsigned int length;
1454 NTSTATUS status = NT_STATUS_OK;
1457 if this is an authenticated connection then parse and check
1458 the auth info. We have to do this before finding the
1459 matching packet, as the request structure might have been
1460 removed due to a timeout, but if it has been we still need
1461 to run the auth routines so that we don't get the sign/seal
1462 info out of step with the server
1464 if (c->security_state.auth_info && c->security_state.generic_state &&
1465 pkt->ptype == DCERPC_PKT_RESPONSE) {
1466 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1469 /* find the matching request */
1470 for (req=c->pending;req;req=req->next) {
1471 if (pkt->call_id == req->call_id) break;
1474 #if 0
1475 /* useful for testing certain vendors RPC servers */
1476 if (req == NULL && c->pending && pkt->call_id == 0) {
1477 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1478 req = c->pending;
1480 #endif
1482 if (req == NULL) {
1483 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1484 data_blob_free(raw_packet);
1485 return;
1488 talloc_steal(req, raw_packet->data);
1490 if (req->recv_handler != NULL) {
1491 dcerpc_req_dequeue(req);
1492 req->state = RPC_REQUEST_DONE;
1495 * We have to look at shipping further requests before calling
1496 * the async function, that one might close the pipe
1498 dcerpc_schedule_io_trigger(c);
1500 req->recv_handler(req, raw_packet, pkt);
1501 return;
1504 if (pkt->ptype == DCERPC_PKT_FAULT) {
1505 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1506 req->fault_code = pkt->u.fault.status;
1507 req->status = NT_STATUS_NET_WRITE_FAULT;
1508 goto req_done;
1511 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1512 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1513 (int)pkt->ptype));
1514 req->fault_code = DCERPC_FAULT_OTHER;
1515 req->status = NT_STATUS_NET_WRITE_FAULT;
1516 goto req_done;
1519 /* now check the status from the auth routines, and if it failed then fail
1520 this request accordingly */
1521 if (!NT_STATUS_IS_OK(status)) {
1522 req->status = status;
1523 goto req_done;
1526 length = pkt->u.response.stub_and_verifier.length;
1528 if (length > 0) {
1529 req->payload.data = talloc_realloc(req,
1530 req->payload.data,
1531 uint8_t,
1532 req->payload.length + length);
1533 if (!req->payload.data) {
1534 req->status = NT_STATUS_NO_MEMORY;
1535 goto req_done;
1537 memcpy(req->payload.data+req->payload.length,
1538 pkt->u.response.stub_and_verifier.data, length);
1539 req->payload.length += length;
1542 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1543 data_blob_free(raw_packet);
1544 dcerpc_send_read(c);
1545 return;
1548 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1549 req->flags |= DCERPC_PULL_BIGENDIAN;
1550 } else {
1551 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1554 req_done:
1555 data_blob_free(raw_packet);
1557 /* we've got the full payload */
1558 dcerpc_req_dequeue(req);
1559 req->state = RPC_REQUEST_DONE;
1562 * We have to look at shipping further requests before calling
1563 * the async function, that one might close the pipe
1565 dcerpc_schedule_io_trigger(c);
1567 if (req->async.callback) {
1568 req->async.callback(req);
1573 perform the send side of a async dcerpc request
1575 static struct rpc_request *dcerpc_request_send(TALLOC_CTX *mem_ctx,
1576 struct dcerpc_pipe *p,
1577 const struct GUID *object,
1578 uint16_t opnum,
1579 DATA_BLOB *stub_data)
1581 struct rpc_request *req;
1583 req = talloc_zero(mem_ctx, struct rpc_request);
1584 if (req == NULL) {
1585 return NULL;
1588 req->p = p;
1589 req->call_id = next_call_id(p->conn);
1590 req->state = RPC_REQUEST_QUEUED;
1592 if (object != NULL) {
1593 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1594 if (req->object == NULL) {
1595 talloc_free(req);
1596 return NULL;
1600 req->opnum = opnum;
1601 req->request_data.length = stub_data->length;
1602 req->request_data.data = stub_data->data;
1604 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1605 talloc_set_destructor(req, dcerpc_req_dequeue);
1607 dcerpc_schedule_io_trigger(p->conn);
1609 if (p->request_timeout) {
1610 tevent_add_timer(p->conn->event_ctx, req,
1611 timeval_current_ofs(p->request_timeout, 0),
1612 dcerpc_timeout_handler, req);
1615 return req;
1619 Send a request using the transport
1622 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1624 struct rpc_request *req;
1625 struct dcerpc_pipe *p;
1626 DATA_BLOB *stub_data;
1627 struct ncacn_packet pkt;
1628 DATA_BLOB blob;
1629 uint32_t remaining, chunk_size;
1630 bool first_packet = true;
1631 size_t sig_size = 0;
1632 bool need_async = false;
1633 bool can_async = true;
1635 req = c->request_queue;
1636 if (req == NULL) {
1637 return;
1640 p = req->p;
1641 stub_data = &req->request_data;
1643 if (c->pending) {
1644 need_async = true;
1647 if (c->security_state.auth_info &&
1648 c->security_state.generic_state)
1650 struct gensec_security *gensec = c->security_state.generic_state;
1652 switch (c->security_state.auth_info->auth_level) {
1653 case DCERPC_AUTH_LEVEL_PRIVACY:
1654 case DCERPC_AUTH_LEVEL_INTEGRITY:
1655 can_async = gensec_have_feature(gensec,
1656 GENSEC_FEATURE_ASYNC_REPLIES);
1657 break;
1658 case DCERPC_AUTH_LEVEL_CONNECT:
1659 case DCERPC_AUTH_LEVEL_NONE:
1660 can_async = true;
1661 break;
1662 default:
1663 can_async = false;
1664 break;
1668 if (need_async && !can_async) {
1669 req->wait_for_sync = true;
1670 return;
1673 DLIST_REMOVE(c->request_queue, req);
1674 DLIST_ADD(c->pending, req);
1675 req->state = RPC_REQUEST_PENDING;
1677 init_ncacn_hdr(p->conn, &pkt);
1679 remaining = stub_data->length;
1681 /* we can write a full max_recv_frag size, minus the dcerpc
1682 request header size */
1683 chunk_size = p->conn->srv_max_recv_frag;
1684 chunk_size -= DCERPC_REQUEST_LENGTH;
1685 if (c->security_state.auth_info &&
1686 c->security_state.generic_state) {
1687 size_t max_payload = chunk_size;
1689 max_payload -= DCERPC_AUTH_TRAILER_LENGTH;
1690 max_payload -= (max_payload % DCERPC_AUTH_PAD_ALIGNMENT);
1692 sig_size = gensec_sig_size(c->security_state.generic_state,
1693 max_payload);
1694 if (sig_size) {
1695 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1696 chunk_size -= sig_size;
1699 chunk_size -= (chunk_size % DCERPC_AUTH_PAD_ALIGNMENT);
1701 pkt.ptype = DCERPC_PKT_REQUEST;
1702 pkt.call_id = req->call_id;
1703 pkt.auth_length = 0;
1704 pkt.pfc_flags = 0;
1705 pkt.u.request.context_id = p->context_id;
1706 pkt.u.request.opnum = req->opnum;
1708 if (req->object) {
1709 pkt.u.request.object.object = *req->object;
1710 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1711 chunk_size -= ndr_size_GUID(req->object,0);
1714 /* we send a series of pdus without waiting for a reply */
1715 while (remaining > 0 || first_packet) {
1716 uint32_t chunk = MIN(chunk_size, remaining);
1717 bool last_frag = false;
1718 bool do_trans = false;
1720 first_packet = false;
1721 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1723 if (remaining == stub_data->length) {
1724 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1726 if (chunk == remaining) {
1727 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1728 last_frag = true;
1731 pkt.u.request.alloc_hint = remaining;
1732 pkt.u.request.stub_and_verifier.data = stub_data->data +
1733 (stub_data->length - remaining);
1734 pkt.u.request.stub_and_verifier.length = chunk;
1736 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1737 if (!NT_STATUS_IS_OK(req->status)) {
1738 req->state = RPC_REQUEST_DONE;
1739 DLIST_REMOVE(p->conn->pending, req);
1740 return;
1743 if (last_frag && !need_async) {
1744 do_trans = true;
1747 req->status = dcerpc_send_request(p->conn, &blob, do_trans);
1748 if (!NT_STATUS_IS_OK(req->status)) {
1749 req->state = RPC_REQUEST_DONE;
1750 DLIST_REMOVE(p->conn->pending, req);
1751 return;
1754 if (last_frag && !do_trans) {
1755 req->status = dcerpc_send_read(p->conn);
1756 if (!NT_STATUS_IS_OK(req->status)) {
1757 req->state = RPC_REQUEST_DONE;
1758 DLIST_REMOVE(p->conn->pending, req);
1759 return;
1763 remaining -= chunk;
1767 static void dcerpc_io_trigger(struct tevent_context *ctx,
1768 struct tevent_immediate *im,
1769 void *private_data)
1771 struct dcecli_connection *c =
1772 talloc_get_type_abort(private_data,
1773 struct dcecli_connection);
1775 c->io_trigger_pending = false;
1777 dcerpc_schedule_io_trigger(c);
1779 dcerpc_ship_next_request(c);
1782 static void dcerpc_schedule_io_trigger(struct dcecli_connection *c)
1784 if (c->dead) {
1785 return;
1788 if (c->request_queue == NULL) {
1789 return;
1792 if (c->request_queue->wait_for_sync && c->pending) {
1793 return;
1796 if (c->io_trigger_pending) {
1797 return;
1800 c->io_trigger_pending = true;
1802 tevent_schedule_immediate(c->io_trigger,
1803 c->event_ctx,
1804 dcerpc_io_trigger,
1809 perform the receive side of a async dcerpc request
1811 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1812 TALLOC_CTX *mem_ctx,
1813 DATA_BLOB *stub_data)
1815 NTSTATUS status;
1817 while (req->state != RPC_REQUEST_DONE) {
1818 struct tevent_context *ctx = req->p->conn->event_ctx;
1819 if (tevent_loop_once(ctx) != 0) {
1820 return NT_STATUS_CONNECTION_DISCONNECTED;
1823 *stub_data = req->payload;
1824 status = req->status;
1825 if (stub_data->data) {
1826 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1828 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1829 req->p->last_fault_code = req->fault_code;
1831 talloc_unlink(talloc_parent(req), req);
1832 return status;
1836 this is a paranoid NDR validator. For every packet we push onto the wire
1837 we pull it back again, then push it again. Then we compare the raw NDR data
1838 for that to the NDR we initially generated. If they don't match then we know
1839 we must have a bug in either the pull or push side of our code
1841 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1842 TALLOC_CTX *mem_ctx,
1843 DATA_BLOB blob,
1844 size_t struct_size,
1845 ndr_push_flags_fn_t ndr_push,
1846 ndr_pull_flags_fn_t ndr_pull)
1848 void *st;
1849 struct ndr_pull *pull;
1850 struct ndr_push *push;
1851 DATA_BLOB blob2;
1852 enum ndr_err_code ndr_err;
1854 st = talloc_size(mem_ctx, struct_size);
1855 if (!st) {
1856 return NT_STATUS_NO_MEMORY;
1859 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1860 if (!pull) {
1861 return NT_STATUS_NO_MEMORY;
1863 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1865 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1866 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1869 if (c->flags & DCERPC_NDR64) {
1870 pull->flags |= LIBNDR_FLAG_NDR64;
1873 ndr_err = ndr_pull(pull, NDR_IN, st);
1874 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1875 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1876 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1877 "failed input validation pull - %s",
1878 nt_errstr(status));
1879 return ndr_map_error2ntstatus(ndr_err);
1882 push = ndr_push_init_ctx(mem_ctx);
1883 if (!push) {
1884 return NT_STATUS_NO_MEMORY;
1887 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1888 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1891 if (c->flags & DCERPC_NDR64) {
1892 push->flags |= LIBNDR_FLAG_NDR64;
1895 ndr_err = ndr_push(push, NDR_IN, st);
1896 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1897 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1898 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1899 "failed input validation push - %s",
1900 nt_errstr(status));
1901 return ndr_map_error2ntstatus(ndr_err);
1904 blob2 = ndr_push_blob(push);
1906 if (data_blob_cmp(&blob, &blob2) != 0) {
1907 DEBUG(3,("original:\n"));
1908 dump_data(3, blob.data, blob.length);
1909 DEBUG(3,("secondary:\n"));
1910 dump_data(3, blob2.data, blob2.length);
1911 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1912 "failed input validation blobs doesn't match");
1913 return ndr_map_error2ntstatus(ndr_err);
1916 return NT_STATUS_OK;
1920 this is a paranoid NDR input validator. For every packet we pull
1921 from the wire we push it back again then pull and push it
1922 again. Then we compare the raw NDR data for that to the NDR we
1923 initially generated. If they don't match then we know we must have a
1924 bug in either the pull or push side of our code
1926 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1927 struct ndr_pull *pull_in,
1928 void *struct_ptr,
1929 size_t struct_size,
1930 ndr_push_flags_fn_t ndr_push,
1931 ndr_pull_flags_fn_t ndr_pull,
1932 ndr_print_function_t ndr_print)
1934 void *st;
1935 struct ndr_pull *pull;
1936 struct ndr_push *push;
1937 DATA_BLOB blob, blob2;
1938 TALLOC_CTX *mem_ctx = pull_in;
1939 char *s1, *s2;
1940 enum ndr_err_code ndr_err;
1942 st = talloc_size(mem_ctx, struct_size);
1943 if (!st) {
1944 return NT_STATUS_NO_MEMORY;
1946 memcpy(st, struct_ptr, struct_size);
1948 push = ndr_push_init_ctx(mem_ctx);
1949 if (!push) {
1950 return NT_STATUS_NO_MEMORY;
1953 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1954 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1955 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1956 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1957 "failed output validation push - %s",
1958 nt_errstr(status));
1959 return ndr_map_error2ntstatus(ndr_err);
1962 blob = ndr_push_blob(push);
1964 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1965 if (!pull) {
1966 return NT_STATUS_NO_MEMORY;
1969 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1970 ndr_err = ndr_pull(pull, NDR_OUT, st);
1971 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1972 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1973 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1974 "failed output validation pull - %s",
1975 nt_errstr(status));
1976 return ndr_map_error2ntstatus(ndr_err);
1979 push = ndr_push_init_ctx(mem_ctx);
1980 if (!push) {
1981 return NT_STATUS_NO_MEMORY;
1984 ndr_err = ndr_push(push, NDR_OUT, st);
1985 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1986 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1987 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1988 "failed output validation push2 - %s",
1989 nt_errstr(status));
1990 return ndr_map_error2ntstatus(ndr_err);
1993 blob2 = ndr_push_blob(push);
1995 if (data_blob_cmp(&blob, &blob2) != 0) {
1996 DEBUG(3,("original:\n"));
1997 dump_data(3, blob.data, blob.length);
1998 DEBUG(3,("secondary:\n"));
1999 dump_data(3, blob2.data, blob2.length);
2000 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2001 "failed output validation blobs doesn't match");
2002 return ndr_map_error2ntstatus(ndr_err);
2005 /* this checks the printed forms of the two structures, which effectively
2006 tests all of the value() attributes */
2007 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2008 NDR_OUT, struct_ptr);
2009 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
2010 NDR_OUT, st);
2011 if (strcmp(s1, s2) != 0) {
2012 #if 1
2013 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
2014 #else
2015 /* this is sometimes useful */
2016 printf("VALIDATE ERROR\n");
2017 file_save("wire.dat", s1, strlen(s1));
2018 file_save("gen.dat", s2, strlen(s2));
2019 system("diff -u wire.dat gen.dat");
2020 #endif
2021 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
2022 "failed output validation strings doesn't match");
2023 return ndr_map_error2ntstatus(ndr_err);
2026 return NT_STATUS_OK;
2030 a useful function for retrieving the server name we connected to
2032 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
2034 return p->conn ? p->conn->server_name : NULL;
2039 get the dcerpc auth_level for a open connection
2041 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
2043 uint8_t auth_level;
2045 if (c->flags & DCERPC_SEAL) {
2046 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
2047 } else if (c->flags & DCERPC_SIGN) {
2048 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
2049 } else if (c->flags & DCERPC_CONNECT) {
2050 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
2051 } else {
2052 auth_level = DCERPC_AUTH_LEVEL_NONE;
2054 return auth_level;
2057 struct dcerpc_alter_context_state {
2058 struct tevent_context *ev;
2059 struct dcerpc_pipe *p;
2062 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq);
2063 static void dcerpc_alter_context_recv_handler(struct rpc_request *req,
2064 DATA_BLOB *raw_packet,
2065 struct ncacn_packet *pkt);
2067 struct tevent_req *dcerpc_alter_context_send(TALLOC_CTX *mem_ctx,
2068 struct tevent_context *ev,
2069 struct dcerpc_pipe *p,
2070 const struct ndr_syntax_id *syntax,
2071 const struct ndr_syntax_id *transfer_syntax)
2073 struct tevent_req *req;
2074 struct dcerpc_alter_context_state *state;
2075 struct ncacn_packet pkt;
2076 DATA_BLOB blob;
2077 NTSTATUS status;
2078 struct rpc_request *subreq;
2079 uint32_t flags;
2081 req = tevent_req_create(mem_ctx, &state,
2082 struct dcerpc_alter_context_state);
2083 if (req == NULL) {
2084 return NULL;
2087 state->ev = ev;
2088 state->p = p;
2090 p->syntax = *syntax;
2091 p->transfer_syntax = *transfer_syntax;
2093 flags = dcerpc_binding_get_flags(p->binding);
2095 init_ncacn_hdr(p->conn, &pkt);
2097 pkt.ptype = DCERPC_PKT_ALTER;
2098 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2099 pkt.call_id = p->conn->call_id;
2100 pkt.auth_length = 0;
2102 if (flags & DCERPC_CONCURRENT_MULTIPLEX) {
2103 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2106 pkt.u.alter.max_xmit_frag = p->conn->srv_max_xmit_frag;
2107 pkt.u.alter.max_recv_frag = p->conn->srv_max_recv_frag;
2108 pkt.u.alter.assoc_group_id = dcerpc_binding_get_assoc_group_id(p->binding);
2109 pkt.u.alter.num_contexts = 1;
2110 pkt.u.alter.ctx_list = talloc_array(state, struct dcerpc_ctx_list, 1);
2111 if (tevent_req_nomem(pkt.u.alter.ctx_list, req)) {
2112 return tevent_req_post(req, ev);
2114 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2115 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2116 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2117 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2118 pkt.u.alter.auth_info = data_blob(NULL, 0);
2120 /* construct the NDR form of the packet */
2121 status = ncacn_push_auth(&blob, state, &pkt,
2122 p->conn->security_state.auth_info);
2123 if (tevent_req_nterror(req, status)) {
2124 return tevent_req_post(req, ev);
2128 * we allocate a dcerpc_request so we can be in the same
2129 * request queue as normal requests
2131 subreq = talloc_zero(state, struct rpc_request);
2132 if (tevent_req_nomem(subreq, req)) {
2133 return tevent_req_post(req, ev);
2136 subreq->state = RPC_REQUEST_PENDING;
2137 subreq->call_id = pkt.call_id;
2138 subreq->async.private_data = req;
2139 subreq->async.callback = dcerpc_alter_context_fail_handler;
2140 subreq->p = p;
2141 subreq->recv_handler = dcerpc_alter_context_recv_handler;
2142 DLIST_ADD_END(p->conn->pending, subreq, struct rpc_request *);
2143 talloc_set_destructor(subreq, dcerpc_req_dequeue);
2145 status = dcerpc_send_request(p->conn, &blob, true);
2146 if (tevent_req_nterror(req, status)) {
2147 return tevent_req_post(req, ev);
2150 tevent_add_timer(ev, subreq,
2151 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2152 dcerpc_timeout_handler, subreq);
2154 return req;
2157 static void dcerpc_alter_context_fail_handler(struct rpc_request *subreq)
2159 struct tevent_req *req =
2160 talloc_get_type_abort(subreq->async.private_data,
2161 struct tevent_req);
2162 struct dcerpc_alter_context_state *state =
2163 tevent_req_data(req,
2164 struct dcerpc_alter_context_state);
2165 NTSTATUS status = subreq->status;
2167 TALLOC_FREE(subreq);
2170 * We trigger the callback in the next event run
2171 * because the code in this file might trigger
2172 * multiple request callbacks from within a single
2173 * while loop.
2175 * In order to avoid segfaults from within
2176 * dcerpc_connection_dead() we call
2177 * tevent_req_defer_callback().
2179 tevent_req_defer_callback(req, state->ev);
2181 tevent_req_nterror(req, status);
2184 static void dcerpc_alter_context_recv_handler(struct rpc_request *subreq,
2185 DATA_BLOB *raw_packet,
2186 struct ncacn_packet *pkt)
2188 struct tevent_req *req =
2189 talloc_get_type_abort(subreq->async.private_data,
2190 struct tevent_req);
2191 struct dcerpc_alter_context_state *state =
2192 tevent_req_data(req,
2193 struct dcerpc_alter_context_state);
2194 struct dcecli_connection *conn = state->p->conn;
2195 NTSTATUS status;
2198 * Note that pkt is allocated under raw_packet->data,
2199 * while raw_packet->data is a child of subreq.
2201 talloc_steal(state, raw_packet->data);
2202 TALLOC_FREE(subreq);
2205 * We trigger the callback in the next event run
2206 * because the code in this file might trigger
2207 * multiple request callbacks from within a single
2208 * while loop.
2210 * In order to avoid segfaults from within
2211 * dcerpc_connection_dead() we call
2212 * tevent_req_defer_callback().
2214 tevent_req_defer_callback(req, state->ev);
2216 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
2217 pkt->u.alter_resp.num_results == 1 &&
2218 pkt->u.alter_resp.ctx_list[0].result != 0) {
2219 status = dcerpc_map_ack_reason(&pkt->u.alter_resp.ctx_list[0]);
2220 DEBUG(2,("dcerpc: alter_resp failed - reason %d - %s\n",
2221 pkt->u.alter_resp.ctx_list[0].reason.value,
2222 nt_errstr(status)));
2223 tevent_req_nterror(req, status);
2224 return;
2227 if (pkt->ptype == DCERPC_PKT_FAULT) {
2228 DEBUG(5,("dcerpc: alter_resp - rpc fault: %s\n",
2229 dcerpc_errstr(state, pkt->u.fault.status)));
2230 if (pkt->u.fault.status == DCERPC_FAULT_ACCESS_DENIED) {
2231 state->p->last_fault_code = pkt->u.fault.status;
2232 tevent_req_nterror(req, NT_STATUS_LOGON_FAILURE);
2233 } else {
2234 state->p->last_fault_code = pkt->u.fault.status;
2235 status = dcerpc_fault_to_nt_status(pkt->u.fault.status);
2236 tevent_req_nterror(req, status);
2238 return;
2241 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2242 pkt->u.alter_resp.num_results == 0 ||
2243 pkt->u.alter_resp.ctx_list[0].result != 0) {
2244 state->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2245 tevent_req_nterror(req, NT_STATUS_NET_WRITE_FAULT);
2246 return;
2249 /* the alter_resp might contain a reply set of credentials */
2250 if (conn->security_state.auth_info &&
2251 pkt->u.alter_resp.auth_info.length) {
2252 uint32_t auth_length;
2254 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2255 conn->security_state.auth_info, &auth_length, true);
2256 if (tevent_req_nterror(req, status)) {
2257 return;
2261 tevent_req_done(req);
2264 NTSTATUS dcerpc_alter_context_recv(struct tevent_req *req)
2266 return tevent_req_simple_recv_ntstatus(req);
2270 send a dcerpc alter_context request
2272 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2273 TALLOC_CTX *mem_ctx,
2274 const struct ndr_syntax_id *syntax,
2275 const struct ndr_syntax_id *transfer_syntax)
2277 struct tevent_req *subreq;
2278 struct tevent_context *ev = p->conn->event_ctx;
2279 bool ok;
2281 /* TODO: create a new event context here */
2283 subreq = dcerpc_alter_context_send(mem_ctx, ev,
2284 p, syntax, transfer_syntax);
2285 if (subreq == NULL) {
2286 return NT_STATUS_NO_MEMORY;
2289 ok = tevent_req_poll(subreq, ev);
2290 if (!ok) {
2291 NTSTATUS status;
2292 status = map_nt_error_from_unix_common(errno);
2293 return status;
2296 return dcerpc_alter_context_recv(subreq);
2299 static void dcerpc_transport_dead(struct dcecli_connection *c, NTSTATUS status)
2301 if (c->transport.stream == NULL) {
2302 return;
2305 tevent_queue_stop(c->transport.write_queue);
2306 TALLOC_FREE(c->transport.read_subreq);
2307 TALLOC_FREE(c->transport.stream);
2309 if (NT_STATUS_EQUAL(NT_STATUS_UNSUCCESSFUL, status)) {
2310 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2313 if (NT_STATUS_EQUAL(NT_STATUS_OK, status)) {
2314 status = NT_STATUS_END_OF_FILE;
2317 dcerpc_recv_data(c, NULL, status);
2322 shutdown SMB pipe connection
2324 struct dcerpc_shutdown_pipe_state {
2325 struct dcecli_connection *c;
2326 NTSTATUS status;
2329 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq);
2331 static NTSTATUS dcerpc_shutdown_pipe(struct dcecli_connection *c, NTSTATUS status)
2333 struct dcerpc_shutdown_pipe_state *state;
2334 struct tevent_req *subreq;
2336 if (c->transport.stream == NULL) {
2337 return NT_STATUS_OK;
2340 state = talloc_zero(c, struct dcerpc_shutdown_pipe_state);
2341 if (state == NULL) {
2342 return NT_STATUS_NO_MEMORY;
2344 state->c = c;
2345 state->status = status;
2347 subreq = tstream_disconnect_send(state, c->event_ctx, c->transport.stream);
2348 if (subreq == NULL) {
2349 return NT_STATUS_NO_MEMORY;
2351 tevent_req_set_callback(subreq, dcerpc_shutdown_pipe_done, state);
2353 return status;
2356 static void dcerpc_shutdown_pipe_done(struct tevent_req *subreq)
2358 struct dcerpc_shutdown_pipe_state *state =
2359 tevent_req_callback_data(subreq, struct dcerpc_shutdown_pipe_state);
2360 struct dcecli_connection *c = state->c;
2361 NTSTATUS status = state->status;
2362 int error;
2365 * here we ignore the return values...
2367 tstream_disconnect_recv(subreq, &error);
2368 TALLOC_FREE(subreq);
2370 TALLOC_FREE(state);
2372 dcerpc_transport_dead(c, status);
2377 struct dcerpc_send_read_state {
2378 struct dcecli_connection *p;
2381 static int dcerpc_send_read_state_destructor(struct dcerpc_send_read_state *state)
2383 struct dcecli_connection *p = state->p;
2385 p->transport.read_subreq = NULL;
2387 return 0;
2390 static void dcerpc_send_read_done(struct tevent_req *subreq);
2392 static NTSTATUS dcerpc_send_read(struct dcecli_connection *p)
2394 struct dcerpc_send_read_state *state;
2396 if (p->transport.read_subreq != NULL) {
2397 p->transport.pending_reads++;
2398 return NT_STATUS_OK;
2401 state = talloc_zero(p, struct dcerpc_send_read_state);
2402 if (state == NULL) {
2403 return NT_STATUS_NO_MEMORY;
2405 state->p = p;
2407 talloc_set_destructor(state, dcerpc_send_read_state_destructor);
2409 p->transport.read_subreq = dcerpc_read_ncacn_packet_send(state,
2410 p->event_ctx,
2411 p->transport.stream);
2412 if (p->transport.read_subreq == NULL) {
2413 return NT_STATUS_NO_MEMORY;
2415 tevent_req_set_callback(p->transport.read_subreq, dcerpc_send_read_done, state);
2417 return NT_STATUS_OK;
2420 static void dcerpc_send_read_done(struct tevent_req *subreq)
2422 struct dcerpc_send_read_state *state =
2423 tevent_req_callback_data(subreq,
2424 struct dcerpc_send_read_state);
2425 struct dcecli_connection *p = state->p;
2426 NTSTATUS status;
2427 struct ncacn_packet *pkt;
2428 DATA_BLOB blob;
2430 status = dcerpc_read_ncacn_packet_recv(subreq, state,
2431 &pkt, &blob);
2432 TALLOC_FREE(subreq);
2433 if (!NT_STATUS_IS_OK(status)) {
2434 TALLOC_FREE(state);
2435 dcerpc_transport_dead(p, status);
2436 return;
2440 * here we steal into thet connection context,
2441 * but p->transport.recv_data() will steal or free it again
2443 talloc_steal(p, blob.data);
2444 TALLOC_FREE(state);
2446 if (p->transport.pending_reads > 0) {
2447 p->transport.pending_reads--;
2449 status = dcerpc_send_read(p);
2450 if (!NT_STATUS_IS_OK(status)) {
2451 dcerpc_transport_dead(p, status);
2452 return;
2456 dcerpc_recv_data(p, &blob, NT_STATUS_OK);
2459 struct dcerpc_send_request_state {
2460 struct dcecli_connection *p;
2461 DATA_BLOB blob;
2462 struct iovec iov;
2465 static int dcerpc_send_request_state_destructor(struct dcerpc_send_request_state *state)
2467 struct dcecli_connection *p = state->p;
2469 p->transport.read_subreq = NULL;
2471 return 0;
2474 static void dcerpc_send_request_wait_done(struct tevent_req *subreq);
2475 static void dcerpc_send_request_done(struct tevent_req *subreq);
2477 static NTSTATUS dcerpc_send_request(struct dcecli_connection *p, DATA_BLOB *data,
2478 bool trigger_read)
2480 struct dcerpc_send_request_state *state;
2481 struct tevent_req *subreq;
2482 bool use_trans = trigger_read;
2484 if (p->transport.stream == NULL) {
2485 return NT_STATUS_CONNECTION_DISCONNECTED;
2488 state = talloc_zero(p, struct dcerpc_send_request_state);
2489 if (state == NULL) {
2490 return NT_STATUS_NO_MEMORY;
2492 state->p = p;
2494 state->blob = data_blob_talloc(state, data->data, data->length);
2495 if (state->blob.data == NULL) {
2496 TALLOC_FREE(state);
2497 return NT_STATUS_NO_MEMORY;
2499 state->iov.iov_base = (void *)state->blob.data;
2500 state->iov.iov_len = state->blob.length;
2502 if (p->transport.read_subreq != NULL) {
2503 use_trans = false;
2506 if (!tstream_is_smbXcli_np(p->transport.stream)) {
2507 use_trans = false;
2510 if (use_trans) {
2512 * we need to block reads until our write is
2513 * the next in the write queue.
2515 p->transport.read_subreq = tevent_queue_wait_send(state, p->event_ctx,
2516 p->transport.write_queue);
2517 if (p->transport.read_subreq == NULL) {
2518 TALLOC_FREE(state);
2519 return NT_STATUS_NO_MEMORY;
2521 tevent_req_set_callback(p->transport.read_subreq,
2522 dcerpc_send_request_wait_done,
2523 state);
2525 talloc_set_destructor(state, dcerpc_send_request_state_destructor);
2527 trigger_read = false;
2530 subreq = tstream_writev_queue_send(state, p->event_ctx,
2531 p->transport.stream,
2532 p->transport.write_queue,
2533 &state->iov, 1);
2534 if (subreq == NULL) {
2535 TALLOC_FREE(state);
2536 return NT_STATUS_NO_MEMORY;
2538 tevent_req_set_callback(subreq, dcerpc_send_request_done, state);
2540 if (trigger_read) {
2541 dcerpc_send_read(p);
2544 return NT_STATUS_OK;
2547 static void dcerpc_send_request_wait_done(struct tevent_req *subreq)
2549 struct dcerpc_send_request_state *state =
2550 tevent_req_callback_data(subreq,
2551 struct dcerpc_send_request_state);
2552 struct dcecli_connection *p = state->p;
2553 NTSTATUS status;
2554 bool ok;
2556 p->transport.read_subreq = NULL;
2557 talloc_set_destructor(state, NULL);
2559 ok = tevent_queue_wait_recv(subreq);
2560 if (!ok) {
2561 TALLOC_FREE(state);
2562 dcerpc_transport_dead(p, NT_STATUS_NO_MEMORY);
2563 return;
2566 if (tevent_queue_length(p->transport.write_queue) <= 2) {
2567 status = tstream_smbXcli_np_use_trans(p->transport.stream);
2568 if (!NT_STATUS_IS_OK(status)) {
2569 TALLOC_FREE(state);
2570 dcerpc_transport_dead(p, status);
2571 return;
2575 /* we free subreq after tstream_cli_np_use_trans */
2576 TALLOC_FREE(subreq);
2578 dcerpc_send_read(p);
2581 static void dcerpc_send_request_done(struct tevent_req *subreq)
2583 struct dcerpc_send_request_state *state =
2584 tevent_req_callback_data(subreq,
2585 struct dcerpc_send_request_state);
2586 int ret;
2587 int error;
2589 ret = tstream_writev_queue_recv(subreq, &error);
2590 TALLOC_FREE(subreq);
2591 if (ret == -1) {
2592 struct dcecli_connection *p = state->p;
2593 NTSTATUS status = map_nt_error_from_unix_common(error);
2595 TALLOC_FREE(state);
2596 dcerpc_transport_dead(p, status);
2597 return;
2600 TALLOC_FREE(state);