s3:libsmb: smb_bytes_talloc_string() doesn't need a cli_state
[Samba/gebeck_regimport.git] / source4 / librpc / rpc / dcerpc.c
blob110da57c939be489caa657d34d47a704c112ffdb
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 "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.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"
36 enum rpc_request_state {
37 RPC_REQUEST_QUEUED,
38 RPC_REQUEST_PENDING,
39 RPC_REQUEST_DONE
43 handle for an async dcerpc request
45 struct rpc_request {
46 struct rpc_request *next, *prev;
47 struct dcerpc_pipe *p;
48 NTSTATUS status;
49 uint32_t call_id;
50 enum rpc_request_state state;
51 DATA_BLOB payload;
52 uint32_t flags;
53 uint32_t fault_code;
55 /* this is used to distinguish bind and alter_context requests
56 from normal requests */
57 void (*recv_handler)(struct rpc_request *conn,
58 DATA_BLOB *blob, struct ncacn_packet *pkt);
60 const struct GUID *object;
61 uint16_t opnum;
62 DATA_BLOB request_data;
63 bool ignore_timeout;
65 /* use by the ndr level async recv call */
66 struct {
67 const struct ndr_interface_table *table;
68 uint32_t opnum;
69 void *struct_ptr;
70 TALLOC_CTX *mem_ctx;
71 } ndr;
73 struct {
74 void (*callback)(struct rpc_request *);
75 void *private_data;
76 } async;
79 _PUBLIC_ NTSTATUS dcerpc_init(void)
81 return gensec_init();
84 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status);
85 static void dcerpc_ship_next_request(struct dcecli_connection *c);
87 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
88 const struct GUID *object,
89 uint16_t opnum,
90 DATA_BLOB *stub_data);
91 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
92 TALLOC_CTX *mem_ctx,
93 DATA_BLOB *stub_data);
94 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
95 TALLOC_CTX *mem_ctx,
96 DATA_BLOB blob,
97 size_t struct_size,
98 ndr_push_flags_fn_t ndr_push,
99 ndr_pull_flags_fn_t ndr_pull);
100 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
101 struct ndr_pull *pull_in,
102 void *struct_ptr,
103 size_t struct_size,
104 ndr_push_flags_fn_t ndr_push,
105 ndr_pull_flags_fn_t ndr_pull,
106 ndr_print_function_t ndr_print);
108 /* destroy a dcerpc connection */
109 static int dcerpc_connection_destructor(struct dcecli_connection *conn)
111 if (conn->dead) {
112 conn->free_skipped = true;
113 return -1;
115 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
116 return 0;
120 /* initialise a dcerpc connection.
121 the event context is optional
123 static struct dcecli_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
124 struct tevent_context *ev)
126 struct dcecli_connection *c;
128 c = talloc_zero(mem_ctx, struct dcecli_connection);
129 if (!c) {
130 return NULL;
133 c->event_ctx = ev;
135 if (c->event_ctx == NULL) {
136 talloc_free(c);
137 return NULL;
140 c->call_id = 1;
141 c->security_state.auth_info = NULL;
142 c->security_state.session_key = dcerpc_generic_session_key;
143 c->security_state.generic_state = NULL;
144 c->binding_string = NULL;
145 c->flags = 0;
146 c->srv_max_xmit_frag = 0;
147 c->srv_max_recv_frag = 0;
148 c->pending = NULL;
150 talloc_set_destructor(c, dcerpc_connection_destructor);
152 return c;
155 struct dcerpc_bh_state {
156 struct dcerpc_pipe *p;
159 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
161 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
162 struct dcerpc_bh_state);
164 if (!hs->p) {
165 return false;
168 return true;
171 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
172 uint32_t timeout)
174 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
175 struct dcerpc_bh_state);
176 uint32_t old;
178 if (!hs->p) {
179 return DCERPC_REQUEST_TIMEOUT;
182 old = hs->p->request_timeout;
183 hs->p->request_timeout = timeout;
185 return old;
188 struct dcerpc_bh_raw_call_state {
189 struct dcerpc_binding_handle *h;
190 DATA_BLOB in_data;
191 DATA_BLOB out_data;
192 uint32_t out_flags;
195 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
197 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
198 struct tevent_context *ev,
199 struct dcerpc_binding_handle *h,
200 const struct GUID *object,
201 uint32_t opnum,
202 uint32_t in_flags,
203 const uint8_t *in_data,
204 size_t in_length)
206 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
207 struct dcerpc_bh_state);
208 struct tevent_req *req;
209 struct dcerpc_bh_raw_call_state *state;
210 bool ok;
211 struct rpc_request *subreq;
213 req = tevent_req_create(mem_ctx, &state,
214 struct dcerpc_bh_raw_call_state);
215 if (req == NULL) {
216 return NULL;
218 state->h = h;
219 state->in_data.data = discard_const_p(uint8_t, in_data);
220 state->in_data.length = in_length;
222 ok = dcerpc_bh_is_connected(h);
223 if (!ok) {
224 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
225 return tevent_req_post(req, ev);
228 subreq = dcerpc_request_send(hs->p,
229 object,
230 opnum,
231 &state->in_data);
232 if (tevent_req_nomem(subreq, req)) {
233 return tevent_req_post(req, ev);
235 subreq->async.callback = dcerpc_bh_raw_call_done;
236 subreq->async.private_data = req;
238 return req;
241 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
243 struct tevent_req *req =
244 talloc_get_type_abort(subreq->async.private_data,
245 struct tevent_req);
246 struct dcerpc_bh_raw_call_state *state =
247 tevent_req_data(req,
248 struct dcerpc_bh_raw_call_state);
249 NTSTATUS status;
250 uint32_t fault_code;
252 state->out_flags = 0;
253 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
254 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
257 fault_code = subreq->fault_code;
259 status = dcerpc_request_recv(subreq, state, &state->out_data);
260 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
261 status = dcerpc_fault_to_nt_status(fault_code);
263 if (!NT_STATUS_IS_OK(status)) {
264 tevent_req_nterror(req, status);
265 return;
268 tevent_req_done(req);
271 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
272 TALLOC_CTX *mem_ctx,
273 uint8_t **out_data,
274 size_t *out_length,
275 uint32_t *out_flags)
277 struct dcerpc_bh_raw_call_state *state =
278 tevent_req_data(req,
279 struct dcerpc_bh_raw_call_state);
280 NTSTATUS status;
282 if (tevent_req_is_nterror(req, &status)) {
283 tevent_req_received(req);
284 return status;
287 *out_data = talloc_move(mem_ctx, &state->out_data.data);
288 *out_length = state->out_data.length;
289 *out_flags = state->out_flags;
290 tevent_req_received(req);
291 return NT_STATUS_OK;
294 struct dcerpc_bh_disconnect_state {
295 uint8_t _dummy;
298 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
299 struct tevent_context *ev,
300 struct dcerpc_binding_handle *h)
302 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
303 struct dcerpc_bh_state);
304 struct tevent_req *req;
305 struct dcerpc_bh_disconnect_state *state;
306 bool ok;
308 req = tevent_req_create(mem_ctx, &state,
309 struct dcerpc_bh_disconnect_state);
310 if (req == NULL) {
311 return NULL;
314 ok = dcerpc_bh_is_connected(h);
315 if (!ok) {
316 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
317 return tevent_req_post(req, ev);
320 /* TODO: do a real disconnect ... */
321 hs->p = NULL;
323 tevent_req_done(req);
324 return tevent_req_post(req, ev);
327 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
329 NTSTATUS status;
331 if (tevent_req_is_nterror(req, &status)) {
332 tevent_req_received(req);
333 return status;
336 tevent_req_received(req);
337 return NT_STATUS_OK;
340 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
342 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
343 struct dcerpc_bh_state);
345 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
346 return true;
349 return false;
352 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
354 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
355 struct dcerpc_bh_state);
357 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
358 return true;
361 return false;
364 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
366 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
367 struct dcerpc_bh_state);
369 if (hs->p->conn->flags & DCERPC_NDR64) {
370 return true;
373 return false;
376 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
377 int ndr_flags,
378 const void *_struct_ptr,
379 const struct ndr_interface_call *call)
381 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
382 struct dcerpc_bh_state);
383 void *struct_ptr = discard_const(_struct_ptr);
385 if (ndr_flags & NDR_IN) {
386 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
387 ndr_print_function_debug(call->ndr_print,
388 call->name,
389 ndr_flags,
390 struct_ptr);
393 if (ndr_flags & NDR_OUT) {
394 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
395 ndr_print_function_debug(call->ndr_print,
396 call->name,
397 ndr_flags,
398 struct_ptr);
403 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
404 NTSTATUS error,
405 const void *struct_ptr,
406 const struct ndr_interface_call *call)
408 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
409 call->name, nt_errstr(error)));
412 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
413 NTSTATUS error,
414 const DATA_BLOB *blob,
415 const struct ndr_interface_call *call)
417 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
418 struct dcerpc_bh_state);
419 const uint32_t num_examples = 20;
420 uint32_t i;
422 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
423 call->name, nt_errstr(error)));
425 if (hs->p->conn->packet_log_dir == NULL) return;
427 for (i=0;i<num_examples;i++) {
428 char *name=NULL;
429 asprintf(&name, "%s/rpclog/%s-out.%d",
430 hs->p->conn->packet_log_dir,
431 call->name, i);
432 if (name == NULL) {
433 return;
435 if (!file_exist(name)) {
436 if (file_save(name, blob->data, blob->length)) {
437 DEBUG(10,("Logged rpc packet to %s\n", name));
439 free(name);
440 break;
442 free(name);
446 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
447 TALLOC_CTX *mem_ctx,
448 const DATA_BLOB *blob,
449 const struct ndr_interface_call *call)
451 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
452 struct dcerpc_bh_state);
454 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
455 NTSTATUS status;
457 status = dcerpc_ndr_validate_in(hs->p->conn,
458 mem_ctx,
459 *blob,
460 call->struct_size,
461 call->ndr_push,
462 call->ndr_pull);
463 if (!NT_STATUS_IS_OK(status)) {
464 DEBUG(0,("Validation [in] failed for %s - %s\n",
465 call->name, nt_errstr(status)));
466 return status;
470 DEBUG(10,("rpc request data:\n"));
471 dump_data(10, blob->data, blob->length);
473 return NT_STATUS_OK;
476 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
477 struct ndr_pull *pull_in,
478 const void *_struct_ptr,
479 const struct ndr_interface_call *call)
481 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
482 struct dcerpc_bh_state);
483 void *struct_ptr = discard_const(_struct_ptr);
485 DEBUG(10,("rpc reply data:\n"));
486 dump_data(10, pull_in->data, pull_in->data_size);
488 if (pull_in->offset != pull_in->data_size) {
489 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
490 pull_in->data_size - pull_in->offset,
491 pull_in->offset, pull_in->offset,
492 call->name));
493 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
494 but it turns out that early versions of NT
495 (specifically NT3.1) add junk onto the end of rpc
496 packets, so if we want to interoperate at all with
497 those versions then we need to ignore this error */
500 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
501 NTSTATUS status;
503 status = dcerpc_ndr_validate_out(hs->p->conn,
504 pull_in,
505 struct_ptr,
506 call->struct_size,
507 call->ndr_push,
508 call->ndr_pull,
509 call->ndr_print);
510 if (!NT_STATUS_IS_OK(status)) {
511 DEBUG(2,("Validation [out] failed for %s - %s\n",
512 call->name, nt_errstr(status)));
513 return status;
517 return NT_STATUS_OK;
520 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
521 .name = "dcerpc",
522 .is_connected = dcerpc_bh_is_connected,
523 .set_timeout = dcerpc_bh_set_timeout,
524 .raw_call_send = dcerpc_bh_raw_call_send,
525 .raw_call_recv = dcerpc_bh_raw_call_recv,
526 .disconnect_send = dcerpc_bh_disconnect_send,
527 .disconnect_recv = dcerpc_bh_disconnect_recv,
529 .push_bigendian = dcerpc_bh_push_bigendian,
530 .ref_alloc = dcerpc_bh_ref_alloc,
531 .use_ndr64 = dcerpc_bh_use_ndr64,
532 .do_ndr_print = dcerpc_bh_do_ndr_print,
533 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
534 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
535 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
536 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
539 /* initialise a dcerpc pipe. */
540 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
542 struct dcerpc_binding_handle *h;
543 struct dcerpc_bh_state *hs;
545 h = dcerpc_binding_handle_create(p,
546 &dcerpc_bh_ops,
547 NULL,
548 NULL, /* TODO */
549 &hs,
550 struct dcerpc_bh_state,
551 __location__);
552 if (h == NULL) {
553 return NULL;
555 hs->p = p;
557 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
559 return h;
562 /* initialise a dcerpc pipe. */
563 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
565 struct dcerpc_pipe *p;
567 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
568 if (!p) {
569 return NULL;
572 p->conn = dcerpc_connection_init(p, ev);
573 if (p->conn == NULL) {
574 talloc_free(p);
575 return NULL;
578 p->last_fault_code = 0;
579 p->context_id = 0;
580 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
581 p->binding = NULL;
583 ZERO_STRUCT(p->syntax);
584 ZERO_STRUCT(p->transfer_syntax);
586 if (DEBUGLVL(100)) {
587 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
590 p->binding_handle = dcerpc_pipe_binding_handle(p);
591 if (p->binding_handle == NULL) {
592 talloc_free(p);
593 return NULL;
596 return p;
601 choose the next call id to use
603 static uint32_t next_call_id(struct dcecli_connection *c)
605 c->call_id++;
606 if (c->call_id == 0) {
607 c->call_id++;
609 return c->call_id;
613 setup for a ndr pull, also setting up any flags from the binding string
615 static struct ndr_pull *ndr_pull_init_flags(struct dcecli_connection *c,
616 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
618 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
620 if (ndr == NULL) return ndr;
622 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
623 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
626 if (c->flags & DCERPC_NDR_REF_ALLOC) {
627 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
630 if (c->flags & DCERPC_NDR64) {
631 ndr->flags |= LIBNDR_FLAG_NDR64;
634 return ndr;
638 parse a data blob into a ncacn_packet structure. This handles both
639 input and output packets
641 static NTSTATUS ncacn_pull(struct dcecli_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
642 struct ncacn_packet *pkt)
644 struct ndr_pull *ndr;
645 enum ndr_err_code ndr_err;
647 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
648 if (!ndr) {
649 return NT_STATUS_NO_MEMORY;
652 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
653 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
656 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
657 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
658 return ndr_map_error2ntstatus(ndr_err);
661 return NT_STATUS_OK;
665 parse the authentication information on a dcerpc response packet
667 static NTSTATUS ncacn_pull_request_auth(struct dcecli_connection *c, TALLOC_CTX *mem_ctx,
668 DATA_BLOB *raw_packet,
669 struct ncacn_packet *pkt)
671 NTSTATUS status;
672 struct dcerpc_auth auth;
673 uint32_t auth_length;
675 if (!c->security_state.auth_info ||
676 !c->security_state.generic_state) {
677 return NT_STATUS_OK;
680 switch (c->security_state.auth_info->auth_level) {
681 case DCERPC_AUTH_LEVEL_PRIVACY:
682 case DCERPC_AUTH_LEVEL_INTEGRITY:
683 break;
685 case DCERPC_AUTH_LEVEL_CONNECT:
686 if (pkt->auth_length != 0) {
687 break;
689 return NT_STATUS_OK;
690 case DCERPC_AUTH_LEVEL_NONE:
691 if (pkt->auth_length != 0) {
692 return NT_STATUS_INVALID_NETWORK_RESPONSE;
694 return NT_STATUS_OK;
696 default:
697 return NT_STATUS_INVALID_LEVEL;
700 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
701 &pkt->u.response.stub_and_verifier,
702 &auth, &auth_length, false);
703 NT_STATUS_NOT_OK_RETURN(status);
705 pkt->u.response.stub_and_verifier.length -= auth_length;
707 /* check signature or unseal the packet */
708 switch (c->security_state.auth_info->auth_level) {
709 case DCERPC_AUTH_LEVEL_PRIVACY:
710 status = gensec_unseal_packet(c->security_state.generic_state,
711 mem_ctx,
712 raw_packet->data + DCERPC_REQUEST_LENGTH,
713 pkt->u.response.stub_and_verifier.length,
714 raw_packet->data,
715 raw_packet->length - auth.credentials.length,
716 &auth.credentials);
717 memcpy(pkt->u.response.stub_and_verifier.data,
718 raw_packet->data + DCERPC_REQUEST_LENGTH,
719 pkt->u.response.stub_and_verifier.length);
720 break;
722 case DCERPC_AUTH_LEVEL_INTEGRITY:
723 status = gensec_check_packet(c->security_state.generic_state,
724 mem_ctx,
725 pkt->u.response.stub_and_verifier.data,
726 pkt->u.response.stub_and_verifier.length,
727 raw_packet->data,
728 raw_packet->length - auth.credentials.length,
729 &auth.credentials);
730 break;
732 case DCERPC_AUTH_LEVEL_CONNECT:
733 /* for now we ignore possible signatures here */
734 status = NT_STATUS_OK;
735 break;
737 default:
738 status = NT_STATUS_INVALID_LEVEL;
739 break;
742 /* remove the indicated amount of padding */
743 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
744 return NT_STATUS_INFO_LENGTH_MISMATCH;
746 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
748 return status;
753 push a dcerpc request packet into a blob, possibly signing it.
755 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
756 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
757 size_t sig_size,
758 struct ncacn_packet *pkt)
760 NTSTATUS status;
761 struct ndr_push *ndr;
762 DATA_BLOB creds2;
763 size_t payload_length;
764 enum ndr_err_code ndr_err;
765 size_t hdr_size = DCERPC_REQUEST_LENGTH;
767 /* non-signed packets are simpler */
768 if (sig_size == 0) {
769 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
772 switch (c->security_state.auth_info->auth_level) {
773 case DCERPC_AUTH_LEVEL_PRIVACY:
774 case DCERPC_AUTH_LEVEL_INTEGRITY:
775 break;
777 case DCERPC_AUTH_LEVEL_CONNECT:
778 /* TODO: let the gensec mech decide if it wants to generate a signature */
779 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
781 case DCERPC_AUTH_LEVEL_NONE:
782 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
784 default:
785 return NT_STATUS_INVALID_LEVEL;
788 ndr = ndr_push_init_ctx(mem_ctx);
789 if (!ndr) {
790 return NT_STATUS_NO_MEMORY;
793 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
794 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
797 if (c->flags & DCERPC_NDR64) {
798 ndr->flags |= LIBNDR_FLAG_NDR64;
801 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
802 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
803 hdr_size += 16;
806 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
807 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
808 return ndr_map_error2ntstatus(ndr_err);
811 /* pad to 16 byte multiple in the payload portion of the
812 packet. This matches what w2k3 does. Note that we can't use
813 ndr_push_align() as that is relative to the start of the
814 whole packet, whereas w2k8 wants it relative to the start
815 of the stub */
816 c->security_state.auth_info->auth_pad_length =
817 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
818 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
819 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
820 return ndr_map_error2ntstatus(ndr_err);
823 payload_length = pkt->u.request.stub_and_verifier.length +
824 c->security_state.auth_info->auth_pad_length;
826 /* we start without signature, it will appended later */
827 c->security_state.auth_info->credentials = data_blob(NULL,0);
829 /* add the auth verifier */
830 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
831 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
832 return ndr_map_error2ntstatus(ndr_err);
835 /* extract the whole packet as a blob */
836 *blob = ndr_push_blob(ndr);
839 * Setup the frag and auth length in the packet buffer.
840 * This is needed if the GENSEC mech does AEAD signing
841 * of the packet headers. The signature itself will be
842 * appended later.
844 dcerpc_set_frag_length(blob, blob->length + sig_size);
845 dcerpc_set_auth_length(blob, sig_size);
847 /* sign or seal the packet */
848 switch (c->security_state.auth_info->auth_level) {
849 case DCERPC_AUTH_LEVEL_PRIVACY:
850 status = gensec_seal_packet(c->security_state.generic_state,
851 mem_ctx,
852 blob->data + hdr_size,
853 payload_length,
854 blob->data,
855 blob->length,
856 &creds2);
857 if (!NT_STATUS_IS_OK(status)) {
858 return status;
860 break;
862 case DCERPC_AUTH_LEVEL_INTEGRITY:
863 status = gensec_sign_packet(c->security_state.generic_state,
864 mem_ctx,
865 blob->data + hdr_size,
866 payload_length,
867 blob->data,
868 blob->length,
869 &creds2);
870 if (!NT_STATUS_IS_OK(status)) {
871 return status;
873 break;
875 default:
876 status = NT_STATUS_INVALID_LEVEL;
877 break;
880 if (creds2.length != sig_size) {
881 /* this means the sig_size estimate for the signature
882 was incorrect. We have to correct the packet
883 sizes. That means we could go over the max fragment
884 length */
885 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
886 (unsigned) creds2.length,
887 (unsigned) sig_size,
888 (unsigned) c->security_state.auth_info->auth_pad_length,
889 (unsigned) pkt->u.request.stub_and_verifier.length));
890 dcerpc_set_frag_length(blob, blob->length + creds2.length);
891 dcerpc_set_auth_length(blob, creds2.length);
894 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
895 return NT_STATUS_NO_MEMORY;
898 return NT_STATUS_OK;
903 fill in the fixed values in a dcerpc header
905 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
907 pkt->rpc_vers = 5;
908 pkt->rpc_vers_minor = 0;
909 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
910 pkt->drep[0] = 0;
911 } else {
912 pkt->drep[0] = DCERPC_DREP_LE;
914 pkt->drep[1] = 0;
915 pkt->drep[2] = 0;
916 pkt->drep[3] = 0;
920 map a bind nak reason to a NTSTATUS
922 static NTSTATUS dcerpc_map_reason(uint16_t reason)
924 switch (reason) {
925 case DCERPC_BIND_REASON_ASYNTAX:
926 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
927 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
928 return NT_STATUS_INVALID_PARAMETER;
930 return NT_STATUS_UNSUCCESSFUL;
934 a bind or alter context has failed
936 static void dcerpc_composite_fail(struct rpc_request *req)
938 struct composite_context *c = talloc_get_type(req->async.private_data,
939 struct composite_context);
940 composite_error(c, req->status);
944 remove requests from the pending or queued queues
946 static int dcerpc_req_dequeue(struct rpc_request *req)
948 switch (req->state) {
949 case RPC_REQUEST_QUEUED:
950 DLIST_REMOVE(req->p->conn->request_queue, req);
951 break;
952 case RPC_REQUEST_PENDING:
953 DLIST_REMOVE(req->p->conn->pending, req);
954 break;
955 case RPC_REQUEST_DONE:
956 break;
958 return 0;
963 mark the dcerpc connection dead. All outstanding requests get an error
965 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
967 if (conn->dead) return;
969 conn->dead = true;
971 if (conn->transport.shutdown_pipe) {
972 conn->transport.shutdown_pipe(conn, status);
975 /* all pending requests get the error */
976 while (conn->pending) {
977 struct rpc_request *req = conn->pending;
978 dcerpc_req_dequeue(req);
979 req->state = RPC_REQUEST_DONE;
980 req->status = status;
981 if (req->async.callback) {
982 req->async.callback(req);
986 talloc_set_destructor(conn, NULL);
987 if (conn->free_skipped) {
988 talloc_free(conn);
993 forward declarations of the recv_data handlers for the types of
994 packets we need to handle
996 static void dcerpc_request_recv_data(struct dcecli_connection *c,
997 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
1000 receive a dcerpc reply from the transport. Here we work out what
1001 type of reply it is (normal request, bind or alter context) and
1002 dispatch to the appropriate handler
1004 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1006 struct ncacn_packet pkt;
1008 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1009 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1012 /* the transport may be telling us of a severe error, such as
1013 a dropped socket */
1014 if (!NT_STATUS_IS_OK(status)) {
1015 data_blob_free(blob);
1016 dcerpc_connection_dead(conn, status);
1017 return;
1020 /* parse the basic packet to work out what type of response this is */
1021 status = ncacn_pull(conn, blob, blob->data, &pkt);
1022 if (!NT_STATUS_IS_OK(status)) {
1023 data_blob_free(blob);
1024 dcerpc_connection_dead(conn, status);
1027 dcerpc_request_recv_data(conn, blob, &pkt);
1031 Receive a bind reply from the transport
1033 static void dcerpc_bind_recv_handler(struct rpc_request *req,
1034 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1036 struct composite_context *c;
1037 struct dcecli_connection *conn;
1039 c = talloc_get_type(req->async.private_data, struct composite_context);
1041 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1042 DEBUG(2,("dcerpc: bind_nak reason %d\n",
1043 pkt->u.bind_nak.reject_reason));
1044 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
1045 reject_reason));
1046 return;
1049 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1050 (pkt->u.bind_ack.num_results == 0) ||
1051 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1052 req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1053 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1054 return;
1057 conn = req->p->conn;
1059 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1060 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1062 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1063 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1064 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1067 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1068 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1069 conn->flags |= DCERPC_HEADER_SIGNING;
1072 /* the bind_ack might contain a reply set of credentials */
1073 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1074 NTSTATUS status;
1075 uint32_t auth_length;
1076 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1077 conn->security_state.auth_info, &auth_length, true);
1078 if (!NT_STATUS_IS_OK(status)) {
1079 composite_error(c, status);
1080 return;
1084 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1086 composite_done(c);
1090 handle timeouts of individual dcerpc requests
1092 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1093 struct timeval t, void *private_data)
1095 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1097 if (req->ignore_timeout) {
1098 dcerpc_req_dequeue(req);
1099 req->state = RPC_REQUEST_DONE;
1100 req->status = NT_STATUS_IO_TIMEOUT;
1101 if (req->async.callback) {
1102 req->async.callback(req);
1104 return;
1107 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1111 send a async dcerpc bind request
1113 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
1114 TALLOC_CTX *mem_ctx,
1115 const struct ndr_syntax_id *syntax,
1116 const struct ndr_syntax_id *transfer_syntax)
1118 struct composite_context *c;
1119 struct ncacn_packet pkt;
1120 DATA_BLOB blob;
1121 struct rpc_request *req;
1123 c = composite_create(mem_ctx,p->conn->event_ctx);
1124 if (c == NULL) return NULL;
1126 c->private_data = p;
1128 p->syntax = *syntax;
1129 p->transfer_syntax = *transfer_syntax;
1131 init_ncacn_hdr(p->conn, &pkt);
1133 pkt.ptype = DCERPC_PKT_BIND;
1134 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1135 pkt.call_id = p->conn->call_id;
1136 pkt.auth_length = 0;
1138 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1139 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1142 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1143 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1146 pkt.u.bind.max_xmit_frag = 5840;
1147 pkt.u.bind.max_recv_frag = 5840;
1148 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1149 pkt.u.bind.num_contexts = 1;
1150 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1151 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
1152 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1153 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1154 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1155 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1156 pkt.u.bind.auth_info = data_blob(NULL, 0);
1158 /* construct the NDR form of the packet */
1159 c->status = ncacn_push_auth(&blob, c, &pkt,
1160 p->conn->security_state.auth_info);
1161 if (!composite_is_ok(c)) return c;
1163 p->conn->transport.recv_data = dcerpc_recv_data;
1166 * we allocate a dcerpc_request so we can be in the same
1167 * request queue as normal requests
1169 req = talloc_zero(c, struct rpc_request);
1170 if (composite_nomem(req, c)) return c;
1172 req->state = RPC_REQUEST_PENDING;
1173 req->call_id = pkt.call_id;
1174 req->async.private_data = c;
1175 req->async.callback = dcerpc_composite_fail;
1176 req->p = p;
1177 req->recv_handler = dcerpc_bind_recv_handler;
1178 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1179 talloc_set_destructor(req, dcerpc_req_dequeue);
1181 c->status = p->conn->transport.send_request(p->conn, &blob,
1182 true);
1183 if (!composite_is_ok(c)) return c;
1185 event_add_timed(c->event_ctx, req,
1186 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1187 dcerpc_timeout_handler, req);
1189 return c;
1193 recv side of async dcerpc bind request
1195 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
1197 NTSTATUS result = composite_wait(ctx);
1198 talloc_free(ctx);
1199 return result;
1203 perform a continued bind (and auth3)
1205 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1206 TALLOC_CTX *mem_ctx)
1208 struct ncacn_packet pkt;
1209 NTSTATUS status;
1210 DATA_BLOB blob;
1212 init_ncacn_hdr(p->conn, &pkt);
1214 pkt.ptype = DCERPC_PKT_AUTH3;
1215 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1216 pkt.call_id = next_call_id(p->conn);
1217 pkt.auth_length = 0;
1218 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1220 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1221 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1224 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1225 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1228 /* construct the NDR form of the packet */
1229 status = ncacn_push_auth(&blob, mem_ctx,
1230 &pkt,
1231 p->conn->security_state.auth_info);
1232 if (!NT_STATUS_IS_OK(status)) {
1233 return status;
1236 /* send it on its way */
1237 status = p->conn->transport.send_request(p->conn, &blob, false);
1238 if (!NT_STATUS_IS_OK(status)) {
1239 return status;
1242 return NT_STATUS_OK;
1247 process a fragment received from the transport layer during a
1248 request
1250 This function frees the data
1252 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1253 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1255 struct rpc_request *req;
1256 unsigned int length;
1257 NTSTATUS status = NT_STATUS_OK;
1260 if this is an authenticated connection then parse and check
1261 the auth info. We have to do this before finding the
1262 matching packet, as the request structure might have been
1263 removed due to a timeout, but if it has been we still need
1264 to run the auth routines so that we don't get the sign/seal
1265 info out of step with the server
1267 if (c->security_state.auth_info && c->security_state.generic_state &&
1268 pkt->ptype == DCERPC_PKT_RESPONSE) {
1269 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1272 /* find the matching request */
1273 for (req=c->pending;req;req=req->next) {
1274 if (pkt->call_id == req->call_id) break;
1277 #if 0
1278 /* useful for testing certain vendors RPC servers */
1279 if (req == NULL && c->pending && pkt->call_id == 0) {
1280 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1281 req = c->pending;
1283 #endif
1285 if (req == NULL) {
1286 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1287 data_blob_free(raw_packet);
1288 return;
1291 talloc_steal(req, raw_packet->data);
1293 if (req->recv_handler != NULL) {
1294 dcerpc_req_dequeue(req);
1295 req->state = RPC_REQUEST_DONE;
1296 req->recv_handler(req, raw_packet, pkt);
1297 return;
1300 if (pkt->ptype == DCERPC_PKT_FAULT) {
1301 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1302 req->fault_code = pkt->u.fault.status;
1303 req->status = NT_STATUS_NET_WRITE_FAULT;
1304 goto req_done;
1307 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1308 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1309 (int)pkt->ptype));
1310 req->fault_code = DCERPC_FAULT_OTHER;
1311 req->status = NT_STATUS_NET_WRITE_FAULT;
1312 goto req_done;
1315 /* now check the status from the auth routines, and if it failed then fail
1316 this request accordingly */
1317 if (!NT_STATUS_IS_OK(status)) {
1318 req->status = status;
1319 goto req_done;
1322 length = pkt->u.response.stub_and_verifier.length;
1324 if (length > 0) {
1325 req->payload.data = talloc_realloc(req,
1326 req->payload.data,
1327 uint8_t,
1328 req->payload.length + length);
1329 if (!req->payload.data) {
1330 req->status = NT_STATUS_NO_MEMORY;
1331 goto req_done;
1333 memcpy(req->payload.data+req->payload.length,
1334 pkt->u.response.stub_and_verifier.data, length);
1335 req->payload.length += length;
1338 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1339 c->transport.send_read(c);
1340 return;
1343 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1344 req->flags |= DCERPC_PULL_BIGENDIAN;
1345 } else {
1346 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1350 req_done:
1351 /* we've got the full payload */
1352 req->state = RPC_REQUEST_DONE;
1353 DLIST_REMOVE(c->pending, req);
1355 if (c->request_queue != NULL) {
1356 /* We have to look at shipping further requests before calling
1357 * the async function, that one might close the pipe */
1358 dcerpc_ship_next_request(c);
1361 if (req->async.callback) {
1362 req->async.callback(req);
1367 perform the send side of a async dcerpc request
1369 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
1370 const struct GUID *object,
1371 uint16_t opnum,
1372 DATA_BLOB *stub_data)
1374 struct rpc_request *req;
1376 p->conn->transport.recv_data = dcerpc_recv_data;
1378 req = talloc(p, struct rpc_request);
1379 if (req == NULL) {
1380 return NULL;
1383 req->p = p;
1384 req->call_id = next_call_id(p->conn);
1385 req->status = NT_STATUS_OK;
1386 req->state = RPC_REQUEST_QUEUED;
1387 req->payload = data_blob(NULL, 0);
1388 req->flags = 0;
1389 req->fault_code = 0;
1390 req->ignore_timeout = false;
1391 req->async.callback = NULL;
1392 req->async.private_data = NULL;
1393 req->recv_handler = NULL;
1395 if (object != NULL) {
1396 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1397 if (req->object == NULL) {
1398 talloc_free(req);
1399 return NULL;
1401 } else {
1402 req->object = NULL;
1405 req->opnum = opnum;
1406 req->request_data.length = stub_data->length;
1407 req->request_data.data = talloc_reference(req, stub_data->data);
1408 if (req->request_data.length && req->request_data.data == NULL) {
1409 return NULL;
1412 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1413 talloc_set_destructor(req, dcerpc_req_dequeue);
1415 dcerpc_ship_next_request(p->conn);
1417 if (p->request_timeout) {
1418 event_add_timed(dcerpc_event_context(p), req,
1419 timeval_current_ofs(p->request_timeout, 0),
1420 dcerpc_timeout_handler, req);
1423 return req;
1427 Send a request using the transport
1430 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1432 struct rpc_request *req;
1433 struct dcerpc_pipe *p;
1434 DATA_BLOB *stub_data;
1435 struct ncacn_packet pkt;
1436 DATA_BLOB blob;
1437 uint32_t remaining, chunk_size;
1438 bool first_packet = true;
1439 size_t sig_size = 0;
1440 bool need_async = false;
1442 req = c->request_queue;
1443 if (req == NULL) {
1444 return;
1447 p = req->p;
1448 stub_data = &req->request_data;
1450 if (c->pending) {
1451 need_async = true;
1454 DLIST_REMOVE(c->request_queue, req);
1455 DLIST_ADD(c->pending, req);
1456 req->state = RPC_REQUEST_PENDING;
1458 init_ncacn_hdr(p->conn, &pkt);
1460 remaining = stub_data->length;
1462 /* we can write a full max_recv_frag size, minus the dcerpc
1463 request header size */
1464 chunk_size = p->conn->srv_max_recv_frag;
1465 chunk_size -= DCERPC_REQUEST_LENGTH;
1466 if (c->security_state.auth_info &&
1467 c->security_state.generic_state) {
1468 sig_size = gensec_sig_size(c->security_state.generic_state,
1469 p->conn->srv_max_recv_frag);
1470 if (sig_size) {
1471 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1472 chunk_size -= sig_size;
1475 chunk_size -= (chunk_size % 16);
1477 pkt.ptype = DCERPC_PKT_REQUEST;
1478 pkt.call_id = req->call_id;
1479 pkt.auth_length = 0;
1480 pkt.pfc_flags = 0;
1481 pkt.u.request.alloc_hint = remaining;
1482 pkt.u.request.context_id = p->context_id;
1483 pkt.u.request.opnum = req->opnum;
1485 if (req->object) {
1486 pkt.u.request.object.object = *req->object;
1487 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1488 chunk_size -= ndr_size_GUID(req->object,0);
1491 /* we send a series of pdus without waiting for a reply */
1492 while (remaining > 0 || first_packet) {
1493 uint32_t chunk = MIN(chunk_size, remaining);
1494 bool last_frag = false;
1495 bool do_trans = false;
1497 first_packet = false;
1498 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1500 if (remaining == stub_data->length) {
1501 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1503 if (chunk == remaining) {
1504 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1505 last_frag = true;
1508 pkt.u.request.stub_and_verifier.data = stub_data->data +
1509 (stub_data->length - remaining);
1510 pkt.u.request.stub_and_verifier.length = chunk;
1512 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1513 if (!NT_STATUS_IS_OK(req->status)) {
1514 req->state = RPC_REQUEST_DONE;
1515 DLIST_REMOVE(p->conn->pending, req);
1516 return;
1519 if (last_frag && !need_async) {
1520 do_trans = true;
1523 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1524 if (!NT_STATUS_IS_OK(req->status)) {
1525 req->state = RPC_REQUEST_DONE;
1526 DLIST_REMOVE(p->conn->pending, req);
1527 return;
1530 if (last_frag && !do_trans) {
1531 req->status = p->conn->transport.send_read(p->conn);
1532 if (!NT_STATUS_IS_OK(req->status)) {
1533 req->state = RPC_REQUEST_DONE;
1534 DLIST_REMOVE(p->conn->pending, req);
1535 return;
1539 remaining -= chunk;
1544 return the event context for a dcerpc pipe
1545 used by callers who wish to operate asynchronously
1547 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1549 return p->conn->event_ctx;
1555 perform the receive side of a async dcerpc request
1557 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1558 TALLOC_CTX *mem_ctx,
1559 DATA_BLOB *stub_data)
1561 NTSTATUS status;
1563 while (req->state != RPC_REQUEST_DONE) {
1564 struct tevent_context *ctx = dcerpc_event_context(req->p);
1565 if (event_loop_once(ctx) != 0) {
1566 return NT_STATUS_CONNECTION_DISCONNECTED;
1569 *stub_data = req->payload;
1570 status = req->status;
1571 if (stub_data->data) {
1572 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1574 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1575 req->p->last_fault_code = req->fault_code;
1577 talloc_unlink(talloc_parent(req), req);
1578 return status;
1582 this is a paranoid NDR validator. For every packet we push onto the wire
1583 we pull it back again, then push it again. Then we compare the raw NDR data
1584 for that to the NDR we initially generated. If they don't match then we know
1585 we must have a bug in either the pull or push side of our code
1587 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1588 TALLOC_CTX *mem_ctx,
1589 DATA_BLOB blob,
1590 size_t struct_size,
1591 ndr_push_flags_fn_t ndr_push,
1592 ndr_pull_flags_fn_t ndr_pull)
1594 void *st;
1595 struct ndr_pull *pull;
1596 struct ndr_push *push;
1597 DATA_BLOB blob2;
1598 enum ndr_err_code ndr_err;
1600 st = talloc_size(mem_ctx, struct_size);
1601 if (!st) {
1602 return NT_STATUS_NO_MEMORY;
1605 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1606 if (!pull) {
1607 return NT_STATUS_NO_MEMORY;
1609 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1611 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1612 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1615 if (c->flags & DCERPC_NDR64) {
1616 pull->flags |= LIBNDR_FLAG_NDR64;
1619 ndr_err = ndr_pull(pull, NDR_IN, st);
1620 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1621 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1622 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1623 "failed input validation pull - %s",
1624 nt_errstr(status));
1625 return ndr_map_error2ntstatus(ndr_err);
1628 push = ndr_push_init_ctx(mem_ctx);
1629 if (!push) {
1630 return NT_STATUS_NO_MEMORY;
1633 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1634 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1637 if (c->flags & DCERPC_NDR64) {
1638 push->flags |= LIBNDR_FLAG_NDR64;
1641 ndr_err = ndr_push(push, NDR_IN, st);
1642 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1643 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1644 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1645 "failed input validation push - %s",
1646 nt_errstr(status));
1647 return ndr_map_error2ntstatus(ndr_err);
1650 blob2 = ndr_push_blob(push);
1652 if (data_blob_cmp(&blob, &blob2) != 0) {
1653 DEBUG(3,("original:\n"));
1654 dump_data(3, blob.data, blob.length);
1655 DEBUG(3,("secondary:\n"));
1656 dump_data(3, blob2.data, blob2.length);
1657 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1658 "failed input validation blobs doesn't match");
1659 return ndr_map_error2ntstatus(ndr_err);
1662 return NT_STATUS_OK;
1666 this is a paranoid NDR input validator. For every packet we pull
1667 from the wire we push it back again then pull and push it
1668 again. Then we compare the raw NDR data for that to the NDR we
1669 initially generated. If they don't match then we know we must have a
1670 bug in either the pull or push side of our code
1672 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1673 struct ndr_pull *pull_in,
1674 void *struct_ptr,
1675 size_t struct_size,
1676 ndr_push_flags_fn_t ndr_push,
1677 ndr_pull_flags_fn_t ndr_pull,
1678 ndr_print_function_t ndr_print)
1680 void *st;
1681 struct ndr_pull *pull;
1682 struct ndr_push *push;
1683 DATA_BLOB blob, blob2;
1684 TALLOC_CTX *mem_ctx = pull_in;
1685 char *s1, *s2;
1686 enum ndr_err_code ndr_err;
1688 st = talloc_size(mem_ctx, struct_size);
1689 if (!st) {
1690 return NT_STATUS_NO_MEMORY;
1692 memcpy(st, struct_ptr, struct_size);
1694 push = ndr_push_init_ctx(mem_ctx);
1695 if (!push) {
1696 return NT_STATUS_NO_MEMORY;
1699 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1700 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1701 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1702 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1703 "failed output validation push - %s",
1704 nt_errstr(status));
1705 return ndr_map_error2ntstatus(ndr_err);
1708 blob = ndr_push_blob(push);
1710 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1711 if (!pull) {
1712 return NT_STATUS_NO_MEMORY;
1715 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1716 ndr_err = ndr_pull(pull, NDR_OUT, st);
1717 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1718 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1719 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1720 "failed output validation pull - %s",
1721 nt_errstr(status));
1722 return ndr_map_error2ntstatus(ndr_err);
1725 push = ndr_push_init_ctx(mem_ctx);
1726 if (!push) {
1727 return NT_STATUS_NO_MEMORY;
1730 ndr_err = ndr_push(push, NDR_OUT, st);
1731 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1732 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1733 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1734 "failed output validation push2 - %s",
1735 nt_errstr(status));
1736 return ndr_map_error2ntstatus(ndr_err);
1739 blob2 = ndr_push_blob(push);
1741 if (data_blob_cmp(&blob, &blob2) != 0) {
1742 DEBUG(3,("original:\n"));
1743 dump_data(3, blob.data, blob.length);
1744 DEBUG(3,("secondary:\n"));
1745 dump_data(3, blob2.data, blob2.length);
1746 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1747 "failed output validation blobs doesn't match");
1748 return ndr_map_error2ntstatus(ndr_err);
1751 /* this checks the printed forms of the two structures, which effectively
1752 tests all of the value() attributes */
1753 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1754 NDR_OUT, struct_ptr);
1755 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1756 NDR_OUT, st);
1757 if (strcmp(s1, s2) != 0) {
1758 #if 1
1759 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1760 #else
1761 /* this is sometimes useful */
1762 printf("VALIDATE ERROR\n");
1763 file_save("wire.dat", s1, strlen(s1));
1764 file_save("gen.dat", s2, strlen(s2));
1765 system("diff -u wire.dat gen.dat");
1766 #endif
1767 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1768 "failed output validation strings doesn't match");
1769 return ndr_map_error2ntstatus(ndr_err);
1772 return NT_STATUS_OK;
1776 a useful function for retrieving the server name we connected to
1778 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1780 if (!p->conn->transport.target_hostname) {
1781 if (!p->conn->transport.peer_name) {
1782 return "";
1784 return p->conn->transport.peer_name(p->conn);
1786 return p->conn->transport.target_hostname(p->conn);
1791 get the dcerpc auth_level for a open connection
1793 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1795 uint8_t auth_level;
1797 if (c->flags & DCERPC_SEAL) {
1798 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1799 } else if (c->flags & DCERPC_SIGN) {
1800 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1801 } else if (c->flags & DCERPC_CONNECT) {
1802 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1803 } else {
1804 auth_level = DCERPC_AUTH_LEVEL_NONE;
1806 return auth_level;
1810 Receive an alter reply from the transport
1812 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1813 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1815 struct composite_context *c;
1816 struct dcerpc_pipe *recv_pipe;
1818 c = talloc_get_type(req->async.private_data, struct composite_context);
1819 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1821 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1822 pkt->u.alter_resp.num_results == 1 &&
1823 pkt->u.alter_resp.ctx_list[0].result != 0) {
1824 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1825 pkt->u.alter_resp.ctx_list[0].reason));
1826 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1827 return;
1830 if (pkt->ptype == DCERPC_PKT_FAULT) {
1831 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1832 recv_pipe->last_fault_code = pkt->u.fault.status;
1833 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1834 return;
1837 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1838 pkt->u.alter_resp.num_results == 0 ||
1839 pkt->u.alter_resp.ctx_list[0].result != 0) {
1840 recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1841 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1842 return;
1845 /* the alter_resp might contain a reply set of credentials */
1846 if (recv_pipe->conn->security_state.auth_info &&
1847 pkt->u.alter_resp.auth_info.length) {
1848 struct dcecli_connection *conn = recv_pipe->conn;
1849 NTSTATUS status;
1850 uint32_t auth_length;
1851 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1852 conn->security_state.auth_info, &auth_length, true);
1853 if (!NT_STATUS_IS_OK(status)) {
1854 composite_error(c, status);
1855 return;
1859 composite_done(c);
1863 send a dcerpc alter_context request
1865 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1866 TALLOC_CTX *mem_ctx,
1867 const struct ndr_syntax_id *syntax,
1868 const struct ndr_syntax_id *transfer_syntax)
1870 struct composite_context *c;
1871 struct ncacn_packet pkt;
1872 DATA_BLOB blob;
1873 struct rpc_request *req;
1875 c = composite_create(mem_ctx, p->conn->event_ctx);
1876 if (c == NULL) return NULL;
1878 c->private_data = p;
1880 p->syntax = *syntax;
1881 p->transfer_syntax = *transfer_syntax;
1883 init_ncacn_hdr(p->conn, &pkt);
1885 pkt.ptype = DCERPC_PKT_ALTER;
1886 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1887 pkt.call_id = p->conn->call_id;
1888 pkt.auth_length = 0;
1890 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1891 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1894 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1895 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1898 pkt.u.alter.max_xmit_frag = 5840;
1899 pkt.u.alter.max_recv_frag = 5840;
1900 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1901 pkt.u.alter.num_contexts = 1;
1902 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1903 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1904 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1905 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1906 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1907 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1908 pkt.u.alter.auth_info = data_blob(NULL, 0);
1910 /* construct the NDR form of the packet */
1911 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1912 p->conn->security_state.auth_info);
1913 if (!composite_is_ok(c)) return c;
1915 p->conn->transport.recv_data = dcerpc_recv_data;
1918 * we allocate a dcerpc_request so we can be in the same
1919 * request queue as normal requests
1921 req = talloc_zero(c, struct rpc_request);
1922 if (composite_nomem(req, c)) return c;
1924 req->state = RPC_REQUEST_PENDING;
1925 req->call_id = pkt.call_id;
1926 req->async.private_data = c;
1927 req->async.callback = dcerpc_composite_fail;
1928 req->p = p;
1929 req->recv_handler = dcerpc_alter_recv_handler;
1930 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1931 talloc_set_destructor(req, dcerpc_req_dequeue);
1933 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1934 if (!composite_is_ok(c)) return c;
1936 event_add_timed(c->event_ctx, req,
1937 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1938 dcerpc_timeout_handler, req);
1940 return c;
1943 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1945 NTSTATUS result = composite_wait(ctx);
1946 talloc_free(ctx);
1947 return result;
1951 send a dcerpc alter_context request
1953 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1954 TALLOC_CTX *mem_ctx,
1955 const struct ndr_syntax_id *syntax,
1956 const struct ndr_syntax_id *transfer_syntax)
1958 struct composite_context *creq;
1959 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1960 return dcerpc_alter_context_recv(creq);