build: moved librpc/rpc/*.c into a rpccommon library
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blob3b67512f913cc7a8386eb0623ac5e4abcbe0bca7
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 _PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
38 return gensec_init(lp_ctx);
41 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
42 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
44 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
45 const struct GUID *object,
46 uint16_t opnum,
47 DATA_BLOB *stub_data);
48 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
49 TALLOC_CTX *mem_ctx,
50 DATA_BLOB blob,
51 size_t struct_size,
52 ndr_push_flags_fn_t ndr_push,
53 ndr_pull_flags_fn_t ndr_pull);
54 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
55 struct ndr_pull *pull_in,
56 void *struct_ptr,
57 size_t struct_size,
58 ndr_push_flags_fn_t ndr_push,
59 ndr_pull_flags_fn_t ndr_pull,
60 ndr_print_function_t ndr_print);
62 /* destroy a dcerpc connection */
63 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
65 if (conn->dead) {
66 conn->free_skipped = true;
67 return -1;
69 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
70 return 0;
74 /* initialise a dcerpc connection.
75 the event context is optional
77 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
78 struct tevent_context *ev)
80 struct dcerpc_connection *c;
82 c = talloc_zero(mem_ctx, struct dcerpc_connection);
83 if (!c) {
84 return NULL;
87 c->event_ctx = ev;
89 if (c->event_ctx == NULL) {
90 talloc_free(c);
91 return NULL;
94 c->call_id = 1;
95 c->security_state.auth_info = NULL;
96 c->security_state.session_key = dcerpc_generic_session_key;
97 c->security_state.generic_state = NULL;
98 c->binding_string = NULL;
99 c->flags = 0;
100 c->srv_max_xmit_frag = 0;
101 c->srv_max_recv_frag = 0;
102 c->pending = NULL;
104 talloc_set_destructor(c, dcerpc_connection_destructor);
106 return c;
109 struct dcerpc_bh_state {
110 struct dcerpc_pipe *p;
113 static bool dcerpc_bh_is_connected(struct dcerpc_binding_handle *h)
115 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
116 struct dcerpc_bh_state);
118 if (!hs->p) {
119 return false;
122 return true;
125 static uint32_t dcerpc_bh_set_timeout(struct dcerpc_binding_handle *h,
126 uint32_t timeout)
128 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
129 struct dcerpc_bh_state);
130 uint32_t old;
132 if (!hs->p) {
133 return DCERPC_REQUEST_TIMEOUT;
136 old = hs->p->request_timeout;
137 hs->p->request_timeout = timeout;
139 return old;
142 struct dcerpc_bh_raw_call_state {
143 struct dcerpc_binding_handle *h;
144 DATA_BLOB in_data;
145 DATA_BLOB out_data;
146 uint32_t out_flags;
149 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq);
151 static struct tevent_req *dcerpc_bh_raw_call_send(TALLOC_CTX *mem_ctx,
152 struct tevent_context *ev,
153 struct dcerpc_binding_handle *h,
154 const struct GUID *object,
155 uint32_t opnum,
156 uint32_t in_flags,
157 const uint8_t *in_data,
158 size_t in_length)
160 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
161 struct dcerpc_bh_state);
162 struct tevent_req *req;
163 struct dcerpc_bh_raw_call_state *state;
164 bool ok;
165 struct rpc_request *subreq;
167 req = tevent_req_create(mem_ctx, &state,
168 struct dcerpc_bh_raw_call_state);
169 if (req == NULL) {
170 return NULL;
172 state->h = h;
173 state->in_data.data = discard_const_p(uint8_t, in_data);
174 state->in_data.length = in_length;
176 ok = dcerpc_bh_is_connected(h);
177 if (!ok) {
178 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
179 return tevent_req_post(req, ev);
182 subreq = dcerpc_request_send(hs->p,
183 object,
184 opnum,
185 &state->in_data);
186 if (tevent_req_nomem(subreq, req)) {
187 return tevent_req_post(req, ev);
189 subreq->async.callback = dcerpc_bh_raw_call_done;
190 subreq->async.private_data = req;
192 return req;
195 static void dcerpc_bh_raw_call_done(struct rpc_request *subreq)
197 struct tevent_req *req =
198 talloc_get_type_abort(subreq->async.private_data,
199 struct tevent_req);
200 struct dcerpc_bh_raw_call_state *state =
201 tevent_req_data(req,
202 struct dcerpc_bh_raw_call_state);
203 NTSTATUS status;
204 uint32_t fault_code;
206 state->out_flags = 0;
207 if (subreq->flags & DCERPC_PULL_BIGENDIAN) {
208 state->out_flags |= LIBNDR_FLAG_BIGENDIAN;
211 fault_code = subreq->fault_code;
213 status = dcerpc_request_recv(subreq, state, &state->out_data);
214 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
215 status = dcerpc_fault_to_nt_status(fault_code);
217 if (!NT_STATUS_IS_OK(status)) {
218 tevent_req_nterror(req, status);
219 return;
222 tevent_req_done(req);
225 static NTSTATUS dcerpc_bh_raw_call_recv(struct tevent_req *req,
226 TALLOC_CTX *mem_ctx,
227 uint8_t **out_data,
228 size_t *out_length,
229 uint32_t *out_flags)
231 struct dcerpc_bh_raw_call_state *state =
232 tevent_req_data(req,
233 struct dcerpc_bh_raw_call_state);
234 NTSTATUS status;
236 if (tevent_req_is_nterror(req, &status)) {
237 tevent_req_received(req);
238 return status;
241 *out_data = talloc_move(mem_ctx, &state->out_data.data);
242 *out_length = state->out_data.length;
243 *out_flags = state->out_flags;
244 tevent_req_received(req);
245 return NT_STATUS_OK;
248 struct dcerpc_bh_disconnect_state {
249 uint8_t _dummy;
252 static struct tevent_req *dcerpc_bh_disconnect_send(TALLOC_CTX *mem_ctx,
253 struct tevent_context *ev,
254 struct dcerpc_binding_handle *h)
256 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
257 struct dcerpc_bh_state);
258 struct tevent_req *req;
259 struct dcerpc_bh_disconnect_state *state;
260 bool ok;
262 req = tevent_req_create(mem_ctx, &state,
263 struct dcerpc_bh_disconnect_state);
264 if (req == NULL) {
265 return NULL;
268 ok = dcerpc_bh_is_connected(h);
269 if (!ok) {
270 tevent_req_nterror(req, NT_STATUS_INVALID_CONNECTION);
271 return tevent_req_post(req, ev);
274 /* TODO: do a real disconnect ... */
275 hs->p = NULL;
277 tevent_req_done(req);
278 return tevent_req_post(req, ev);
281 static NTSTATUS dcerpc_bh_disconnect_recv(struct tevent_req *req)
283 NTSTATUS status;
285 if (tevent_req_is_nterror(req, &status)) {
286 tevent_req_received(req);
287 return status;
290 tevent_req_received(req);
291 return NT_STATUS_OK;
294 static bool dcerpc_bh_push_bigendian(struct dcerpc_binding_handle *h)
296 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
297 struct dcerpc_bh_state);
299 if (hs->p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
300 return true;
303 return false;
306 static bool dcerpc_bh_ref_alloc(struct dcerpc_binding_handle *h)
308 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
309 struct dcerpc_bh_state);
311 if (hs->p->conn->flags & DCERPC_NDR_REF_ALLOC) {
312 return true;
315 return false;
318 static bool dcerpc_bh_use_ndr64(struct dcerpc_binding_handle *h)
320 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
321 struct dcerpc_bh_state);
323 if (hs->p->conn->flags & DCERPC_NDR64) {
324 return true;
327 return false;
330 static void dcerpc_bh_do_ndr_print(struct dcerpc_binding_handle *h,
331 int ndr_flags,
332 const void *_struct_ptr,
333 const struct ndr_interface_call *call)
335 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
336 struct dcerpc_bh_state);
337 void *struct_ptr = discard_const(_struct_ptr);
339 if (ndr_flags & NDR_IN) {
340 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_IN) {
341 ndr_print_function_debug(call->ndr_print,
342 call->name,
343 ndr_flags,
344 struct_ptr);
347 if (ndr_flags & NDR_OUT) {
348 if (hs->p->conn->flags & DCERPC_DEBUG_PRINT_OUT) {
349 ndr_print_function_debug(call->ndr_print,
350 call->name,
351 ndr_flags,
352 struct_ptr);
357 static void dcerpc_bh_ndr_push_failed(struct dcerpc_binding_handle *h,
358 NTSTATUS error,
359 const void *struct_ptr,
360 const struct ndr_interface_call *call)
362 DEBUG(2,("Unable to ndr_push structure for %s - %s\n",
363 call->name, nt_errstr(error)));
366 static void dcerpc_bh_ndr_pull_failed(struct dcerpc_binding_handle *h,
367 NTSTATUS error,
368 const DATA_BLOB *blob,
369 const struct ndr_interface_call *call)
371 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
372 struct dcerpc_bh_state);
373 const uint32_t num_examples = 20;
374 uint32_t i;
376 DEBUG(2,("Unable to ndr_pull structure for %s - %s\n",
377 call->name, nt_errstr(error)));
379 if (hs->p->conn->packet_log_dir == NULL) return;
381 for (i=0;i<num_examples;i++) {
382 char *name=NULL;
383 asprintf(&name, "%s/rpclog/%s-out.%d",
384 hs->p->conn->packet_log_dir,
385 call->name, i);
386 if (name == NULL) {
387 return;
389 if (!file_exist(name)) {
390 if (file_save(name, blob->data, blob->length)) {
391 DEBUG(10,("Logged rpc packet to %s\n", name));
393 free(name);
394 break;
396 free(name);
400 static NTSTATUS dcerpc_bh_ndr_validate_in(struct dcerpc_binding_handle *h,
401 TALLOC_CTX *mem_ctx,
402 const DATA_BLOB *blob,
403 const struct ndr_interface_call *call)
405 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
406 struct dcerpc_bh_state);
408 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
409 NTSTATUS status;
411 status = dcerpc_ndr_validate_in(hs->p->conn,
412 mem_ctx,
413 *blob,
414 call->struct_size,
415 call->ndr_push,
416 call->ndr_pull);
417 if (!NT_STATUS_IS_OK(status)) {
418 DEBUG(0,("Validation [in] failed for %s - %s\n",
419 call->name, nt_errstr(status)));
420 return status;
424 DEBUG(10,("rpc request data:\n"));
425 dump_data(10, blob->data, blob->length);
427 return NT_STATUS_OK;
430 static NTSTATUS dcerpc_bh_ndr_validate_out(struct dcerpc_binding_handle *h,
431 struct ndr_pull *pull_in,
432 const void *_struct_ptr,
433 const struct ndr_interface_call *call)
435 struct dcerpc_bh_state *hs = dcerpc_binding_handle_data(h,
436 struct dcerpc_bh_state);
437 void *struct_ptr = discard_const(_struct_ptr);
439 DEBUG(10,("rpc reply data:\n"));
440 dump_data(10, pull_in->data, pull_in->data_size);
442 if (pull_in->offset != pull_in->data_size) {
443 DEBUG(0,("Warning! ignoring %u unread bytes at ofs:%u (0x%08X) for %s!\n",
444 pull_in->data_size - pull_in->offset,
445 pull_in->offset, pull_in->offset,
446 call->name));
447 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
448 but it turns out that early versions of NT
449 (specifically NT3.1) add junk onto the end of rpc
450 packets, so if we want to interoperate at all with
451 those versions then we need to ignore this error */
454 if (hs->p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
455 NTSTATUS status;
457 status = dcerpc_ndr_validate_out(hs->p->conn,
458 pull_in,
459 struct_ptr,
460 call->struct_size,
461 call->ndr_push,
462 call->ndr_pull,
463 call->ndr_print);
464 if (!NT_STATUS_IS_OK(status)) {
465 DEBUG(2,("Validation [out] failed for %s - %s\n",
466 call->name, nt_errstr(status)));
467 return status;
471 return NT_STATUS_OK;
474 static const struct dcerpc_binding_handle_ops dcerpc_bh_ops = {
475 .name = "dcerpc",
476 .is_connected = dcerpc_bh_is_connected,
477 .set_timeout = dcerpc_bh_set_timeout,
478 .raw_call_send = dcerpc_bh_raw_call_send,
479 .raw_call_recv = dcerpc_bh_raw_call_recv,
480 .disconnect_send = dcerpc_bh_disconnect_send,
481 .disconnect_recv = dcerpc_bh_disconnect_recv,
483 .push_bigendian = dcerpc_bh_push_bigendian,
484 .ref_alloc = dcerpc_bh_ref_alloc,
485 .use_ndr64 = dcerpc_bh_use_ndr64,
486 .do_ndr_print = dcerpc_bh_do_ndr_print,
487 .ndr_push_failed = dcerpc_bh_ndr_push_failed,
488 .ndr_pull_failed = dcerpc_bh_ndr_pull_failed,
489 .ndr_validate_in = dcerpc_bh_ndr_validate_in,
490 .ndr_validate_out = dcerpc_bh_ndr_validate_out,
493 /* initialise a dcerpc pipe. */
494 struct dcerpc_binding_handle *dcerpc_pipe_binding_handle(struct dcerpc_pipe *p)
496 struct dcerpc_binding_handle *h;
497 struct dcerpc_bh_state *hs;
499 h = dcerpc_binding_handle_create(p,
500 &dcerpc_bh_ops,
501 NULL,
502 NULL, /* TODO */
503 &hs,
504 struct dcerpc_bh_state,
505 __location__);
506 if (h == NULL) {
507 return NULL;
509 hs->p = p;
511 dcerpc_binding_handle_set_sync_ev(h, p->conn->event_ctx);
513 return h;
516 /* initialise a dcerpc pipe. */
517 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
519 struct dcerpc_pipe *p;
521 p = talloc_zero(mem_ctx, struct dcerpc_pipe);
522 if (!p) {
523 return NULL;
526 p->conn = dcerpc_connection_init(p, ev);
527 if (p->conn == NULL) {
528 talloc_free(p);
529 return NULL;
532 p->last_fault_code = 0;
533 p->context_id = 0;
534 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
535 p->binding = NULL;
537 ZERO_STRUCT(p->syntax);
538 ZERO_STRUCT(p->transfer_syntax);
540 if (DEBUGLVL(100)) {
541 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
544 p->binding_handle = dcerpc_pipe_binding_handle(p);
545 if (p->binding_handle == NULL) {
546 talloc_free(p);
547 return NULL;
550 return p;
555 choose the next call id to use
557 static uint32_t next_call_id(struct dcerpc_connection *c)
559 c->call_id++;
560 if (c->call_id == 0) {
561 c->call_id++;
563 return c->call_id;
567 setup for a ndr pull, also setting up any flags from the binding string
569 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
570 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
572 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
574 if (ndr == NULL) return ndr;
576 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
577 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
580 if (c->flags & DCERPC_NDR_REF_ALLOC) {
581 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
584 if (c->flags & DCERPC_NDR64) {
585 ndr->flags |= LIBNDR_FLAG_NDR64;
588 return ndr;
592 parse a data blob into a ncacn_packet structure. This handles both
593 input and output packets
595 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
596 struct ncacn_packet *pkt)
598 struct ndr_pull *ndr;
599 enum ndr_err_code ndr_err;
601 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
602 if (!ndr) {
603 return NT_STATUS_NO_MEMORY;
606 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
607 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
610 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
611 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
612 return ndr_map_error2ntstatus(ndr_err);
615 return NT_STATUS_OK;
619 parse the authentication information on a dcerpc response packet
621 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
622 DATA_BLOB *raw_packet,
623 struct ncacn_packet *pkt)
625 NTSTATUS status;
626 struct dcerpc_auth auth;
627 uint32_t auth_length;
629 if (!c->security_state.auth_info ||
630 !c->security_state.generic_state) {
631 return NT_STATUS_OK;
634 switch (c->security_state.auth_info->auth_level) {
635 case DCERPC_AUTH_LEVEL_PRIVACY:
636 case DCERPC_AUTH_LEVEL_INTEGRITY:
637 break;
639 case DCERPC_AUTH_LEVEL_CONNECT:
640 if (pkt->auth_length != 0) {
641 break;
643 return NT_STATUS_OK;
644 case DCERPC_AUTH_LEVEL_NONE:
645 if (pkt->auth_length != 0) {
646 return NT_STATUS_INVALID_NETWORK_RESPONSE;
648 return NT_STATUS_OK;
650 default:
651 return NT_STATUS_INVALID_LEVEL;
654 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
655 &pkt->u.response.stub_and_verifier,
656 &auth, &auth_length, false);
657 NT_STATUS_NOT_OK_RETURN(status);
659 pkt->u.response.stub_and_verifier.length -= auth_length;
661 /* check signature or unseal the packet */
662 switch (c->security_state.auth_info->auth_level) {
663 case DCERPC_AUTH_LEVEL_PRIVACY:
664 status = gensec_unseal_packet(c->security_state.generic_state,
665 mem_ctx,
666 raw_packet->data + DCERPC_REQUEST_LENGTH,
667 pkt->u.response.stub_and_verifier.length,
668 raw_packet->data,
669 raw_packet->length - auth.credentials.length,
670 &auth.credentials);
671 memcpy(pkt->u.response.stub_and_verifier.data,
672 raw_packet->data + DCERPC_REQUEST_LENGTH,
673 pkt->u.response.stub_and_verifier.length);
674 break;
676 case DCERPC_AUTH_LEVEL_INTEGRITY:
677 status = gensec_check_packet(c->security_state.generic_state,
678 mem_ctx,
679 pkt->u.response.stub_and_verifier.data,
680 pkt->u.response.stub_and_verifier.length,
681 raw_packet->data,
682 raw_packet->length - auth.credentials.length,
683 &auth.credentials);
684 break;
686 case DCERPC_AUTH_LEVEL_CONNECT:
687 /* for now we ignore possible signatures here */
688 status = NT_STATUS_OK;
689 break;
691 default:
692 status = NT_STATUS_INVALID_LEVEL;
693 break;
696 /* remove the indicated amount of padding */
697 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
698 return NT_STATUS_INFO_LENGTH_MISMATCH;
700 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
702 return status;
707 push a dcerpc request packet into a blob, possibly signing it.
709 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
710 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
711 size_t sig_size,
712 struct ncacn_packet *pkt)
714 NTSTATUS status;
715 struct ndr_push *ndr;
716 DATA_BLOB creds2;
717 size_t payload_length;
718 enum ndr_err_code ndr_err;
719 size_t hdr_size = DCERPC_REQUEST_LENGTH;
721 /* non-signed packets are simpler */
722 if (sig_size == 0) {
723 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
726 switch (c->security_state.auth_info->auth_level) {
727 case DCERPC_AUTH_LEVEL_PRIVACY:
728 case DCERPC_AUTH_LEVEL_INTEGRITY:
729 break;
731 case DCERPC_AUTH_LEVEL_CONNECT:
732 /* TODO: let the gensec mech decide if it wants to generate a signature */
733 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
735 case DCERPC_AUTH_LEVEL_NONE:
736 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
738 default:
739 return NT_STATUS_INVALID_LEVEL;
742 ndr = ndr_push_init_ctx(mem_ctx);
743 if (!ndr) {
744 return NT_STATUS_NO_MEMORY;
747 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
748 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
751 if (c->flags & DCERPC_NDR64) {
752 ndr->flags |= LIBNDR_FLAG_NDR64;
755 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
756 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
757 hdr_size += 16;
760 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
761 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
762 return ndr_map_error2ntstatus(ndr_err);
765 /* pad to 16 byte multiple in the payload portion of the
766 packet. This matches what w2k3 does. Note that we can't use
767 ndr_push_align() as that is relative to the start of the
768 whole packet, whereas w2k8 wants it relative to the start
769 of the stub */
770 c->security_state.auth_info->auth_pad_length =
771 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
772 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
773 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
774 return ndr_map_error2ntstatus(ndr_err);
777 payload_length = pkt->u.request.stub_and_verifier.length +
778 c->security_state.auth_info->auth_pad_length;
780 /* we start without signature, it will appended later */
781 c->security_state.auth_info->credentials = data_blob(NULL,0);
783 /* add the auth verifier */
784 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
785 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
786 return ndr_map_error2ntstatus(ndr_err);
789 /* extract the whole packet as a blob */
790 *blob = ndr_push_blob(ndr);
793 * Setup the frag and auth length in the packet buffer.
794 * This is needed if the GENSEC mech does AEAD signing
795 * of the packet headers. The signature itself will be
796 * appended later.
798 dcerpc_set_frag_length(blob, blob->length + sig_size);
799 dcerpc_set_auth_length(blob, sig_size);
801 /* sign or seal the packet */
802 switch (c->security_state.auth_info->auth_level) {
803 case DCERPC_AUTH_LEVEL_PRIVACY:
804 status = gensec_seal_packet(c->security_state.generic_state,
805 mem_ctx,
806 blob->data + hdr_size,
807 payload_length,
808 blob->data,
809 blob->length,
810 &creds2);
811 if (!NT_STATUS_IS_OK(status)) {
812 return status;
814 break;
816 case DCERPC_AUTH_LEVEL_INTEGRITY:
817 status = gensec_sign_packet(c->security_state.generic_state,
818 mem_ctx,
819 blob->data + hdr_size,
820 payload_length,
821 blob->data,
822 blob->length,
823 &creds2);
824 if (!NT_STATUS_IS_OK(status)) {
825 return status;
827 break;
829 default:
830 status = NT_STATUS_INVALID_LEVEL;
831 break;
834 if (creds2.length != sig_size) {
835 /* this means the sig_size estimate for the signature
836 was incorrect. We have to correct the packet
837 sizes. That means we could go over the max fragment
838 length */
839 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
840 (unsigned) creds2.length,
841 (unsigned) sig_size,
842 (unsigned) c->security_state.auth_info->auth_pad_length,
843 (unsigned) pkt->u.request.stub_and_verifier.length));
844 dcerpc_set_frag_length(blob, blob->length + creds2.length);
845 dcerpc_set_auth_length(blob, creds2.length);
848 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
849 return NT_STATUS_NO_MEMORY;
852 return NT_STATUS_OK;
857 fill in the fixed values in a dcerpc header
859 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
861 pkt->rpc_vers = 5;
862 pkt->rpc_vers_minor = 0;
863 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
864 pkt->drep[0] = 0;
865 } else {
866 pkt->drep[0] = DCERPC_DREP_LE;
868 pkt->drep[1] = 0;
869 pkt->drep[2] = 0;
870 pkt->drep[3] = 0;
874 map a bind nak reason to a NTSTATUS
876 static NTSTATUS dcerpc_map_reason(uint16_t reason)
878 switch (reason) {
879 case DCERPC_BIND_REASON_ASYNTAX:
880 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
881 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
882 return NT_STATUS_INVALID_PARAMETER;
884 return NT_STATUS_UNSUCCESSFUL;
888 a bind or alter context has failed
890 static void dcerpc_composite_fail(struct rpc_request *req)
892 struct composite_context *c = talloc_get_type(req->async.private_data,
893 struct composite_context);
894 composite_error(c, req->status);
898 remove requests from the pending or queued queues
900 static int dcerpc_req_dequeue(struct rpc_request *req)
902 switch (req->state) {
903 case RPC_REQUEST_QUEUED:
904 DLIST_REMOVE(req->p->conn->request_queue, req);
905 break;
906 case RPC_REQUEST_PENDING:
907 DLIST_REMOVE(req->p->conn->pending, req);
908 break;
909 case RPC_REQUEST_DONE:
910 break;
912 return 0;
917 mark the dcerpc connection dead. All outstanding requests get an error
919 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
921 if (conn->dead) return;
923 conn->dead = true;
925 if (conn->transport.shutdown_pipe) {
926 conn->transport.shutdown_pipe(conn, status);
929 /* all pending requests get the error */
930 while (conn->pending) {
931 struct rpc_request *req = conn->pending;
932 dcerpc_req_dequeue(req);
933 req->state = RPC_REQUEST_DONE;
934 req->status = status;
935 if (req->async.callback) {
936 req->async.callback(req);
940 talloc_set_destructor(conn, NULL);
941 if (conn->free_skipped) {
942 talloc_free(conn);
947 forward declarations of the recv_data handlers for the types of
948 packets we need to handle
950 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
951 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
954 receive a dcerpc reply from the transport. Here we work out what
955 type of reply it is (normal request, bind or alter context) and
956 dispatch to the appropriate handler
958 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
960 struct ncacn_packet pkt;
962 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
963 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
966 /* the transport may be telling us of a severe error, such as
967 a dropped socket */
968 if (!NT_STATUS_IS_OK(status)) {
969 data_blob_free(blob);
970 dcerpc_connection_dead(conn, status);
971 return;
974 /* parse the basic packet to work out what type of response this is */
975 status = ncacn_pull(conn, blob, blob->data, &pkt);
976 if (!NT_STATUS_IS_OK(status)) {
977 data_blob_free(blob);
978 dcerpc_connection_dead(conn, status);
981 dcerpc_request_recv_data(conn, blob, &pkt);
985 Receive a bind reply from the transport
987 static void dcerpc_bind_recv_handler(struct rpc_request *req,
988 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
990 struct composite_context *c;
991 struct dcerpc_connection *conn;
993 c = talloc_get_type(req->async.private_data, struct composite_context);
995 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
996 DEBUG(2,("dcerpc: bind_nak reason %d\n",
997 pkt->u.bind_nak.reject_reason));
998 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
999 reject_reason));
1000 return;
1003 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
1004 (pkt->u.bind_ack.num_results == 0) ||
1005 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
1006 req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1007 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1008 return;
1011 conn = req->p->conn;
1013 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1014 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
1016 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
1017 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
1018 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
1021 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
1022 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
1023 conn->flags |= DCERPC_HEADER_SIGNING;
1026 /* the bind_ack might contain a reply set of credentials */
1027 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
1028 NTSTATUS status;
1029 uint32_t auth_length;
1030 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
1031 conn->security_state.auth_info, &auth_length, true);
1032 if (!NT_STATUS_IS_OK(status)) {
1033 composite_error(c, status);
1034 return;
1038 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
1040 composite_done(c);
1044 handle timeouts of individual dcerpc requests
1046 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
1047 struct timeval t, void *private_data)
1049 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
1051 if (req->ignore_timeout) {
1052 dcerpc_req_dequeue(req);
1053 req->state = RPC_REQUEST_DONE;
1054 req->status = NT_STATUS_IO_TIMEOUT;
1055 if (req->async.callback) {
1056 req->async.callback(req);
1058 return;
1061 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
1065 send a async dcerpc bind request
1067 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
1068 TALLOC_CTX *mem_ctx,
1069 const struct ndr_syntax_id *syntax,
1070 const struct ndr_syntax_id *transfer_syntax)
1072 struct composite_context *c;
1073 struct ncacn_packet pkt;
1074 DATA_BLOB blob;
1075 struct rpc_request *req;
1077 c = composite_create(mem_ctx,p->conn->event_ctx);
1078 if (c == NULL) return NULL;
1080 c->private_data = p;
1082 p->syntax = *syntax;
1083 p->transfer_syntax = *transfer_syntax;
1085 init_ncacn_hdr(p->conn, &pkt);
1087 pkt.ptype = DCERPC_PKT_BIND;
1088 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1089 pkt.call_id = p->conn->call_id;
1090 pkt.auth_length = 0;
1092 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1093 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1096 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1097 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1100 pkt.u.bind.max_xmit_frag = 5840;
1101 pkt.u.bind.max_recv_frag = 5840;
1102 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
1103 pkt.u.bind.num_contexts = 1;
1104 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1105 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
1106 pkt.u.bind.ctx_list[0].context_id = p->context_id;
1107 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
1108 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
1109 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1110 pkt.u.bind.auth_info = data_blob(NULL, 0);
1112 /* construct the NDR form of the packet */
1113 c->status = ncacn_push_auth(&blob, c, &pkt,
1114 p->conn->security_state.auth_info);
1115 if (!composite_is_ok(c)) return c;
1117 p->conn->transport.recv_data = dcerpc_recv_data;
1120 * we allocate a dcerpc_request so we can be in the same
1121 * request queue as normal requests
1123 req = talloc_zero(c, struct rpc_request);
1124 if (composite_nomem(req, c)) return c;
1126 req->state = RPC_REQUEST_PENDING;
1127 req->call_id = pkt.call_id;
1128 req->async.private_data = c;
1129 req->async.callback = dcerpc_composite_fail;
1130 req->p = p;
1131 req->recv_handler = dcerpc_bind_recv_handler;
1132 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1133 talloc_set_destructor(req, dcerpc_req_dequeue);
1135 c->status = p->conn->transport.send_request(p->conn, &blob,
1136 true);
1137 if (!composite_is_ok(c)) return c;
1139 event_add_timed(c->event_ctx, req,
1140 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1141 dcerpc_timeout_handler, req);
1143 return c;
1147 recv side of async dcerpc bind request
1149 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
1151 NTSTATUS result = composite_wait(ctx);
1152 talloc_free(ctx);
1153 return result;
1157 perform a continued bind (and auth3)
1159 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
1160 TALLOC_CTX *mem_ctx)
1162 struct ncacn_packet pkt;
1163 NTSTATUS status;
1164 DATA_BLOB blob;
1166 init_ncacn_hdr(p->conn, &pkt);
1168 pkt.ptype = DCERPC_PKT_AUTH3;
1169 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1170 pkt.call_id = next_call_id(p->conn);
1171 pkt.auth_length = 0;
1172 pkt.u.auth3.auth_info = data_blob(NULL, 0);
1174 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1175 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1178 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1179 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1182 /* construct the NDR form of the packet */
1183 status = ncacn_push_auth(&blob, mem_ctx,
1184 &pkt,
1185 p->conn->security_state.auth_info);
1186 if (!NT_STATUS_IS_OK(status)) {
1187 return status;
1190 /* send it on its way */
1191 status = p->conn->transport.send_request(p->conn, &blob, false);
1192 if (!NT_STATUS_IS_OK(status)) {
1193 return status;
1196 return NT_STATUS_OK;
1201 process a fragment received from the transport layer during a
1202 request
1204 This function frees the data
1206 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
1207 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1209 struct rpc_request *req;
1210 unsigned int length;
1211 NTSTATUS status = NT_STATUS_OK;
1214 if this is an authenticated connection then parse and check
1215 the auth info. We have to do this before finding the
1216 matching packet, as the request structure might have been
1217 removed due to a timeout, but if it has been we still need
1218 to run the auth routines so that we don't get the sign/seal
1219 info out of step with the server
1221 if (c->security_state.auth_info && c->security_state.generic_state &&
1222 pkt->ptype == DCERPC_PKT_RESPONSE) {
1223 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
1226 /* find the matching request */
1227 for (req=c->pending;req;req=req->next) {
1228 if (pkt->call_id == req->call_id) break;
1231 #if 0
1232 /* useful for testing certain vendors RPC servers */
1233 if (req == NULL && c->pending && pkt->call_id == 0) {
1234 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
1235 req = c->pending;
1237 #endif
1239 if (req == NULL) {
1240 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
1241 data_blob_free(raw_packet);
1242 return;
1245 talloc_steal(req, raw_packet->data);
1247 if (req->recv_handler != NULL) {
1248 dcerpc_req_dequeue(req);
1249 req->state = RPC_REQUEST_DONE;
1250 req->recv_handler(req, raw_packet, pkt);
1251 return;
1254 if (pkt->ptype == DCERPC_PKT_FAULT) {
1255 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1256 req->fault_code = pkt->u.fault.status;
1257 req->status = NT_STATUS_NET_WRITE_FAULT;
1258 goto req_done;
1261 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
1262 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
1263 (int)pkt->ptype));
1264 req->fault_code = DCERPC_FAULT_OTHER;
1265 req->status = NT_STATUS_NET_WRITE_FAULT;
1266 goto req_done;
1269 /* now check the status from the auth routines, and if it failed then fail
1270 this request accordingly */
1271 if (!NT_STATUS_IS_OK(status)) {
1272 req->status = status;
1273 goto req_done;
1276 length = pkt->u.response.stub_and_verifier.length;
1278 if (length > 0) {
1279 req->payload.data = talloc_realloc(req,
1280 req->payload.data,
1281 uint8_t,
1282 req->payload.length + length);
1283 if (!req->payload.data) {
1284 req->status = NT_STATUS_NO_MEMORY;
1285 goto req_done;
1287 memcpy(req->payload.data+req->payload.length,
1288 pkt->u.response.stub_and_verifier.data, length);
1289 req->payload.length += length;
1292 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
1293 c->transport.send_read(c);
1294 return;
1297 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
1298 req->flags |= DCERPC_PULL_BIGENDIAN;
1299 } else {
1300 req->flags &= ~DCERPC_PULL_BIGENDIAN;
1304 req_done:
1305 /* we've got the full payload */
1306 req->state = RPC_REQUEST_DONE;
1307 DLIST_REMOVE(c->pending, req);
1309 if (c->request_queue != NULL) {
1310 /* We have to look at shipping further requests before calling
1311 * the async function, that one might close the pipe */
1312 dcerpc_ship_next_request(c);
1315 if (req->async.callback) {
1316 req->async.callback(req);
1321 perform the send side of a async dcerpc request
1323 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
1324 const struct GUID *object,
1325 uint16_t opnum,
1326 DATA_BLOB *stub_data)
1328 struct rpc_request *req;
1330 p->conn->transport.recv_data = dcerpc_recv_data;
1332 req = talloc(p, struct rpc_request);
1333 if (req == NULL) {
1334 return NULL;
1337 req->p = p;
1338 req->call_id = next_call_id(p->conn);
1339 req->status = NT_STATUS_OK;
1340 req->state = RPC_REQUEST_QUEUED;
1341 req->payload = data_blob(NULL, 0);
1342 req->flags = 0;
1343 req->fault_code = 0;
1344 req->ignore_timeout = false;
1345 req->async.callback = NULL;
1346 req->async.private_data = NULL;
1347 req->recv_handler = NULL;
1349 if (object != NULL) {
1350 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
1351 if (req->object == NULL) {
1352 talloc_free(req);
1353 return NULL;
1355 } else {
1356 req->object = NULL;
1359 req->opnum = opnum;
1360 req->request_data.length = stub_data->length;
1361 req->request_data.data = talloc_reference(req, stub_data->data);
1362 if (req->request_data.length && req->request_data.data == NULL) {
1363 return NULL;
1366 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
1367 talloc_set_destructor(req, dcerpc_req_dequeue);
1369 dcerpc_ship_next_request(p->conn);
1371 if (p->request_timeout) {
1372 event_add_timed(dcerpc_event_context(p), req,
1373 timeval_current_ofs(p->request_timeout, 0),
1374 dcerpc_timeout_handler, req);
1377 return req;
1381 Send a request using the transport
1384 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1386 struct rpc_request *req;
1387 struct dcerpc_pipe *p;
1388 DATA_BLOB *stub_data;
1389 struct ncacn_packet pkt;
1390 DATA_BLOB blob;
1391 uint32_t remaining, chunk_size;
1392 bool first_packet = true;
1393 size_t sig_size = 0;
1394 bool need_async = false;
1396 req = c->request_queue;
1397 if (req == NULL) {
1398 return;
1401 p = req->p;
1402 stub_data = &req->request_data;
1404 if (c->pending) {
1405 need_async = true;
1408 DLIST_REMOVE(c->request_queue, req);
1409 DLIST_ADD(c->pending, req);
1410 req->state = RPC_REQUEST_PENDING;
1412 init_ncacn_hdr(p->conn, &pkt);
1414 remaining = stub_data->length;
1416 /* we can write a full max_recv_frag size, minus the dcerpc
1417 request header size */
1418 chunk_size = p->conn->srv_max_recv_frag;
1419 chunk_size -= DCERPC_REQUEST_LENGTH;
1420 if (c->security_state.auth_info &&
1421 c->security_state.generic_state) {
1422 sig_size = gensec_sig_size(c->security_state.generic_state,
1423 p->conn->srv_max_recv_frag);
1424 if (sig_size) {
1425 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1426 chunk_size -= sig_size;
1429 chunk_size -= (chunk_size % 16);
1431 pkt.ptype = DCERPC_PKT_REQUEST;
1432 pkt.call_id = req->call_id;
1433 pkt.auth_length = 0;
1434 pkt.pfc_flags = 0;
1435 pkt.u.request.alloc_hint = remaining;
1436 pkt.u.request.context_id = p->context_id;
1437 pkt.u.request.opnum = req->opnum;
1439 if (req->object) {
1440 pkt.u.request.object.object = *req->object;
1441 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1442 chunk_size -= ndr_size_GUID(req->object,0);
1445 /* we send a series of pdus without waiting for a reply */
1446 while (remaining > 0 || first_packet) {
1447 uint32_t chunk = MIN(chunk_size, remaining);
1448 bool last_frag = false;
1449 bool do_trans = false;
1451 first_packet = false;
1452 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1454 if (remaining == stub_data->length) {
1455 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1457 if (chunk == remaining) {
1458 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1459 last_frag = true;
1462 pkt.u.request.stub_and_verifier.data = stub_data->data +
1463 (stub_data->length - remaining);
1464 pkt.u.request.stub_and_verifier.length = chunk;
1466 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1467 if (!NT_STATUS_IS_OK(req->status)) {
1468 req->state = RPC_REQUEST_DONE;
1469 DLIST_REMOVE(p->conn->pending, req);
1470 return;
1473 if (last_frag && !need_async) {
1474 do_trans = true;
1477 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1478 if (!NT_STATUS_IS_OK(req->status)) {
1479 req->state = RPC_REQUEST_DONE;
1480 DLIST_REMOVE(p->conn->pending, req);
1481 return;
1484 if (last_frag && !do_trans) {
1485 req->status = p->conn->transport.send_read(p->conn);
1486 if (!NT_STATUS_IS_OK(req->status)) {
1487 req->state = RPC_REQUEST_DONE;
1488 DLIST_REMOVE(p->conn->pending, req);
1489 return;
1493 remaining -= chunk;
1498 return the event context for a dcerpc pipe
1499 used by callers who wish to operate asynchronously
1501 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1503 return p->conn->event_ctx;
1509 perform the receive side of a async dcerpc request
1511 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1512 TALLOC_CTX *mem_ctx,
1513 DATA_BLOB *stub_data)
1515 NTSTATUS status;
1517 while (req->state != RPC_REQUEST_DONE) {
1518 struct tevent_context *ctx = dcerpc_event_context(req->p);
1519 if (event_loop_once(ctx) != 0) {
1520 return NT_STATUS_CONNECTION_DISCONNECTED;
1523 *stub_data = req->payload;
1524 status = req->status;
1525 if (stub_data->data) {
1526 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1528 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1529 req->p->last_fault_code = req->fault_code;
1531 talloc_unlink(talloc_parent(req), req);
1532 return status;
1536 perform a full request/response pair on a dcerpc pipe
1538 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1539 struct GUID *object,
1540 uint16_t opnum,
1541 TALLOC_CTX *mem_ctx,
1542 DATA_BLOB *stub_data_in,
1543 DATA_BLOB *stub_data_out)
1545 struct rpc_request *req;
1547 req = dcerpc_request_send(p, object, opnum, stub_data_in);
1548 if (req == NULL) {
1549 return NT_STATUS_NO_MEMORY;
1552 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1557 this is a paranoid NDR validator. For every packet we push onto the wire
1558 we pull it back again, then push it again. Then we compare the raw NDR data
1559 for that to the NDR we initially generated. If they don't match then we know
1560 we must have a bug in either the pull or push side of our code
1562 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1563 TALLOC_CTX *mem_ctx,
1564 DATA_BLOB blob,
1565 size_t struct_size,
1566 ndr_push_flags_fn_t ndr_push,
1567 ndr_pull_flags_fn_t ndr_pull)
1569 void *st;
1570 struct ndr_pull *pull;
1571 struct ndr_push *push;
1572 DATA_BLOB blob2;
1573 enum ndr_err_code ndr_err;
1575 st = talloc_size(mem_ctx, struct_size);
1576 if (!st) {
1577 return NT_STATUS_NO_MEMORY;
1580 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1581 if (!pull) {
1582 return NT_STATUS_NO_MEMORY;
1584 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1586 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1587 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1590 if (c->flags & DCERPC_NDR64) {
1591 pull->flags |= LIBNDR_FLAG_NDR64;
1594 ndr_err = ndr_pull(pull, NDR_IN, st);
1595 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1596 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1597 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1598 "failed input validation pull - %s",
1599 nt_errstr(status));
1600 return ndr_map_error2ntstatus(ndr_err);
1603 push = ndr_push_init_ctx(mem_ctx);
1604 if (!push) {
1605 return NT_STATUS_NO_MEMORY;
1608 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1609 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1612 if (c->flags & DCERPC_NDR64) {
1613 push->flags |= LIBNDR_FLAG_NDR64;
1616 ndr_err = ndr_push(push, NDR_IN, st);
1617 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1618 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1619 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1620 "failed input validation push - %s",
1621 nt_errstr(status));
1622 return ndr_map_error2ntstatus(ndr_err);
1625 blob2 = ndr_push_blob(push);
1627 if (data_blob_cmp(&blob, &blob2) != 0) {
1628 DEBUG(3,("original:\n"));
1629 dump_data(3, blob.data, blob.length);
1630 DEBUG(3,("secondary:\n"));
1631 dump_data(3, blob2.data, blob2.length);
1632 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1633 "failed input validation blobs doesn't match");
1634 return ndr_map_error2ntstatus(ndr_err);
1637 return NT_STATUS_OK;
1641 this is a paranoid NDR input validator. For every packet we pull
1642 from the wire we push it back again then pull and push it
1643 again. Then we compare the raw NDR data for that to the NDR we
1644 initially generated. If they don't match then we know we must have a
1645 bug in either the pull or push side of our code
1647 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1648 struct ndr_pull *pull_in,
1649 void *struct_ptr,
1650 size_t struct_size,
1651 ndr_push_flags_fn_t ndr_push,
1652 ndr_pull_flags_fn_t ndr_pull,
1653 ndr_print_function_t ndr_print)
1655 void *st;
1656 struct ndr_pull *pull;
1657 struct ndr_push *push;
1658 DATA_BLOB blob, blob2;
1659 TALLOC_CTX *mem_ctx = pull_in;
1660 char *s1, *s2;
1661 enum ndr_err_code ndr_err;
1663 st = talloc_size(mem_ctx, struct_size);
1664 if (!st) {
1665 return NT_STATUS_NO_MEMORY;
1667 memcpy(st, struct_ptr, struct_size);
1669 push = ndr_push_init_ctx(mem_ctx);
1670 if (!push) {
1671 return NT_STATUS_NO_MEMORY;
1674 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1675 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1676 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1677 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1678 "failed output validation push - %s",
1679 nt_errstr(status));
1680 return ndr_map_error2ntstatus(ndr_err);
1683 blob = ndr_push_blob(push);
1685 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1686 if (!pull) {
1687 return NT_STATUS_NO_MEMORY;
1690 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1691 ndr_err = ndr_pull(pull, NDR_OUT, st);
1692 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1693 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1694 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1695 "failed output validation pull - %s",
1696 nt_errstr(status));
1697 return ndr_map_error2ntstatus(ndr_err);
1700 push = ndr_push_init_ctx(mem_ctx);
1701 if (!push) {
1702 return NT_STATUS_NO_MEMORY;
1705 ndr_err = ndr_push(push, NDR_OUT, st);
1706 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1707 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1708 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1709 "failed output validation push2 - %s",
1710 nt_errstr(status));
1711 return ndr_map_error2ntstatus(ndr_err);
1714 blob2 = ndr_push_blob(push);
1716 if (data_blob_cmp(&blob, &blob2) != 0) {
1717 DEBUG(3,("original:\n"));
1718 dump_data(3, blob.data, blob.length);
1719 DEBUG(3,("secondary:\n"));
1720 dump_data(3, blob2.data, blob2.length);
1721 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1722 "failed output validation blobs doesn't match");
1723 return ndr_map_error2ntstatus(ndr_err);
1726 /* this checks the printed forms of the two structures, which effectively
1727 tests all of the value() attributes */
1728 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1729 NDR_OUT, struct_ptr);
1730 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1731 NDR_OUT, st);
1732 if (strcmp(s1, s2) != 0) {
1733 #if 1
1734 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1735 #else
1736 /* this is sometimes useful */
1737 printf("VALIDATE ERROR\n");
1738 file_save("wire.dat", s1, strlen(s1));
1739 file_save("gen.dat", s2, strlen(s2));
1740 system("diff -u wire.dat gen.dat");
1741 #endif
1742 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1743 "failed output validation strings doesn't match");
1744 return ndr_map_error2ntstatus(ndr_err);
1747 return NT_STATUS_OK;
1752 send a rpc request given a dcerpc_call structure
1754 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1755 const struct GUID *object,
1756 const struct ndr_interface_table *table,
1757 uint32_t opnum,
1758 bool async,
1759 TALLOC_CTX *mem_ctx,
1760 void *r)
1762 const struct ndr_interface_call *call;
1763 struct ndr_push *push;
1764 NTSTATUS status;
1765 DATA_BLOB request;
1766 struct rpc_request *req;
1767 enum ndr_err_code ndr_err;
1769 call = &table->calls[opnum];
1771 /* setup for a ndr_push_* call */
1772 push = ndr_push_init_ctx(mem_ctx);
1773 if (!push) {
1774 return NULL;
1777 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1778 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1781 if (p->conn->flags & DCERPC_NDR64) {
1782 push->flags |= LIBNDR_FLAG_NDR64;
1785 /* push the structure into a blob */
1786 ndr_err = call->ndr_push(push, NDR_IN, r);
1787 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1788 status = ndr_map_error2ntstatus(ndr_err);
1789 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1790 nt_errstr(status)));
1791 talloc_free(push);
1792 return NULL;
1795 /* retrieve the blob */
1796 request = ndr_push_blob(push);
1798 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1799 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1800 call->ndr_push, call->ndr_pull);
1801 if (!NT_STATUS_IS_OK(status)) {
1802 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1803 nt_errstr(status)));
1804 talloc_free(push);
1805 return NULL;
1809 DEBUG(10,("rpc request data:\n"));
1810 dump_data(10, request.data, request.length);
1812 /* make the actual dcerpc request */
1813 req = dcerpc_request_send(p, object, opnum, &request);
1815 if (req != NULL) {
1816 req->ndr.table = table;
1817 req->ndr.opnum = opnum;
1818 req->ndr.struct_ptr = r;
1819 req->ndr.mem_ctx = mem_ctx;
1822 talloc_free(push);
1824 return req;
1828 receive the answer from a dcerpc_ndr_request_send()
1830 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1832 struct dcerpc_pipe *p = req->p;
1833 NTSTATUS status;
1834 DATA_BLOB response;
1835 struct ndr_pull *pull;
1836 unsigned int flags;
1837 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1838 void *r = req->ndr.struct_ptr;
1839 uint32_t opnum = req->ndr.opnum;
1840 const struct ndr_interface_table *table = req->ndr.table;
1841 const struct ndr_interface_call *call = &table->calls[opnum];
1842 enum ndr_err_code ndr_err;
1844 /* make sure the recv code doesn't free the request, as we
1845 need to grab the flags element before it is freed */
1846 if (talloc_reference(p, req) == NULL) {
1847 return NT_STATUS_NO_MEMORY;
1850 status = dcerpc_request_recv(req, mem_ctx, &response);
1851 if (!NT_STATUS_IS_OK(status)) {
1852 talloc_unlink(p, req);
1853 return status;
1856 flags = req->flags;
1858 /* prepare for ndr_pull_* */
1859 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1860 if (!pull) {
1861 talloc_unlink(p, req);
1862 return NT_STATUS_NO_MEMORY;
1865 if (pull->data) {
1866 pull->data = talloc_steal(pull, pull->data);
1868 talloc_unlink(p, req);
1870 if (flags & DCERPC_PULL_BIGENDIAN) {
1871 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1874 DEBUG(10,("rpc reply data:\n"));
1875 dump_data(10, pull->data, pull->data_size);
1877 /* pull the structure from the blob */
1878 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1879 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1880 status = ndr_map_error2ntstatus(ndr_err);
1881 dcerpc_log_packet(p->conn->packet_log_dir,
1882 table, opnum, NDR_OUT,
1883 &response);
1884 return status;
1887 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1888 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1889 call->ndr_push, call->ndr_pull,
1890 call->ndr_print);
1891 if (!NT_STATUS_IS_OK(status)) {
1892 dcerpc_log_packet(p->conn->packet_log_dir,
1893 table, opnum, NDR_OUT,
1894 &response);
1895 return status;
1899 if (pull->offset != pull->data_size) {
1900 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1901 pull->data_size - pull->offset));
1902 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1903 but it turns out that early versions of NT
1904 (specifically NT3.1) add junk onto the end of rpc
1905 packets, so if we want to interoperate at all with
1906 those versions then we need to ignore this error */
1909 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1911 return NT_STATUS_OK;
1916 a useful helper function for synchronous rpc requests
1918 this can be used when you have ndr push/pull functions in the
1919 standard format
1921 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1922 const struct GUID *object,
1923 const struct ndr_interface_table *table,
1924 uint32_t opnum,
1925 TALLOC_CTX *mem_ctx,
1926 void *r)
1928 struct rpc_request *req;
1930 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1931 if (req == NULL) {
1932 return NT_STATUS_NO_MEMORY;
1935 return dcerpc_ndr_request_recv(req);
1940 a useful function for retrieving the server name we connected to
1942 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1944 if (!p->conn->transport.target_hostname) {
1945 if (!p->conn->transport.peer_name) {
1946 return "";
1948 return p->conn->transport.peer_name(p->conn);
1950 return p->conn->transport.target_hostname(p->conn);
1955 get the dcerpc auth_level for a open connection
1957 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1959 uint8_t auth_level;
1961 if (c->flags & DCERPC_SEAL) {
1962 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1963 } else if (c->flags & DCERPC_SIGN) {
1964 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1965 } else if (c->flags & DCERPC_CONNECT) {
1966 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1967 } else {
1968 auth_level = DCERPC_AUTH_LEVEL_NONE;
1970 return auth_level;
1974 Receive an alter reply from the transport
1976 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1977 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1979 struct composite_context *c;
1980 struct dcerpc_pipe *recv_pipe;
1982 c = talloc_get_type(req->async.private_data, struct composite_context);
1983 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1985 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1986 pkt->u.alter_resp.num_results == 1 &&
1987 pkt->u.alter_resp.ctx_list[0].result != 0) {
1988 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1989 pkt->u.alter_resp.ctx_list[0].reason));
1990 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1991 return;
1994 if (pkt->ptype == DCERPC_PKT_FAULT) {
1995 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1996 recv_pipe->last_fault_code = pkt->u.fault.status;
1997 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1998 return;
2001 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
2002 pkt->u.alter_resp.num_results == 0 ||
2003 pkt->u.alter_resp.ctx_list[0].result != 0) {
2004 recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
2005 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
2006 return;
2009 /* the alter_resp might contain a reply set of credentials */
2010 if (recv_pipe->conn->security_state.auth_info &&
2011 pkt->u.alter_resp.auth_info.length) {
2012 struct dcerpc_connection *conn = recv_pipe->conn;
2013 NTSTATUS status;
2014 uint32_t auth_length;
2015 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
2016 conn->security_state.auth_info, &auth_length, true);
2017 if (!NT_STATUS_IS_OK(status)) {
2018 composite_error(c, status);
2019 return;
2023 composite_done(c);
2027 send a dcerpc alter_context request
2029 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
2030 TALLOC_CTX *mem_ctx,
2031 const struct ndr_syntax_id *syntax,
2032 const struct ndr_syntax_id *transfer_syntax)
2034 struct composite_context *c;
2035 struct ncacn_packet pkt;
2036 DATA_BLOB blob;
2037 struct rpc_request *req;
2039 c = composite_create(mem_ctx, p->conn->event_ctx);
2040 if (c == NULL) return NULL;
2042 c->private_data = p;
2044 p->syntax = *syntax;
2045 p->transfer_syntax = *transfer_syntax;
2047 init_ncacn_hdr(p->conn, &pkt);
2049 pkt.ptype = DCERPC_PKT_ALTER;
2050 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
2051 pkt.call_id = p->conn->call_id;
2052 pkt.auth_length = 0;
2054 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
2055 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
2058 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
2059 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
2062 pkt.u.alter.max_xmit_frag = 5840;
2063 pkt.u.alter.max_recv_frag = 5840;
2064 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
2065 pkt.u.alter.num_contexts = 1;
2066 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
2067 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
2068 pkt.u.alter.ctx_list[0].context_id = p->context_id;
2069 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
2070 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
2071 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
2072 pkt.u.alter.auth_info = data_blob(NULL, 0);
2074 /* construct the NDR form of the packet */
2075 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
2076 p->conn->security_state.auth_info);
2077 if (!composite_is_ok(c)) return c;
2079 p->conn->transport.recv_data = dcerpc_recv_data;
2082 * we allocate a dcerpc_request so we can be in the same
2083 * request queue as normal requests
2085 req = talloc_zero(c, struct rpc_request);
2086 if (composite_nomem(req, c)) return c;
2088 req->state = RPC_REQUEST_PENDING;
2089 req->call_id = pkt.call_id;
2090 req->async.private_data = c;
2091 req->async.callback = dcerpc_composite_fail;
2092 req->p = p;
2093 req->recv_handler = dcerpc_alter_recv_handler;
2094 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
2095 talloc_set_destructor(req, dcerpc_req_dequeue);
2097 c->status = p->conn->transport.send_request(p->conn, &blob, true);
2098 if (!composite_is_ok(c)) return c;
2100 event_add_timed(c->event_ctx, req,
2101 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
2102 dcerpc_timeout_handler, req);
2104 return c;
2107 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
2109 NTSTATUS result = composite_wait(ctx);
2110 talloc_free(ctx);
2111 return result;
2115 send a dcerpc alter_context request
2117 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
2118 TALLOC_CTX *mem_ctx,
2119 const struct ndr_syntax_id *syntax,
2120 const struct ndr_syntax_id *transfer_syntax)
2122 struct composite_context *creq;
2123 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
2124 return dcerpc_alter_context_recv(creq);