s3: Convert open_files.idl to tab indents
[Samba/id10ts.git] / source4 / librpc / rpc / dcerpc.c
blobcaf421ba87d2912398531cf7b28b834b2c48a65f
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_CONNECTION_DISCONNECTED);
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_CONNECTION_DISCONNECTED);
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 raw_packet->data + DCERPC_REQUEST_LENGTH,
712 pkt->u.response.stub_and_verifier.length,
713 raw_packet->data,
714 raw_packet->length - auth.credentials.length,
715 &auth.credentials);
716 memcpy(pkt->u.response.stub_and_verifier.data,
717 raw_packet->data + DCERPC_REQUEST_LENGTH,
718 pkt->u.response.stub_and_verifier.length);
719 break;
721 case DCERPC_AUTH_LEVEL_INTEGRITY:
722 status = gensec_check_packet(c->security_state.generic_state,
723 pkt->u.response.stub_and_verifier.data,
724 pkt->u.response.stub_and_verifier.length,
725 raw_packet->data,
726 raw_packet->length - auth.credentials.length,
727 &auth.credentials);
728 break;
730 case DCERPC_AUTH_LEVEL_CONNECT:
731 /* for now we ignore possible signatures here */
732 status = NT_STATUS_OK;
733 break;
735 default:
736 status = NT_STATUS_INVALID_LEVEL;
737 break;
740 /* remove the indicated amount of padding */
741 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
742 return NT_STATUS_INFO_LENGTH_MISMATCH;
744 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
746 return status;
751 push a dcerpc request packet into a blob, possibly signing it.
753 static NTSTATUS ncacn_push_request_sign(struct dcecli_connection *c,
754 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
755 size_t sig_size,
756 struct ncacn_packet *pkt)
758 NTSTATUS status;
759 struct ndr_push *ndr;
760 DATA_BLOB creds2;
761 size_t payload_length;
762 enum ndr_err_code ndr_err;
763 size_t hdr_size = DCERPC_REQUEST_LENGTH;
765 /* non-signed packets are simpler */
766 if (sig_size == 0) {
767 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
770 switch (c->security_state.auth_info->auth_level) {
771 case DCERPC_AUTH_LEVEL_PRIVACY:
772 case DCERPC_AUTH_LEVEL_INTEGRITY:
773 break;
775 case DCERPC_AUTH_LEVEL_CONNECT:
776 /* TODO: let the gensec mech decide if it wants to generate a signature */
777 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
779 case DCERPC_AUTH_LEVEL_NONE:
780 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
782 default:
783 return NT_STATUS_INVALID_LEVEL;
786 ndr = ndr_push_init_ctx(mem_ctx);
787 if (!ndr) {
788 return NT_STATUS_NO_MEMORY;
791 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
792 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
795 if (c->flags & DCERPC_NDR64) {
796 ndr->flags |= LIBNDR_FLAG_NDR64;
799 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
800 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
801 hdr_size += 16;
804 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
805 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
806 return ndr_map_error2ntstatus(ndr_err);
809 /* pad to 16 byte multiple in the payload portion of the
810 packet. This matches what w2k3 does. Note that we can't use
811 ndr_push_align() as that is relative to the start of the
812 whole packet, whereas w2k8 wants it relative to the start
813 of the stub */
814 c->security_state.auth_info->auth_pad_length =
815 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
816 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
817 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
818 return ndr_map_error2ntstatus(ndr_err);
821 payload_length = pkt->u.request.stub_and_verifier.length +
822 c->security_state.auth_info->auth_pad_length;
824 /* we start without signature, it will appended later */
825 c->security_state.auth_info->credentials = data_blob(NULL,0);
827 /* add the auth verifier */
828 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
829 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
830 return ndr_map_error2ntstatus(ndr_err);
833 /* extract the whole packet as a blob */
834 *blob = ndr_push_blob(ndr);
837 * Setup the frag and auth length in the packet buffer.
838 * This is needed if the GENSEC mech does AEAD signing
839 * of the packet headers. The signature itself will be
840 * appended later.
842 dcerpc_set_frag_length(blob, blob->length + sig_size);
843 dcerpc_set_auth_length(blob, sig_size);
845 /* sign or seal the packet */
846 switch (c->security_state.auth_info->auth_level) {
847 case DCERPC_AUTH_LEVEL_PRIVACY:
848 status = gensec_seal_packet(c->security_state.generic_state,
849 mem_ctx,
850 blob->data + hdr_size,
851 payload_length,
852 blob->data,
853 blob->length,
854 &creds2);
855 if (!NT_STATUS_IS_OK(status)) {
856 return status;
858 break;
860 case DCERPC_AUTH_LEVEL_INTEGRITY:
861 status = gensec_sign_packet(c->security_state.generic_state,
862 mem_ctx,
863 blob->data + hdr_size,
864 payload_length,
865 blob->data,
866 blob->length,
867 &creds2);
868 if (!NT_STATUS_IS_OK(status)) {
869 return status;
871 break;
873 default:
874 status = NT_STATUS_INVALID_LEVEL;
875 break;
878 if (creds2.length != sig_size) {
879 /* this means the sig_size estimate for the signature
880 was incorrect. We have to correct the packet
881 sizes. That means we could go over the max fragment
882 length */
883 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
884 (unsigned) creds2.length,
885 (unsigned) sig_size,
886 (unsigned) c->security_state.auth_info->auth_pad_length,
887 (unsigned) pkt->u.request.stub_and_verifier.length));
888 dcerpc_set_frag_length(blob, blob->length + creds2.length);
889 dcerpc_set_auth_length(blob, creds2.length);
892 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
893 return NT_STATUS_NO_MEMORY;
896 return NT_STATUS_OK;
901 fill in the fixed values in a dcerpc header
903 static void init_ncacn_hdr(struct dcecli_connection *c, struct ncacn_packet *pkt)
905 pkt->rpc_vers = 5;
906 pkt->rpc_vers_minor = 0;
907 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
908 pkt->drep[0] = 0;
909 } else {
910 pkt->drep[0] = DCERPC_DREP_LE;
912 pkt->drep[1] = 0;
913 pkt->drep[2] = 0;
914 pkt->drep[3] = 0;
918 map a bind nak reason to a NTSTATUS
920 static NTSTATUS dcerpc_map_reason(uint16_t reason)
922 switch (reason) {
923 case DCERPC_BIND_REASON_ASYNTAX:
924 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
925 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
926 return NT_STATUS_INVALID_PARAMETER;
928 return NT_STATUS_UNSUCCESSFUL;
932 a bind or alter context has failed
934 static void dcerpc_composite_fail(struct rpc_request *req)
936 struct composite_context *c = talloc_get_type(req->async.private_data,
937 struct composite_context);
938 composite_error(c, req->status);
942 remove requests from the pending or queued queues
944 static int dcerpc_req_dequeue(struct rpc_request *req)
946 switch (req->state) {
947 case RPC_REQUEST_QUEUED:
948 DLIST_REMOVE(req->p->conn->request_queue, req);
949 break;
950 case RPC_REQUEST_PENDING:
951 DLIST_REMOVE(req->p->conn->pending, req);
952 break;
953 case RPC_REQUEST_DONE:
954 break;
956 return 0;
961 mark the dcerpc connection dead. All outstanding requests get an error
963 static void dcerpc_connection_dead(struct dcecli_connection *conn, NTSTATUS status)
965 if (conn->dead) return;
967 conn->dead = true;
969 if (conn->transport.shutdown_pipe) {
970 conn->transport.shutdown_pipe(conn, status);
973 /* all pending requests get the error */
974 while (conn->pending) {
975 struct rpc_request *req = conn->pending;
976 dcerpc_req_dequeue(req);
977 req->state = RPC_REQUEST_DONE;
978 req->status = status;
979 if (req->async.callback) {
980 req->async.callback(req);
984 talloc_set_destructor(conn, NULL);
985 if (conn->free_skipped) {
986 talloc_free(conn);
991 forward declarations of the recv_data handlers for the types of
992 packets we need to handle
994 static void dcerpc_request_recv_data(struct dcecli_connection *c,
995 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
998 receive a dcerpc reply from the transport. Here we work out what
999 type of reply it is (normal request, bind or alter context) and
1000 dispatch to the appropriate handler
1002 static void dcerpc_recv_data(struct dcecli_connection *conn, DATA_BLOB *blob, NTSTATUS status)
1004 struct ncacn_packet pkt;
1006 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
1007 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
1010 /* the transport may be telling us of a severe error, such as
1011 a dropped socket */
1012 if (!NT_STATUS_IS_OK(status)) {
1013 data_blob_free(blob);
1014 dcerpc_connection_dead(conn, status);
1015 return;
1018 /* parse the basic packet to work out what type of response this is */
1019 status = ncacn_pull(conn, blob, blob->data, &pkt);
1020 if (!NT_STATUS_IS_OK(status)) {
1021 data_blob_free(blob);
1022 dcerpc_connection_dead(conn, status);
1025 dcerpc_request_recv_data(conn, blob, &pkt);
1029 Receive a bind reply from the transport
1031 static void dcerpc_bind_recv_handler(struct rpc_request *req,
1032 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1034 struct composite_context *c;
1035 struct dcecli_connection *conn;
1037 c = talloc_get_type(req->async.private_data, struct composite_context);
1039 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
1040 DEBUG(2,("dcerpc: bind_nak reason %d\n",
1041 pkt->u.bind_nak.reject_reason));
1042 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
1043 reject_reason));
1044 return;
1047 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1048 (pkt->u.bind_ack.num_results == 0) ||
1049 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1050 req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1051 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1052 return;
1055 conn = req->p->conn;
1057 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1058 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1060 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1061 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1062 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1065 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1066 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1067 conn->flags |= DCERPC_HEADER_SIGNING;
1070 /* the bind_ack might contain a reply set of credentials */
1071 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1072 NTSTATUS status;
1073 uint32_t auth_length;
1074 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1075 conn->security_state.auth_info, &auth_length, true);
1076 if (!NT_STATUS_IS_OK(status)) {
1077 composite_error(c, status);
1078 return;
1082 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1084 composite_done(c);
1088 handle timeouts of individual dcerpc requests
1090 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1091 struct timeval t, void *private_data)
1093 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1095 if (req->ignore_timeout) {
1096 dcerpc_req_dequeue(req);
1097 req->state = RPC_REQUEST_DONE;
1098 req->status = NT_STATUS_IO_TIMEOUT;
1099 if (req->async.callback) {
1100 req->async.callback(req);
1102 return;
1105 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1109 send a async dcerpc bind request
1111 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
1112 TALLOC_CTX *mem_ctx,
1113 const struct ndr_syntax_id *syntax,
1114 const struct ndr_syntax_id *transfer_syntax)
1116 struct composite_context *c;
1117 struct ncacn_packet pkt;
1118 DATA_BLOB blob;
1119 struct rpc_request *req;
1121 c = composite_create(mem_ctx,p->conn->event_ctx);
1122 if (c == NULL) return NULL;
1124 c->private_data = p;
1126 p->syntax = *syntax;
1127 p->transfer_syntax = *transfer_syntax;
1129 init_ncacn_hdr(p->conn, &pkt);
1131 pkt.ptype = DCERPC_PKT_BIND;
1132 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1133 pkt.call_id = p->conn->call_id;
1134 pkt.auth_length = 0;
1136 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1137 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1140 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1141 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1144 pkt.u.bind.max_xmit_frag = 5840;
1145 pkt.u.bind.max_recv_frag = 5840;
1146 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1147 pkt.u.bind.num_contexts = 1;
1148 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1149 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
1150 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1151 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1152 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1153 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1154 pkt.u.bind.auth_info = data_blob(NULL, 0);
1156 /* construct the NDR form of the packet */
1157 c->status = ncacn_push_auth(&blob, c, &pkt,
1158 p->conn->security_state.auth_info);
1159 if (!composite_is_ok(c)) return c;
1161 p->conn->transport.recv_data = dcerpc_recv_data;
1164 * we allocate a dcerpc_request so we can be in the same
1165 * request queue as normal requests
1167 req = talloc_zero(c, struct rpc_request);
1168 if (composite_nomem(req, c)) return c;
1170 req->state = RPC_REQUEST_PENDING;
1171 req->call_id = pkt.call_id;
1172 req->async.private_data = c;
1173 req->async.callback = dcerpc_composite_fail;
1174 req->p = p;
1175 req->recv_handler = dcerpc_bind_recv_handler;
1176 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1177 talloc_set_destructor(req, dcerpc_req_dequeue);
1179 c->status = p->conn->transport.send_request(p->conn, &blob,
1180 true);
1181 if (!composite_is_ok(c)) return c;
1183 tevent_add_timer(c->event_ctx, req,
1184 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1185 dcerpc_timeout_handler, req);
1187 return c;
1191 recv side of async dcerpc bind request
1193 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
1195 NTSTATUS result = composite_wait(ctx);
1196 talloc_free(ctx);
1197 return result;
1201 perform a continued bind (and auth3)
1203 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1204 TALLOC_CTX *mem_ctx)
1206 struct ncacn_packet pkt;
1207 NTSTATUS status;
1208 DATA_BLOB blob;
1210 init_ncacn_hdr(p->conn, &pkt);
1212 pkt.ptype = DCERPC_PKT_AUTH3;
1213 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1214 pkt.call_id = next_call_id(p->conn);
1215 pkt.auth_length = 0;
1216 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1218 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1219 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1222 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1223 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1226 /* construct the NDR form of the packet */
1227 status = ncacn_push_auth(&blob, mem_ctx,
1228 &pkt,
1229 p->conn->security_state.auth_info);
1230 if (!NT_STATUS_IS_OK(status)) {
1231 return status;
1234 /* send it on its way */
1235 status = p->conn->transport.send_request(p->conn, &blob, false);
1236 if (!NT_STATUS_IS_OK(status)) {
1237 return status;
1240 return NT_STATUS_OK;
1245 process a fragment received from the transport layer during a
1246 request
1248 This function frees the data
1250 static void dcerpc_request_recv_data(struct dcecli_connection *c,
1251 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1253 struct rpc_request *req;
1254 unsigned int length;
1255 NTSTATUS status = NT_STATUS_OK;
1258 if this is an authenticated connection then parse and check
1259 the auth info. We have to do this before finding the
1260 matching packet, as the request structure might have been
1261 removed due to a timeout, but if it has been we still need
1262 to run the auth routines so that we don't get the sign/seal
1263 info out of step with the server
1265 if (c->security_state.auth_info && c->security_state.generic_state &&
1266 pkt->ptype == DCERPC_PKT_RESPONSE) {
1267 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1270 /* find the matching request */
1271 for (req=c->pending;req;req=req->next) {
1272 if (pkt->call_id == req->call_id) break;
1275 #if 0
1276 /* useful for testing certain vendors RPC servers */
1277 if (req == NULL && c->pending && pkt->call_id == 0) {
1278 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1279 req = c->pending;
1281 #endif
1283 if (req == NULL) {
1284 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1285 data_blob_free(raw_packet);
1286 return;
1289 talloc_steal(req, raw_packet->data);
1291 if (req->recv_handler != NULL) {
1292 dcerpc_req_dequeue(req);
1293 req->state = RPC_REQUEST_DONE;
1294 req->recv_handler(req, raw_packet, pkt);
1295 return;
1298 if (pkt->ptype == DCERPC_PKT_FAULT) {
1299 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1300 req->fault_code = pkt->u.fault.status;
1301 req->status = NT_STATUS_NET_WRITE_FAULT;
1302 goto req_done;
1305 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1306 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1307 (int)pkt->ptype));
1308 req->fault_code = DCERPC_FAULT_OTHER;
1309 req->status = NT_STATUS_NET_WRITE_FAULT;
1310 goto req_done;
1313 /* now check the status from the auth routines, and if it failed then fail
1314 this request accordingly */
1315 if (!NT_STATUS_IS_OK(status)) {
1316 req->status = status;
1317 goto req_done;
1320 length = pkt->u.response.stub_and_verifier.length;
1322 if (length > 0) {
1323 req->payload.data = talloc_realloc(req,
1324 req->payload.data,
1325 uint8_t,
1326 req->payload.length + length);
1327 if (!req->payload.data) {
1328 req->status = NT_STATUS_NO_MEMORY;
1329 goto req_done;
1331 memcpy(req->payload.data+req->payload.length,
1332 pkt->u.response.stub_and_verifier.data, length);
1333 req->payload.length += length;
1336 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1337 c->transport.send_read(c);
1338 return;
1341 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1342 req->flags |= DCERPC_PULL_BIGENDIAN;
1343 } else {
1344 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1348 req_done:
1349 /* we've got the full payload */
1350 req->state = RPC_REQUEST_DONE;
1351 DLIST_REMOVE(c->pending, req);
1353 if (c->request_queue != NULL) {
1354 /* We have to look at shipping further requests before calling
1355 * the async function, that one might close the pipe */
1356 dcerpc_ship_next_request(c);
1359 if (req->async.callback) {
1360 req->async.callback(req);
1365 perform the send side of a async dcerpc request
1367 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
1368 const struct GUID *object,
1369 uint16_t opnum,
1370 DATA_BLOB *stub_data)
1372 struct rpc_request *req;
1374 p->conn->transport.recv_data = dcerpc_recv_data;
1376 req = talloc(p, struct rpc_request);
1377 if (req == NULL) {
1378 return NULL;
1381 req->p = p;
1382 req->call_id = next_call_id(p->conn);
1383 req->status = NT_STATUS_OK;
1384 req->state = RPC_REQUEST_QUEUED;
1385 req->payload = data_blob(NULL, 0);
1386 req->flags = 0;
1387 req->fault_code = 0;
1388 req->ignore_timeout = false;
1389 req->async.callback = NULL;
1390 req->async.private_data = NULL;
1391 req->recv_handler = NULL;
1393 if (object != NULL) {
1394 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1395 if (req->object == NULL) {
1396 talloc_free(req);
1397 return NULL;
1399 } else {
1400 req->object = NULL;
1403 req->opnum = opnum;
1404 req->request_data.length = stub_data->length;
1405 req->request_data.data = talloc_reference(req, stub_data->data);
1406 if (req->request_data.length && req->request_data.data == NULL) {
1407 return NULL;
1410 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1411 talloc_set_destructor(req, dcerpc_req_dequeue);
1413 dcerpc_ship_next_request(p->conn);
1415 if (p->request_timeout) {
1416 tevent_add_timer(dcerpc_event_context(p), req,
1417 timeval_current_ofs(p->request_timeout, 0),
1418 dcerpc_timeout_handler, req);
1421 return req;
1425 Send a request using the transport
1428 static void dcerpc_ship_next_request(struct dcecli_connection *c)
1430 struct rpc_request *req;
1431 struct dcerpc_pipe *p;
1432 DATA_BLOB *stub_data;
1433 struct ncacn_packet pkt;
1434 DATA_BLOB blob;
1435 uint32_t remaining, chunk_size;
1436 bool first_packet = true;
1437 size_t sig_size = 0;
1438 bool need_async = false;
1440 req = c->request_queue;
1441 if (req == NULL) {
1442 return;
1445 p = req->p;
1446 stub_data = &req->request_data;
1448 if (c->pending) {
1449 need_async = true;
1452 DLIST_REMOVE(c->request_queue, req);
1453 DLIST_ADD(c->pending, req);
1454 req->state = RPC_REQUEST_PENDING;
1456 init_ncacn_hdr(p->conn, &pkt);
1458 remaining = stub_data->length;
1460 /* we can write a full max_recv_frag size, minus the dcerpc
1461 request header size */
1462 chunk_size = p->conn->srv_max_recv_frag;
1463 chunk_size -= DCERPC_REQUEST_LENGTH;
1464 if (c->security_state.auth_info &&
1465 c->security_state.generic_state) {
1466 sig_size = gensec_sig_size(c->security_state.generic_state,
1467 p->conn->srv_max_recv_frag);
1468 if (sig_size) {
1469 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1470 chunk_size -= sig_size;
1473 chunk_size -= (chunk_size % 16);
1475 pkt.ptype = DCERPC_PKT_REQUEST;
1476 pkt.call_id = req->call_id;
1477 pkt.auth_length = 0;
1478 pkt.pfc_flags = 0;
1479 pkt.u.request.alloc_hint = remaining;
1480 pkt.u.request.context_id = p->context_id;
1481 pkt.u.request.opnum = req->opnum;
1483 if (req->object) {
1484 pkt.u.request.object.object = *req->object;
1485 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1486 chunk_size -= ndr_size_GUID(req->object,0);
1489 /* we send a series of pdus without waiting for a reply */
1490 while (remaining > 0 || first_packet) {
1491 uint32_t chunk = MIN(chunk_size, remaining);
1492 bool last_frag = false;
1493 bool do_trans = false;
1495 first_packet = false;
1496 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1498 if (remaining == stub_data->length) {
1499 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1501 if (chunk == remaining) {
1502 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1503 last_frag = true;
1506 pkt.u.request.stub_and_verifier.data = stub_data->data +
1507 (stub_data->length - remaining);
1508 pkt.u.request.stub_and_verifier.length = chunk;
1510 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1511 if (!NT_STATUS_IS_OK(req->status)) {
1512 req->state = RPC_REQUEST_DONE;
1513 DLIST_REMOVE(p->conn->pending, req);
1514 return;
1517 if (last_frag && !need_async) {
1518 do_trans = true;
1521 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1522 if (!NT_STATUS_IS_OK(req->status)) {
1523 req->state = RPC_REQUEST_DONE;
1524 DLIST_REMOVE(p->conn->pending, req);
1525 return;
1528 if (last_frag && !do_trans) {
1529 req->status = p->conn->transport.send_read(p->conn);
1530 if (!NT_STATUS_IS_OK(req->status)) {
1531 req->state = RPC_REQUEST_DONE;
1532 DLIST_REMOVE(p->conn->pending, req);
1533 return;
1537 remaining -= chunk;
1542 return the event context for a dcerpc pipe
1543 used by callers who wish to operate asynchronously
1545 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1547 return p->conn->event_ctx;
1553 perform the receive side of a async dcerpc request
1555 static NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1556 TALLOC_CTX *mem_ctx,
1557 DATA_BLOB *stub_data)
1559 NTSTATUS status;
1561 while (req->state != RPC_REQUEST_DONE) {
1562 struct tevent_context *ctx = dcerpc_event_context(req->p);
1563 if (tevent_loop_once(ctx) != 0) {
1564 return NT_STATUS_CONNECTION_DISCONNECTED;
1567 *stub_data = req->payload;
1568 status = req->status;
1569 if (stub_data->data) {
1570 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1572 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1573 req->p->last_fault_code = req->fault_code;
1575 talloc_unlink(talloc_parent(req), req);
1576 return status;
1580 this is a paranoid NDR validator. For every packet we push onto the wire
1581 we pull it back again, then push it again. Then we compare the raw NDR data
1582 for that to the NDR we initially generated. If they don't match then we know
1583 we must have a bug in either the pull or push side of our code
1585 static NTSTATUS dcerpc_ndr_validate_in(struct dcecli_connection *c,
1586 TALLOC_CTX *mem_ctx,
1587 DATA_BLOB blob,
1588 size_t struct_size,
1589 ndr_push_flags_fn_t ndr_push,
1590 ndr_pull_flags_fn_t ndr_pull)
1592 void *st;
1593 struct ndr_pull *pull;
1594 struct ndr_push *push;
1595 DATA_BLOB blob2;
1596 enum ndr_err_code ndr_err;
1598 st = talloc_size(mem_ctx, struct_size);
1599 if (!st) {
1600 return NT_STATUS_NO_MEMORY;
1603 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1604 if (!pull) {
1605 return NT_STATUS_NO_MEMORY;
1607 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1609 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1610 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1613 if (c->flags & DCERPC_NDR64) {
1614 pull->flags |= LIBNDR_FLAG_NDR64;
1617 ndr_err = ndr_pull(pull, NDR_IN, st);
1618 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1619 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1620 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1621 "failed input validation pull - %s",
1622 nt_errstr(status));
1623 return ndr_map_error2ntstatus(ndr_err);
1626 push = ndr_push_init_ctx(mem_ctx);
1627 if (!push) {
1628 return NT_STATUS_NO_MEMORY;
1631 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1632 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1635 if (c->flags & DCERPC_NDR64) {
1636 push->flags |= LIBNDR_FLAG_NDR64;
1639 ndr_err = ndr_push(push, NDR_IN, st);
1640 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1641 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1642 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1643 "failed input validation push - %s",
1644 nt_errstr(status));
1645 return ndr_map_error2ntstatus(ndr_err);
1648 blob2 = ndr_push_blob(push);
1650 if (data_blob_cmp(&blob, &blob2) != 0) {
1651 DEBUG(3,("original:\n"));
1652 dump_data(3, blob.data, blob.length);
1653 DEBUG(3,("secondary:\n"));
1654 dump_data(3, blob2.data, blob2.length);
1655 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1656 "failed input validation blobs doesn't match");
1657 return ndr_map_error2ntstatus(ndr_err);
1660 return NT_STATUS_OK;
1664 this is a paranoid NDR input validator. For every packet we pull
1665 from the wire we push it back again then pull and push it
1666 again. Then we compare the raw NDR data for that to the NDR we
1667 initially generated. If they don't match then we know we must have a
1668 bug in either the pull or push side of our code
1670 static NTSTATUS dcerpc_ndr_validate_out(struct dcecli_connection *c,
1671 struct ndr_pull *pull_in,
1672 void *struct_ptr,
1673 size_t struct_size,
1674 ndr_push_flags_fn_t ndr_push,
1675 ndr_pull_flags_fn_t ndr_pull,
1676 ndr_print_function_t ndr_print)
1678 void *st;
1679 struct ndr_pull *pull;
1680 struct ndr_push *push;
1681 DATA_BLOB blob, blob2;
1682 TALLOC_CTX *mem_ctx = pull_in;
1683 char *s1, *s2;
1684 enum ndr_err_code ndr_err;
1686 st = talloc_size(mem_ctx, struct_size);
1687 if (!st) {
1688 return NT_STATUS_NO_MEMORY;
1690 memcpy(st, struct_ptr, struct_size);
1692 push = ndr_push_init_ctx(mem_ctx);
1693 if (!push) {
1694 return NT_STATUS_NO_MEMORY;
1697 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1698 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1699 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1700 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1701 "failed output validation push - %s",
1702 nt_errstr(status));
1703 return ndr_map_error2ntstatus(ndr_err);
1706 blob = ndr_push_blob(push);
1708 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1709 if (!pull) {
1710 return NT_STATUS_NO_MEMORY;
1713 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1714 ndr_err = ndr_pull(pull, NDR_OUT, st);
1715 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1716 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1717 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1718 "failed output validation pull - %s",
1719 nt_errstr(status));
1720 return ndr_map_error2ntstatus(ndr_err);
1723 push = ndr_push_init_ctx(mem_ctx);
1724 if (!push) {
1725 return NT_STATUS_NO_MEMORY;
1728 ndr_err = ndr_push(push, NDR_OUT, st);
1729 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1730 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1731 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1732 "failed output validation push2 - %s",
1733 nt_errstr(status));
1734 return ndr_map_error2ntstatus(ndr_err);
1737 blob2 = ndr_push_blob(push);
1739 if (data_blob_cmp(&blob, &blob2) != 0) {
1740 DEBUG(3,("original:\n"));
1741 dump_data(3, blob.data, blob.length);
1742 DEBUG(3,("secondary:\n"));
1743 dump_data(3, blob2.data, blob2.length);
1744 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1745 "failed output validation blobs doesn't match");
1746 return ndr_map_error2ntstatus(ndr_err);
1749 /* this checks the printed forms of the two structures, which effectively
1750 tests all of the value() attributes */
1751 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1752 NDR_OUT, struct_ptr);
1753 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1754 NDR_OUT, st);
1755 if (strcmp(s1, s2) != 0) {
1756 #if 1
1757 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1758 #else
1759 /* this is sometimes useful */
1760 printf("VALIDATE ERROR\n");
1761 file_save("wire.dat", s1, strlen(s1));
1762 file_save("gen.dat", s2, strlen(s2));
1763 system("diff -u wire.dat gen.dat");
1764 #endif
1765 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1766 "failed output validation strings doesn't match");
1767 return ndr_map_error2ntstatus(ndr_err);
1770 return NT_STATUS_OK;
1774 a useful function for retrieving the server name we connected to
1776 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1778 if (!p->conn->transport.target_hostname) {
1779 if (!p->conn->transport.peer_name) {
1780 return "";
1782 return p->conn->transport.peer_name(p->conn);
1784 return p->conn->transport.target_hostname(p->conn);
1789 get the dcerpc auth_level for a open connection
1791 uint32_t dcerpc_auth_level(struct dcecli_connection *c)
1793 uint8_t auth_level;
1795 if (c->flags & DCERPC_SEAL) {
1796 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1797 } else if (c->flags & DCERPC_SIGN) {
1798 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1799 } else if (c->flags & DCERPC_CONNECT) {
1800 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1801 } else {
1802 auth_level = DCERPC_AUTH_LEVEL_NONE;
1804 return auth_level;
1808 Receive an alter reply from the transport
1810 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1811 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1813 struct composite_context *c;
1814 struct dcerpc_pipe *recv_pipe;
1816 c = talloc_get_type(req->async.private_data, struct composite_context);
1817 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1819 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1820 pkt->u.alter_resp.num_results == 1 &&
1821 pkt->u.alter_resp.ctx_list[0].result != 0) {
1822 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1823 pkt->u.alter_resp.ctx_list[0].reason));
1824 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1825 return;
1828 if (pkt->ptype == DCERPC_PKT_FAULT) {
1829 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1830 recv_pipe->last_fault_code = pkt->u.fault.status;
1831 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1832 return;
1835 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1836 pkt->u.alter_resp.num_results == 0 ||
1837 pkt->u.alter_resp.ctx_list[0].result != 0) {
1838 recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1839 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1840 return;
1843 /* the alter_resp might contain a reply set of credentials */
1844 if (recv_pipe->conn->security_state.auth_info &&
1845 pkt->u.alter_resp.auth_info.length) {
1846 struct dcecli_connection *conn = recv_pipe->conn;
1847 NTSTATUS status;
1848 uint32_t auth_length;
1849 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1850 conn->security_state.auth_info, &auth_length, true);
1851 if (!NT_STATUS_IS_OK(status)) {
1852 composite_error(c, status);
1853 return;
1857 composite_done(c);
1861 send a dcerpc alter_context request
1863 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1864 TALLOC_CTX *mem_ctx,
1865 const struct ndr_syntax_id *syntax,
1866 const struct ndr_syntax_id *transfer_syntax)
1868 struct composite_context *c;
1869 struct ncacn_packet pkt;
1870 DATA_BLOB blob;
1871 struct rpc_request *req;
1873 c = composite_create(mem_ctx, p->conn->event_ctx);
1874 if (c == NULL) return NULL;
1876 c->private_data = p;
1878 p->syntax = *syntax;
1879 p->transfer_syntax = *transfer_syntax;
1881 init_ncacn_hdr(p->conn, &pkt);
1883 pkt.ptype = DCERPC_PKT_ALTER;
1884 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1885 pkt.call_id = p->conn->call_id;
1886 pkt.auth_length = 0;
1888 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1889 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1892 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1893 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1896 pkt.u.alter.max_xmit_frag = 5840;
1897 pkt.u.alter.max_recv_frag = 5840;
1898 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1899 pkt.u.alter.num_contexts = 1;
1900 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1901 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1902 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1903 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1904 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1905 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1906 pkt.u.alter.auth_info = data_blob(NULL, 0);
1908 /* construct the NDR form of the packet */
1909 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1910 p->conn->security_state.auth_info);
1911 if (!composite_is_ok(c)) return c;
1913 p->conn->transport.recv_data = dcerpc_recv_data;
1916 * we allocate a dcerpc_request so we can be in the same
1917 * request queue as normal requests
1919 req = talloc_zero(c, struct rpc_request);
1920 if (composite_nomem(req, c)) return c;
1922 req->state = RPC_REQUEST_PENDING;
1923 req->call_id = pkt.call_id;
1924 req->async.private_data = c;
1925 req->async.callback = dcerpc_composite_fail;
1926 req->p = p;
1927 req->recv_handler = dcerpc_alter_recv_handler;
1928 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1929 talloc_set_destructor(req, dcerpc_req_dequeue);
1931 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1932 if (!composite_is_ok(c)) return c;
1934 tevent_add_timer(c->event_ctx, req,
1935 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1936 dcerpc_timeout_handler, req);
1938 return c;
1941 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1943 NTSTATUS result = composite_wait(ctx);
1944 talloc_free(ctx);
1945 return result;
1949 send a dcerpc alter_context request
1951 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1952 TALLOC_CTX *mem_ctx,
1953 const struct ndr_syntax_id *syntax,
1954 const struct ndr_syntax_id *transfer_syntax)
1956 struct composite_context *creq;
1957 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1958 return dcerpc_alter_context_recv(creq);