s4-repl: add a debug to make it easier to monitor replication
[Samba/aatanasov.git] / source4 / librpc / rpc / dcerpc.c
blob819edc8eaaf790f1421797a44ba8229ce9e3411a
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"
34 _PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
36 return gensec_init(lp_ctx);
39 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
45 if (conn->dead) {
46 conn->free_skipped = true;
47 return -1;
49 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
50 return 0;
54 /* initialise a dcerpc connection.
55 the event context is optional
57 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
58 struct tevent_context *ev,
59 struct smb_iconv_convenience *ic)
61 struct dcerpc_connection *c;
63 c = talloc_zero(mem_ctx, struct dcerpc_connection);
64 if (!c) {
65 return NULL;
68 c->iconv_convenience = talloc_reference(c, ic);
70 c->event_ctx = ev;
72 if (c->event_ctx == NULL) {
73 talloc_free(c);
74 return NULL;
77 c->call_id = 1;
78 c->security_state.auth_info = NULL;
79 c->security_state.session_key = dcerpc_generic_session_key;
80 c->security_state.generic_state = NULL;
81 c->binding_string = NULL;
82 c->flags = 0;
83 c->srv_max_xmit_frag = 0;
84 c->srv_max_recv_frag = 0;
85 c->pending = NULL;
87 talloc_set_destructor(c, dcerpc_connection_destructor);
89 return c;
92 /* initialise a dcerpc pipe. */
93 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
94 struct smb_iconv_convenience *ic)
96 struct dcerpc_pipe *p;
98 p = talloc(mem_ctx, struct dcerpc_pipe);
99 if (!p) {
100 return NULL;
103 p->conn = dcerpc_connection_init(p, ev, ic);
104 if (p->conn == NULL) {
105 talloc_free(p);
106 return NULL;
109 p->last_fault_code = 0;
110 p->context_id = 0;
111 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
112 p->binding = NULL;
114 ZERO_STRUCT(p->syntax);
115 ZERO_STRUCT(p->transfer_syntax);
117 if (DEBUGLVL(100)) {
118 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
121 return p;
126 choose the next call id to use
128 static uint32_t next_call_id(struct dcerpc_connection *c)
130 c->call_id++;
131 if (c->call_id == 0) {
132 c->call_id++;
134 return c->call_id;
137 /* we need to be able to get/set the fragment length without doing a full
138 decode */
139 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
141 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
142 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
143 } else {
144 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
148 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
150 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
151 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
152 } else {
153 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
157 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
159 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
160 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
161 } else {
162 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
168 setup for a ndr pull, also setting up any flags from the binding string
170 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
171 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
173 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
175 if (ndr == NULL) return ndr;
177 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
178 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
181 if (c->flags & DCERPC_NDR_REF_ALLOC) {
182 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
185 return ndr;
189 parse a data blob into a ncacn_packet structure. This handles both
190 input and output packets
192 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
193 struct ncacn_packet *pkt)
195 struct ndr_pull *ndr;
196 enum ndr_err_code ndr_err;
198 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
199 if (!ndr) {
200 return NT_STATUS_NO_MEMORY;
203 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
204 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
207 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
209 return ndr_map_error2ntstatus(ndr_err);
212 return NT_STATUS_OK;
216 parse the authentication information on a dcerpc response packet
218 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
219 DATA_BLOB *raw_packet,
220 struct ncacn_packet *pkt)
222 struct ndr_pull *ndr;
223 NTSTATUS status;
224 struct dcerpc_auth auth;
225 DATA_BLOB auth_blob;
226 enum ndr_err_code ndr_err;
228 if (!c->security_state.auth_info ||
229 !c->security_state.generic_state) {
230 return NT_STATUS_OK;
233 switch (c->security_state.auth_info->auth_level) {
234 case DCERPC_AUTH_LEVEL_PRIVACY:
235 case DCERPC_AUTH_LEVEL_INTEGRITY:
236 break;
238 case DCERPC_AUTH_LEVEL_CONNECT:
239 if (pkt->auth_length != 0) {
240 break;
242 return NT_STATUS_OK;
243 case DCERPC_AUTH_LEVEL_NONE:
244 if (pkt->auth_length != 0) {
245 return NT_STATUS_INVALID_NETWORK_RESPONSE;
247 return NT_STATUS_OK;
249 default:
250 return NT_STATUS_INVALID_LEVEL;
253 auth_blob.length = 8 + pkt->auth_length;
255 /* check for a valid length */
256 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
257 return NT_STATUS_INFO_LENGTH_MISMATCH;
260 auth_blob.data =
261 pkt->u.response.stub_and_verifier.data +
262 pkt->u.response.stub_and_verifier.length - auth_blob.length;
263 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
265 /* pull the auth structure */
266 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
267 if (!ndr) {
268 return NT_STATUS_NO_MEMORY;
271 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
272 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
275 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
276 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
277 return ndr_map_error2ntstatus(ndr_err);
279 status = NT_STATUS_OK;
281 /* check signature or unseal the packet */
282 switch (c->security_state.auth_info->auth_level) {
283 case DCERPC_AUTH_LEVEL_PRIVACY:
284 status = gensec_unseal_packet(c->security_state.generic_state,
285 mem_ctx,
286 raw_packet->data + DCERPC_REQUEST_LENGTH,
287 pkt->u.response.stub_and_verifier.length,
288 raw_packet->data,
289 raw_packet->length - auth.credentials.length,
290 &auth.credentials);
291 memcpy(pkt->u.response.stub_and_verifier.data,
292 raw_packet->data + DCERPC_REQUEST_LENGTH,
293 pkt->u.response.stub_and_verifier.length);
294 break;
296 case DCERPC_AUTH_LEVEL_INTEGRITY:
297 status = gensec_check_packet(c->security_state.generic_state,
298 mem_ctx,
299 pkt->u.response.stub_and_verifier.data,
300 pkt->u.response.stub_and_verifier.length,
301 raw_packet->data,
302 raw_packet->length - auth.credentials.length,
303 &auth.credentials);
304 break;
306 case DCERPC_AUTH_LEVEL_CONNECT:
307 /* for now we ignore possible signatures here */
308 status = NT_STATUS_OK;
309 break;
311 default:
312 status = NT_STATUS_INVALID_LEVEL;
313 break;
316 /* remove the indicated amount of paddiing */
317 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
318 return NT_STATUS_INFO_LENGTH_MISMATCH;
320 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
322 return status;
327 push a dcerpc request packet into a blob, possibly signing it.
329 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
330 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
331 size_t sig_size,
332 struct ncacn_packet *pkt)
334 NTSTATUS status;
335 struct ndr_push *ndr;
336 DATA_BLOB creds2;
337 size_t payload_length;
338 enum ndr_err_code ndr_err;
339 size_t hdr_size = DCERPC_REQUEST_LENGTH;
341 /* non-signed packets are simpler */
342 if (sig_size == 0) {
343 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
346 switch (c->security_state.auth_info->auth_level) {
347 case DCERPC_AUTH_LEVEL_PRIVACY:
348 case DCERPC_AUTH_LEVEL_INTEGRITY:
349 break;
351 case DCERPC_AUTH_LEVEL_CONNECT:
352 /* TODO: let the gensec mech decide if it wants to generate a signature */
353 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
355 case DCERPC_AUTH_LEVEL_NONE:
356 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
358 default:
359 return NT_STATUS_INVALID_LEVEL;
362 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
363 if (!ndr) {
364 return NT_STATUS_NO_MEMORY;
367 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
368 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
371 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
372 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
373 hdr_size += 16;
376 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
377 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
378 return ndr_map_error2ntstatus(ndr_err);
380 status = NT_STATUS_OK;
382 /* pad to 16 byte multiple in the payload portion of the
383 packet. This matches what w2k3 does */
384 c->security_state.auth_info->auth_pad_length =
385 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
386 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
387 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
388 return ndr_map_error2ntstatus(ndr_err);
390 status = NT_STATUS_OK;
392 payload_length = pkt->u.request.stub_and_verifier.length +
393 c->security_state.auth_info->auth_pad_length;
395 /* we start without signature, it will appended later */
396 c->security_state.auth_info->credentials = data_blob(NULL,0);
398 /* add the auth verifier */
399 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
400 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
401 return ndr_map_error2ntstatus(ndr_err);
403 status = NT_STATUS_OK;
405 /* extract the whole packet as a blob */
406 *blob = ndr_push_blob(ndr);
409 * Setup the frag and auth length in the packet buffer.
410 * This is needed if the GENSEC mech does AEAD signing
411 * of the packet headers. The signature itself will be
412 * appended later.
414 dcerpc_set_frag_length(blob, blob->length + sig_size);
415 dcerpc_set_auth_length(blob, sig_size);
417 /* sign or seal the packet */
418 switch (c->security_state.auth_info->auth_level) {
419 case DCERPC_AUTH_LEVEL_PRIVACY:
420 status = gensec_seal_packet(c->security_state.generic_state,
421 mem_ctx,
422 blob->data + hdr_size,
423 payload_length,
424 blob->data,
425 blob->length,
426 &creds2);
427 if (!NT_STATUS_IS_OK(status)) {
428 return status;
430 break;
432 case DCERPC_AUTH_LEVEL_INTEGRITY:
433 status = gensec_sign_packet(c->security_state.generic_state,
434 mem_ctx,
435 blob->data + hdr_size,
436 payload_length,
437 blob->data,
438 blob->length,
439 &creds2);
440 if (!NT_STATUS_IS_OK(status)) {
441 return status;
443 break;
445 default:
446 status = NT_STATUS_INVALID_LEVEL;
447 break;
450 if (creds2.length != sig_size) {
451 DEBUG(0,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
452 creds2.length, (uint32_t)sig_size,
453 c->security_state.auth_info->auth_pad_length,
454 pkt->u.request.stub_and_verifier.length));
455 return NT_STATUS_INTERNAL_ERROR;
458 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
459 return NT_STATUS_NO_MEMORY;
462 return NT_STATUS_OK;
467 fill in the fixed values in a dcerpc header
469 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
471 pkt->rpc_vers = 5;
472 pkt->rpc_vers_minor = 0;
473 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
474 pkt->drep[0] = 0;
475 } else {
476 pkt->drep[0] = DCERPC_DREP_LE;
478 pkt->drep[1] = 0;
479 pkt->drep[2] = 0;
480 pkt->drep[3] = 0;
484 map a bind nak reason to a NTSTATUS
486 static NTSTATUS dcerpc_map_reason(uint16_t reason)
488 switch (reason) {
489 case DCERPC_BIND_REASON_ASYNTAX:
490 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
491 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
492 return NT_STATUS_INVALID_PARAMETER;
494 return NT_STATUS_UNSUCCESSFUL;
498 a bind or alter context has failed
500 static void dcerpc_composite_fail(struct rpc_request *req)
502 struct composite_context *c = talloc_get_type(req->async.private_data,
503 struct composite_context);
504 composite_error(c, req->status);
508 remove requests from the pending or queued queues
510 static int dcerpc_req_dequeue(struct rpc_request *req)
512 switch (req->state) {
513 case RPC_REQUEST_QUEUED:
514 DLIST_REMOVE(req->p->conn->request_queue, req);
515 break;
516 case RPC_REQUEST_PENDING:
517 DLIST_REMOVE(req->p->conn->pending, req);
518 break;
519 case RPC_REQUEST_DONE:
520 break;
522 return 0;
527 mark the dcerpc connection dead. All outstanding requests get an error
529 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
531 if (conn->dead) return;
533 conn->dead = true;
535 if (conn->transport.shutdown_pipe) {
536 conn->transport.shutdown_pipe(conn, status);
539 /* all pending requests get the error */
540 while (conn->pending) {
541 struct rpc_request *req = conn->pending;
542 dcerpc_req_dequeue(req);
543 req->state = RPC_REQUEST_DONE;
544 req->status = status;
545 if (req->async.callback) {
546 req->async.callback(req);
550 talloc_set_destructor(conn, NULL);
551 if (conn->free_skipped) {
552 talloc_free(conn);
557 forward declarations of the recv_data handlers for the types of
558 packets we need to handle
560 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
561 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
564 receive a dcerpc reply from the transport. Here we work out what
565 type of reply it is (normal request, bind or alter context) and
566 dispatch to the appropriate handler
568 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
570 struct ncacn_packet pkt;
572 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
573 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
576 /* the transport may be telling us of a severe error, such as
577 a dropped socket */
578 if (!NT_STATUS_IS_OK(status)) {
579 data_blob_free(blob);
580 dcerpc_connection_dead(conn, status);
581 return;
584 /* parse the basic packet to work out what type of response this is */
585 status = ncacn_pull(conn, blob, blob->data, &pkt);
586 if (!NT_STATUS_IS_OK(status)) {
587 data_blob_free(blob);
588 dcerpc_connection_dead(conn, status);
591 dcerpc_request_recv_data(conn, blob, &pkt);
596 Receive a bind reply from the transport
598 static void dcerpc_bind_recv_handler(struct rpc_request *req,
599 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
601 struct composite_context *c;
602 struct dcerpc_connection *conn;
604 c = talloc_get_type(req->async.private_data, struct composite_context);
606 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
607 DEBUG(2,("dcerpc: bind_nak reason %d\n",
608 pkt->u.bind_nak.reject_reason));
609 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
610 reject_reason));
611 return;
614 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
615 (pkt->u.bind_ack.num_results == 0) ||
616 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
617 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
618 return;
621 conn = req->p->conn;
623 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
624 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
626 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
627 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
628 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
631 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
632 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
633 conn->flags |= DCERPC_HEADER_SIGNING;
636 /* the bind_ack might contain a reply set of credentials */
637 if (conn->security_state.auth_info &&
638 pkt->u.bind_ack.auth_info.length) {
639 enum ndr_err_code ndr_err;
640 ndr_err = ndr_pull_struct_blob(
641 &pkt->u.bind_ack.auth_info, conn,
642 NULL,
643 conn->security_state.auth_info,
644 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
645 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
646 c->status = ndr_map_error2ntstatus(ndr_err);
647 if (!composite_is_ok(c)) return;
651 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
653 composite_done(c);
657 handle timeouts of individual dcerpc requests
659 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
660 struct timeval t, void *private_data)
662 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
664 if (req->ignore_timeout) {
665 dcerpc_req_dequeue(req);
666 req->state = RPC_REQUEST_DONE;
667 req->status = NT_STATUS_IO_TIMEOUT;
668 if (req->async.callback) {
669 req->async.callback(req);
671 return;
674 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
678 send a async dcerpc bind request
680 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
681 TALLOC_CTX *mem_ctx,
682 const struct ndr_syntax_id *syntax,
683 const struct ndr_syntax_id *transfer_syntax)
685 struct composite_context *c;
686 struct ncacn_packet pkt;
687 DATA_BLOB blob;
688 struct rpc_request *req;
690 c = composite_create(mem_ctx,p->conn->event_ctx);
691 if (c == NULL) return NULL;
693 c->private_data = p;
695 p->syntax = *syntax;
696 p->transfer_syntax = *transfer_syntax;
698 init_ncacn_hdr(p->conn, &pkt);
700 pkt.ptype = DCERPC_PKT_BIND;
701 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
702 pkt.call_id = p->conn->call_id;
703 pkt.auth_length = 0;
705 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
706 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
709 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
710 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
713 pkt.u.bind.max_xmit_frag = 5840;
714 pkt.u.bind.max_recv_frag = 5840;
715 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
716 pkt.u.bind.num_contexts = 1;
717 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
718 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
719 pkt.u.bind.ctx_list[0].context_id = p->context_id;
720 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
721 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
722 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
723 pkt.u.bind.auth_info = data_blob(NULL, 0);
725 /* construct the NDR form of the packet */
726 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
727 p->conn->security_state.auth_info);
728 if (!composite_is_ok(c)) return c;
730 p->conn->transport.recv_data = dcerpc_recv_data;
733 * we allocate a dcerpc_request so we can be in the same
734 * request queue as normal requests
736 req = talloc_zero(c, struct rpc_request);
737 if (composite_nomem(req, c)) return c;
739 req->state = RPC_REQUEST_PENDING;
740 req->call_id = pkt.call_id;
741 req->async.private_data = c;
742 req->async.callback = dcerpc_composite_fail;
743 req->p = p;
744 req->recv_handler = dcerpc_bind_recv_handler;
745 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
746 talloc_set_destructor(req, dcerpc_req_dequeue);
748 c->status = p->conn->transport.send_request(p->conn, &blob,
749 true);
750 if (!composite_is_ok(c)) return c;
752 event_add_timed(c->event_ctx, req,
753 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
754 dcerpc_timeout_handler, req);
756 return c;
760 recv side of async dcerpc bind request
762 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
764 NTSTATUS result = composite_wait(ctx);
765 talloc_free(ctx);
766 return result;
770 perform a continued bind (and auth3)
772 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
773 TALLOC_CTX *mem_ctx)
775 struct ncacn_packet pkt;
776 NTSTATUS status;
777 DATA_BLOB blob;
779 init_ncacn_hdr(p->conn, &pkt);
781 pkt.ptype = DCERPC_PKT_AUTH3;
782 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
783 pkt.call_id = next_call_id(p->conn);
784 pkt.auth_length = 0;
785 pkt.u.auth3._pad = 0;
786 pkt.u.auth3.auth_info = data_blob(NULL, 0);
788 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
789 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
792 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
793 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
796 /* construct the NDR form of the packet */
797 status = ncacn_push_auth(&blob, mem_ctx,
798 p->conn->iconv_convenience,
799 &pkt,
800 p->conn->security_state.auth_info);
801 if (!NT_STATUS_IS_OK(status)) {
802 return status;
805 /* send it on its way */
806 status = p->conn->transport.send_request(p->conn, &blob, false);
807 if (!NT_STATUS_IS_OK(status)) {
808 return status;
811 return NT_STATUS_OK;
816 process a fragment received from the transport layer during a
817 request
819 This function frees the data
821 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
822 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
824 struct rpc_request *req;
825 uint_t length;
826 NTSTATUS status = NT_STATUS_OK;
829 if this is an authenticated connection then parse and check
830 the auth info. We have to do this before finding the
831 matching packet, as the request structure might have been
832 removed due to a timeout, but if it has been we still need
833 to run the auth routines so that we don't get the sign/seal
834 info out of step with the server
836 if (c->security_state.auth_info && c->security_state.generic_state &&
837 pkt->ptype == DCERPC_PKT_RESPONSE) {
838 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
841 /* find the matching request */
842 for (req=c->pending;req;req=req->next) {
843 if (pkt->call_id == req->call_id) break;
846 #if 0
847 /* useful for testing certain vendors RPC servers */
848 if (req == NULL && c->pending && pkt->call_id == 0) {
849 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
850 req = c->pending;
852 #endif
854 if (req == NULL) {
855 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
856 data_blob_free(raw_packet);
857 return;
860 talloc_steal(req, raw_packet->data);
862 if (req->recv_handler != NULL) {
863 dcerpc_req_dequeue(req);
864 req->state = RPC_REQUEST_DONE;
865 req->recv_handler(req, raw_packet, pkt);
866 return;
869 if (pkt->ptype == DCERPC_PKT_FAULT) {
870 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
871 req->fault_code = pkt->u.fault.status;
872 req->status = NT_STATUS_NET_WRITE_FAULT;
873 goto req_done;
876 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
877 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
878 (int)pkt->ptype));
879 req->fault_code = DCERPC_FAULT_OTHER;
880 req->status = NT_STATUS_NET_WRITE_FAULT;
881 goto req_done;
884 /* now check the status from the auth routines, and if it failed then fail
885 this request accordingly */
886 if (!NT_STATUS_IS_OK(status)) {
887 req->status = status;
888 goto req_done;
891 length = pkt->u.response.stub_and_verifier.length;
893 if (length > 0) {
894 req->payload.data = talloc_realloc(req,
895 req->payload.data,
896 uint8_t,
897 req->payload.length + length);
898 if (!req->payload.data) {
899 req->status = NT_STATUS_NO_MEMORY;
900 goto req_done;
902 memcpy(req->payload.data+req->payload.length,
903 pkt->u.response.stub_and_verifier.data, length);
904 req->payload.length += length;
907 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
908 c->transport.send_read(c);
909 return;
912 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
913 req->flags |= DCERPC_PULL_BIGENDIAN;
914 } else {
915 req->flags &= ~DCERPC_PULL_BIGENDIAN;
919 req_done:
920 /* we've got the full payload */
921 req->state = RPC_REQUEST_DONE;
922 DLIST_REMOVE(c->pending, req);
924 if (c->request_queue != NULL) {
925 /* We have to look at shipping further requests before calling
926 * the async function, that one might close the pipe */
927 dcerpc_ship_next_request(c);
930 if (req->async.callback) {
931 req->async.callback(req);
936 perform the send side of a async dcerpc request
938 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
939 const struct GUID *object,
940 uint16_t opnum,
941 bool async,
942 DATA_BLOB *stub_data)
944 struct rpc_request *req;
946 p->conn->transport.recv_data = dcerpc_recv_data;
948 req = talloc(p, struct rpc_request);
949 if (req == NULL) {
950 return NULL;
953 req->p = p;
954 req->call_id = next_call_id(p->conn);
955 req->status = NT_STATUS_OK;
956 req->state = RPC_REQUEST_QUEUED;
957 req->payload = data_blob(NULL, 0);
958 req->flags = 0;
959 req->fault_code = 0;
960 req->async_call = async;
961 req->ignore_timeout = false;
962 req->async.callback = NULL;
963 req->async.private_data = NULL;
964 req->recv_handler = NULL;
966 if (object != NULL) {
967 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
968 if (req->object == NULL) {
969 talloc_free(req);
970 return NULL;
972 } else {
973 req->object = NULL;
976 req->opnum = opnum;
977 req->request_data.length = stub_data->length;
978 req->request_data.data = talloc_reference(req, stub_data->data);
979 if (req->request_data.length && req->request_data.data == NULL) {
980 return NULL;
983 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
984 talloc_set_destructor(req, dcerpc_req_dequeue);
986 dcerpc_ship_next_request(p->conn);
988 if (p->request_timeout) {
989 event_add_timed(dcerpc_event_context(p), req,
990 timeval_current_ofs(p->request_timeout, 0),
991 dcerpc_timeout_handler, req);
994 return req;
998 Send a request using the transport
1001 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1003 struct rpc_request *req;
1004 struct dcerpc_pipe *p;
1005 DATA_BLOB *stub_data;
1006 struct ncacn_packet pkt;
1007 DATA_BLOB blob;
1008 uint32_t remaining, chunk_size;
1009 bool first_packet = true;
1010 size_t sig_size = 0;
1012 req = c->request_queue;
1013 if (req == NULL) {
1014 return;
1017 p = req->p;
1018 stub_data = &req->request_data;
1020 if (!req->async_call && (c->pending != NULL)) {
1021 return;
1024 DLIST_REMOVE(c->request_queue, req);
1025 DLIST_ADD(c->pending, req);
1026 req->state = RPC_REQUEST_PENDING;
1028 init_ncacn_hdr(p->conn, &pkt);
1030 remaining = stub_data->length;
1032 /* we can write a full max_recv_frag size, minus the dcerpc
1033 request header size */
1034 chunk_size = p->conn->srv_max_recv_frag;
1035 chunk_size -= DCERPC_REQUEST_LENGTH;
1036 if (c->security_state.auth_info &&
1037 c->security_state.generic_state) {
1038 sig_size = gensec_sig_size(c->security_state.generic_state,
1039 p->conn->srv_max_recv_frag);
1040 if (sig_size) {
1041 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1042 chunk_size -= sig_size;
1045 chunk_size -= (chunk_size % 16);
1047 pkt.ptype = DCERPC_PKT_REQUEST;
1048 pkt.call_id = req->call_id;
1049 pkt.auth_length = 0;
1050 pkt.pfc_flags = 0;
1051 pkt.u.request.alloc_hint = remaining;
1052 pkt.u.request.context_id = p->context_id;
1053 pkt.u.request.opnum = req->opnum;
1055 if (req->object) {
1056 pkt.u.request.object.object = *req->object;
1057 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1058 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1061 /* we send a series of pdus without waiting for a reply */
1062 while (remaining > 0 || first_packet) {
1063 uint32_t chunk = MIN(chunk_size, remaining);
1064 bool last_frag = false;
1065 bool do_trans = false;
1067 first_packet = false;
1068 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1070 if (remaining == stub_data->length) {
1071 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1073 if (chunk == remaining) {
1074 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1075 last_frag = true;
1078 pkt.u.request.stub_and_verifier.data = stub_data->data +
1079 (stub_data->length - remaining);
1080 pkt.u.request.stub_and_verifier.length = chunk;
1082 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1083 if (!NT_STATUS_IS_OK(req->status)) {
1084 req->state = RPC_REQUEST_DONE;
1085 DLIST_REMOVE(p->conn->pending, req);
1086 return;
1089 if (last_frag && !req->async_call) {
1090 do_trans = true;
1093 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1094 if (!NT_STATUS_IS_OK(req->status)) {
1095 req->state = RPC_REQUEST_DONE;
1096 DLIST_REMOVE(p->conn->pending, req);
1097 return;
1100 if (last_frag && !do_trans) {
1101 req->status = p->conn->transport.send_read(p->conn);
1102 if (!NT_STATUS_IS_OK(req->status)) {
1103 req->state = RPC_REQUEST_DONE;
1104 DLIST_REMOVE(p->conn->pending, req);
1105 return;
1109 remaining -= chunk;
1114 return the event context for a dcerpc pipe
1115 used by callers who wish to operate asynchronously
1117 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1119 return p->conn->event_ctx;
1125 perform the receive side of a async dcerpc request
1127 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1128 TALLOC_CTX *mem_ctx,
1129 DATA_BLOB *stub_data)
1131 NTSTATUS status;
1133 while (req->state != RPC_REQUEST_DONE) {
1134 struct tevent_context *ctx = dcerpc_event_context(req->p);
1135 if (event_loop_once(ctx) != 0) {
1136 return NT_STATUS_CONNECTION_DISCONNECTED;
1139 *stub_data = req->payload;
1140 status = req->status;
1141 if (stub_data->data) {
1142 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1144 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1145 req->p->last_fault_code = req->fault_code;
1147 talloc_unlink(talloc_parent(req), req);
1148 return status;
1152 perform a full request/response pair on a dcerpc pipe
1154 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1155 struct GUID *object,
1156 uint16_t opnum,
1157 TALLOC_CTX *mem_ctx,
1158 DATA_BLOB *stub_data_in,
1159 DATA_BLOB *stub_data_out)
1161 struct rpc_request *req;
1163 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1164 if (req == NULL) {
1165 return NT_STATUS_NO_MEMORY;
1168 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1173 this is a paranoid NDR validator. For every packet we push onto the wire
1174 we pull it back again, then push it again. Then we compare the raw NDR data
1175 for that to the NDR we initially generated. If they don't match then we know
1176 we must have a bug in either the pull or push side of our code
1178 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1179 TALLOC_CTX *mem_ctx,
1180 DATA_BLOB blob,
1181 size_t struct_size,
1182 ndr_push_flags_fn_t ndr_push,
1183 ndr_pull_flags_fn_t ndr_pull)
1185 void *st;
1186 struct ndr_pull *pull;
1187 struct ndr_push *push;
1188 DATA_BLOB blob2;
1189 enum ndr_err_code ndr_err;
1191 st = talloc_size(mem_ctx, struct_size);
1192 if (!st) {
1193 return NT_STATUS_NO_MEMORY;
1196 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1197 if (!pull) {
1198 return NT_STATUS_NO_MEMORY;
1200 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1202 ndr_err = ndr_pull(pull, NDR_IN, st);
1203 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1204 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1205 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1206 "failed input validation pull - %s",
1207 nt_errstr(status));
1208 return ndr_map_error2ntstatus(ndr_err);
1211 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1212 if (!push) {
1213 return NT_STATUS_NO_MEMORY;
1216 ndr_err = ndr_push(push, NDR_IN, st);
1217 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1218 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1219 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1220 "failed input validation push - %s",
1221 nt_errstr(status));
1222 return ndr_map_error2ntstatus(ndr_err);
1225 blob2 = ndr_push_blob(push);
1227 if (data_blob_cmp(&blob, &blob2) != 0) {
1228 DEBUG(3,("original:\n"));
1229 dump_data(3, blob.data, blob.length);
1230 DEBUG(3,("secondary:\n"));
1231 dump_data(3, blob2.data, blob2.length);
1232 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1233 "failed input validation blobs doesn't match");
1234 return ndr_map_error2ntstatus(ndr_err);
1237 return NT_STATUS_OK;
1241 this is a paranoid NDR input validator. For every packet we pull
1242 from the wire we push it back again then pull and push it
1243 again. Then we compare the raw NDR data for that to the NDR we
1244 initially generated. If they don't match then we know we must have a
1245 bug in either the pull or push side of our code
1247 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1248 struct ndr_pull *pull_in,
1249 void *struct_ptr,
1250 size_t struct_size,
1251 ndr_push_flags_fn_t ndr_push,
1252 ndr_pull_flags_fn_t ndr_pull,
1253 ndr_print_function_t ndr_print)
1255 void *st;
1256 struct ndr_pull *pull;
1257 struct ndr_push *push;
1258 DATA_BLOB blob, blob2;
1259 TALLOC_CTX *mem_ctx = pull_in;
1260 char *s1, *s2;
1261 enum ndr_err_code ndr_err;
1263 st = talloc_size(mem_ctx, struct_size);
1264 if (!st) {
1265 return NT_STATUS_NO_MEMORY;
1267 memcpy(st, struct_ptr, struct_size);
1269 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1270 if (!push) {
1271 return NT_STATUS_NO_MEMORY;
1274 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1275 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1276 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1277 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1278 "failed output validation push - %s",
1279 nt_errstr(status));
1280 return ndr_map_error2ntstatus(ndr_err);
1283 blob = ndr_push_blob(push);
1285 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1286 if (!pull) {
1287 return NT_STATUS_NO_MEMORY;
1290 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1291 ndr_err = ndr_pull(pull, NDR_OUT, st);
1292 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1293 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1294 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1295 "failed output validation pull - %s",
1296 nt_errstr(status));
1297 return ndr_map_error2ntstatus(ndr_err);
1300 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1301 if (!push) {
1302 return NT_STATUS_NO_MEMORY;
1305 ndr_err = ndr_push(push, NDR_OUT, st);
1306 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1307 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1308 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1309 "failed output validation push2 - %s",
1310 nt_errstr(status));
1311 return ndr_map_error2ntstatus(ndr_err);
1314 blob2 = ndr_push_blob(push);
1316 if (data_blob_cmp(&blob, &blob2) != 0) {
1317 DEBUG(3,("original:\n"));
1318 dump_data(3, blob.data, blob.length);
1319 DEBUG(3,("secondary:\n"));
1320 dump_data(3, blob2.data, blob2.length);
1321 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1322 "failed output validation blobs doesn't match");
1323 return ndr_map_error2ntstatus(ndr_err);
1326 /* this checks the printed forms of the two structures, which effectively
1327 tests all of the value() attributes */
1328 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1329 NDR_OUT, struct_ptr);
1330 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1331 NDR_OUT, st);
1332 if (strcmp(s1, s2) != 0) {
1333 #if 1
1334 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1335 #else
1336 /* this is sometimes useful */
1337 printf("VALIDATE ERROR\n");
1338 file_save("wire.dat", s1, strlen(s1));
1339 file_save("gen.dat", s2, strlen(s2));
1340 system("diff -u wire.dat gen.dat");
1341 #endif
1342 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1343 "failed output validation strings doesn't match");
1344 return ndr_map_error2ntstatus(ndr_err);
1347 return NT_STATUS_OK;
1352 send a rpc request given a dcerpc_call structure
1354 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1355 const struct GUID *object,
1356 const struct ndr_interface_table *table,
1357 uint32_t opnum,
1358 bool async,
1359 TALLOC_CTX *mem_ctx,
1360 void *r)
1362 const struct ndr_interface_call *call;
1363 struct ndr_push *push;
1364 NTSTATUS status;
1365 DATA_BLOB request;
1366 struct rpc_request *req;
1367 enum ndr_err_code ndr_err;
1369 call = &table->calls[opnum];
1371 /* setup for a ndr_push_* call */
1372 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1373 if (!push) {
1374 return NULL;
1377 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1378 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1381 /* push the structure into a blob */
1382 ndr_err = call->ndr_push(push, NDR_IN, r);
1383 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1384 status = ndr_map_error2ntstatus(ndr_err);
1385 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1386 nt_errstr(status)));
1387 talloc_free(push);
1388 return NULL;
1391 /* retrieve the blob */
1392 request = ndr_push_blob(push);
1394 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1395 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1396 call->ndr_push, call->ndr_pull);
1397 if (!NT_STATUS_IS_OK(status)) {
1398 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1399 nt_errstr(status)));
1400 talloc_free(push);
1401 return NULL;
1405 DEBUG(10,("rpc request data:\n"));
1406 dump_data(10, request.data, request.length);
1408 /* make the actual dcerpc request */
1409 req = dcerpc_request_send(p, object, opnum, async, &request);
1411 if (req != NULL) {
1412 req->ndr.table = table;
1413 req->ndr.opnum = opnum;
1414 req->ndr.struct_ptr = r;
1415 req->ndr.mem_ctx = mem_ctx;
1418 talloc_free(push);
1420 return req;
1424 receive the answer from a dcerpc_ndr_request_send()
1426 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1428 struct dcerpc_pipe *p = req->p;
1429 NTSTATUS status;
1430 DATA_BLOB response;
1431 struct ndr_pull *pull;
1432 uint_t flags;
1433 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1434 void *r = req->ndr.struct_ptr;
1435 uint32_t opnum = req->ndr.opnum;
1436 const struct ndr_interface_table *table = req->ndr.table;
1437 const struct ndr_interface_call *call = &table->calls[opnum];
1438 enum ndr_err_code ndr_err;
1440 /* make sure the recv code doesn't free the request, as we
1441 need to grab the flags element before it is freed */
1442 if (talloc_reference(p, req) == NULL) {
1443 return NT_STATUS_NO_MEMORY;
1446 status = dcerpc_request_recv(req, mem_ctx, &response);
1447 if (!NT_STATUS_IS_OK(status)) {
1448 talloc_unlink(p, req);
1449 return status;
1452 flags = req->flags;
1454 /* prepare for ndr_pull_* */
1455 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1456 if (!pull) {
1457 talloc_unlink(p, req);
1458 return NT_STATUS_NO_MEMORY;
1461 if (pull->data) {
1462 pull->data = talloc_steal(pull, pull->data);
1464 talloc_unlink(p, req);
1466 if (flags & DCERPC_PULL_BIGENDIAN) {
1467 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1470 DEBUG(10,("rpc reply data:\n"));
1471 dump_data(10, pull->data, pull->data_size);
1473 /* pull the structure from the blob */
1474 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1475 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1476 status = ndr_map_error2ntstatus(ndr_err);
1477 dcerpc_log_packet(p->conn->packet_log_dir,
1478 table, opnum, NDR_OUT,
1479 &response);
1480 return status;
1483 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1484 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1485 call->ndr_push, call->ndr_pull,
1486 call->ndr_print);
1487 if (!NT_STATUS_IS_OK(status)) {
1488 dcerpc_log_packet(p->conn->packet_log_dir,
1489 table, opnum, NDR_OUT,
1490 &response);
1491 return status;
1495 if (pull->offset != pull->data_size) {
1496 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1497 pull->data_size - pull->offset));
1498 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1499 but it turns out that early versions of NT
1500 (specifically NT3.1) add junk onto the end of rpc
1501 packets, so if we want to interoperate at all with
1502 those versions then we need to ignore this error */
1505 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1507 return NT_STATUS_OK;
1512 a useful helper function for synchronous rpc requests
1514 this can be used when you have ndr push/pull functions in the
1515 standard format
1517 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1518 const struct GUID *object,
1519 const struct ndr_interface_table *table,
1520 uint32_t opnum,
1521 TALLOC_CTX *mem_ctx,
1522 void *r)
1524 struct rpc_request *req;
1526 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1527 if (req == NULL) {
1528 return NT_STATUS_NO_MEMORY;
1531 return dcerpc_ndr_request_recv(req);
1536 a useful function for retrieving the server name we connected to
1538 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1540 if (!p->conn->transport.target_hostname) {
1541 if (!p->conn->transport.peer_name) {
1542 return "";
1544 return p->conn->transport.peer_name(p->conn);
1546 return p->conn->transport.target_hostname(p->conn);
1551 get the dcerpc auth_level for a open connection
1553 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1555 uint8_t auth_level;
1557 if (c->flags & DCERPC_SEAL) {
1558 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1559 } else if (c->flags & DCERPC_SIGN) {
1560 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1561 } else if (c->flags & DCERPC_CONNECT) {
1562 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1563 } else {
1564 auth_level = DCERPC_AUTH_LEVEL_NONE;
1566 return auth_level;
1570 Receive an alter reply from the transport
1572 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1573 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1575 struct composite_context *c;
1576 struct dcerpc_pipe *recv_pipe;
1578 c = talloc_get_type(req->async.private_data, struct composite_context);
1579 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1581 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1582 pkt->u.alter_resp.num_results == 1 &&
1583 pkt->u.alter_resp.ctx_list[0].result != 0) {
1584 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1585 pkt->u.alter_resp.ctx_list[0].reason));
1586 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1587 return;
1590 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1591 pkt->u.alter_resp.num_results == 0 ||
1592 pkt->u.alter_resp.ctx_list[0].result != 0) {
1593 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1594 return;
1597 /* the alter_resp might contain a reply set of credentials */
1598 if (recv_pipe->conn->security_state.auth_info &&
1599 pkt->u.alter_resp.auth_info.length) {
1600 enum ndr_err_code ndr_err;
1601 ndr_err = ndr_pull_struct_blob(
1602 &pkt->u.alter_resp.auth_info, recv_pipe,
1603 NULL,
1604 recv_pipe->conn->security_state.auth_info,
1605 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1606 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1607 c->status = ndr_map_error2ntstatus(ndr_err);
1608 if (!composite_is_ok(c)) return;
1612 composite_done(c);
1616 send a dcerpc alter_context request
1618 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1619 TALLOC_CTX *mem_ctx,
1620 const struct ndr_syntax_id *syntax,
1621 const struct ndr_syntax_id *transfer_syntax)
1623 struct composite_context *c;
1624 struct ncacn_packet pkt;
1625 DATA_BLOB blob;
1626 struct rpc_request *req;
1628 c = composite_create(mem_ctx, p->conn->event_ctx);
1629 if (c == NULL) return NULL;
1631 c->private_data = p;
1633 p->syntax = *syntax;
1634 p->transfer_syntax = *transfer_syntax;
1636 init_ncacn_hdr(p->conn, &pkt);
1638 pkt.ptype = DCERPC_PKT_ALTER;
1639 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1640 pkt.call_id = p->conn->call_id;
1641 pkt.auth_length = 0;
1643 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1644 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1647 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1648 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1651 pkt.u.alter.max_xmit_frag = 5840;
1652 pkt.u.alter.max_recv_frag = 5840;
1653 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1654 pkt.u.alter.num_contexts = 1;
1655 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1656 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1657 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1658 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1659 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1660 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1661 pkt.u.alter.auth_info = data_blob(NULL, 0);
1663 /* construct the NDR form of the packet */
1664 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1665 p->conn->security_state.auth_info);
1666 if (!composite_is_ok(c)) return c;
1668 p->conn->transport.recv_data = dcerpc_recv_data;
1671 * we allocate a dcerpc_request so we can be in the same
1672 * request queue as normal requests
1674 req = talloc_zero(c, struct rpc_request);
1675 if (composite_nomem(req, c)) return c;
1677 req->state = RPC_REQUEST_PENDING;
1678 req->call_id = pkt.call_id;
1679 req->async.private_data = c;
1680 req->async.callback = dcerpc_composite_fail;
1681 req->p = p;
1682 req->recv_handler = dcerpc_alter_recv_handler;
1683 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1684 talloc_set_destructor(req, dcerpc_req_dequeue);
1686 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1687 if (!composite_is_ok(c)) return c;
1689 event_add_timed(c->event_ctx, req,
1690 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1691 dcerpc_timeout_handler, req);
1693 return c;
1696 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1698 NTSTATUS result = composite_wait(ctx);
1699 talloc_free(ctx);
1700 return result;
1704 send a dcerpc alter_context request
1706 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1707 TALLOC_CTX *mem_ctx,
1708 const struct ndr_syntax_id *syntax,
1709 const struct ndr_syntax_id *transfer_syntax)
1711 struct composite_context *creq;
1712 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1713 return dcerpc_alter_context_recv(creq);