s4:libnet_rpc: check for NT_STATUS_RPC_PROCNUM_OUT_OF_RANGE instead of NT_STATUS_NET_...
[Samba/gebeck_regimport.git] / source4 / librpc / rpc / dcerpc.c
blob95f83465fc2cb3234763f2def753c19e77bd54f9
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 p->binding_handle = talloc(p, struct dcerpc_binding_handle);
122 if (p->binding_handle == NULL) {
123 talloc_free(p);
124 return NULL;
126 p->binding_handle->private_data = p;
128 return p;
133 choose the next call id to use
135 static uint32_t next_call_id(struct dcerpc_connection *c)
137 c->call_id++;
138 if (c->call_id == 0) {
139 c->call_id++;
141 return c->call_id;
144 /* we need to be able to get/set the fragment length without doing a full
145 decode */
146 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
148 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
149 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
150 } else {
151 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
155 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
157 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
158 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
159 } else {
160 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
164 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
166 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
167 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
168 } else {
169 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
175 setup for a ndr pull, also setting up any flags from the binding string
177 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
178 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
180 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
182 if (ndr == NULL) return ndr;
184 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
185 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
188 if (c->flags & DCERPC_NDR_REF_ALLOC) {
189 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
192 if (c->flags & DCERPC_NDR64) {
193 ndr->flags |= LIBNDR_FLAG_NDR64;
196 return ndr;
200 parse a data blob into a ncacn_packet structure. This handles both
201 input and output packets
203 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
204 struct ncacn_packet *pkt)
206 struct ndr_pull *ndr;
207 enum ndr_err_code ndr_err;
209 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
210 if (!ndr) {
211 return NT_STATUS_NO_MEMORY;
214 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
215 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
218 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
219 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
220 return ndr_map_error2ntstatus(ndr_err);
223 return NT_STATUS_OK;
227 parse the authentication information on a dcerpc response packet
229 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
230 DATA_BLOB *raw_packet,
231 struct ncacn_packet *pkt)
233 NTSTATUS status;
234 struct dcerpc_auth auth;
235 uint32_t auth_length;
237 if (!c->security_state.auth_info ||
238 !c->security_state.generic_state) {
239 return NT_STATUS_OK;
242 switch (c->security_state.auth_info->auth_level) {
243 case DCERPC_AUTH_LEVEL_PRIVACY:
244 case DCERPC_AUTH_LEVEL_INTEGRITY:
245 break;
247 case DCERPC_AUTH_LEVEL_CONNECT:
248 if (pkt->auth_length != 0) {
249 break;
251 return NT_STATUS_OK;
252 case DCERPC_AUTH_LEVEL_NONE:
253 if (pkt->auth_length != 0) {
254 return NT_STATUS_INVALID_NETWORK_RESPONSE;
256 return NT_STATUS_OK;
258 default:
259 return NT_STATUS_INVALID_LEVEL;
262 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
263 &pkt->u.response.stub_and_verifier,
264 &auth, &auth_length, false);
265 NT_STATUS_NOT_OK_RETURN(status);
267 pkt->u.response.stub_and_verifier.length -= auth_length;
269 /* check signature or unseal the packet */
270 switch (c->security_state.auth_info->auth_level) {
271 case DCERPC_AUTH_LEVEL_PRIVACY:
272 status = gensec_unseal_packet(c->security_state.generic_state,
273 mem_ctx,
274 raw_packet->data + DCERPC_REQUEST_LENGTH,
275 pkt->u.response.stub_and_verifier.length,
276 raw_packet->data,
277 raw_packet->length - auth.credentials.length,
278 &auth.credentials);
279 memcpy(pkt->u.response.stub_and_verifier.data,
280 raw_packet->data + DCERPC_REQUEST_LENGTH,
281 pkt->u.response.stub_and_verifier.length);
282 break;
284 case DCERPC_AUTH_LEVEL_INTEGRITY:
285 status = gensec_check_packet(c->security_state.generic_state,
286 mem_ctx,
287 pkt->u.response.stub_and_verifier.data,
288 pkt->u.response.stub_and_verifier.length,
289 raw_packet->data,
290 raw_packet->length - auth.credentials.length,
291 &auth.credentials);
292 break;
294 case DCERPC_AUTH_LEVEL_CONNECT:
295 /* for now we ignore possible signatures here */
296 status = NT_STATUS_OK;
297 break;
299 default:
300 status = NT_STATUS_INVALID_LEVEL;
301 break;
304 /* remove the indicated amount of padding */
305 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
306 return NT_STATUS_INFO_LENGTH_MISMATCH;
308 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
310 return status;
315 push a dcerpc request packet into a blob, possibly signing it.
317 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
318 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
319 size_t sig_size,
320 struct ncacn_packet *pkt)
322 NTSTATUS status;
323 struct ndr_push *ndr;
324 DATA_BLOB creds2;
325 size_t payload_length;
326 enum ndr_err_code ndr_err;
327 size_t hdr_size = DCERPC_REQUEST_LENGTH;
329 /* non-signed packets are simpler */
330 if (sig_size == 0) {
331 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
334 switch (c->security_state.auth_info->auth_level) {
335 case DCERPC_AUTH_LEVEL_PRIVACY:
336 case DCERPC_AUTH_LEVEL_INTEGRITY:
337 break;
339 case DCERPC_AUTH_LEVEL_CONNECT:
340 /* TODO: let the gensec mech decide if it wants to generate a signature */
341 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
343 case DCERPC_AUTH_LEVEL_NONE:
344 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
346 default:
347 return NT_STATUS_INVALID_LEVEL;
350 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
351 if (!ndr) {
352 return NT_STATUS_NO_MEMORY;
355 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
356 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
359 if (c->flags & DCERPC_NDR64) {
360 ndr->flags |= LIBNDR_FLAG_NDR64;
363 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
364 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
365 hdr_size += 16;
368 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
369 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
370 return ndr_map_error2ntstatus(ndr_err);
373 /* pad to 16 byte multiple in the payload portion of the
374 packet. This matches what w2k3 does. Note that we can't use
375 ndr_push_align() as that is relative to the start of the
376 whole packet, whereas w2k8 wants it relative to the start
377 of the stub */
378 c->security_state.auth_info->auth_pad_length =
379 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
380 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
382 return ndr_map_error2ntstatus(ndr_err);
385 payload_length = pkt->u.request.stub_and_verifier.length +
386 c->security_state.auth_info->auth_pad_length;
388 /* we start without signature, it will appended later */
389 c->security_state.auth_info->credentials = data_blob(NULL,0);
391 /* add the auth verifier */
392 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
393 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
394 return ndr_map_error2ntstatus(ndr_err);
397 /* extract the whole packet as a blob */
398 *blob = ndr_push_blob(ndr);
401 * Setup the frag and auth length in the packet buffer.
402 * This is needed if the GENSEC mech does AEAD signing
403 * of the packet headers. The signature itself will be
404 * appended later.
406 dcerpc_set_frag_length(blob, blob->length + sig_size);
407 dcerpc_set_auth_length(blob, sig_size);
409 /* sign or seal the packet */
410 switch (c->security_state.auth_info->auth_level) {
411 case DCERPC_AUTH_LEVEL_PRIVACY:
412 status = gensec_seal_packet(c->security_state.generic_state,
413 mem_ctx,
414 blob->data + hdr_size,
415 payload_length,
416 blob->data,
417 blob->length,
418 &creds2);
419 if (!NT_STATUS_IS_OK(status)) {
420 return status;
422 break;
424 case DCERPC_AUTH_LEVEL_INTEGRITY:
425 status = gensec_sign_packet(c->security_state.generic_state,
426 mem_ctx,
427 blob->data + hdr_size,
428 payload_length,
429 blob->data,
430 blob->length,
431 &creds2);
432 if (!NT_STATUS_IS_OK(status)) {
433 return status;
435 break;
437 default:
438 status = NT_STATUS_INVALID_LEVEL;
439 break;
442 if (creds2.length != sig_size) {
443 /* this means the sig_size estimate for the signature
444 was incorrect. We have to correct the packet
445 sizes. That means we could go over the max fragment
446 length */
447 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
448 (unsigned) creds2.length,
449 (unsigned) sig_size,
450 (unsigned) c->security_state.auth_info->auth_pad_length,
451 (unsigned) pkt->u.request.stub_and_verifier.length));
452 dcerpc_set_frag_length(blob, blob->length + creds2.length);
453 dcerpc_set_auth_length(blob, creds2.length);
456 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
457 return NT_STATUS_NO_MEMORY;
460 return NT_STATUS_OK;
465 fill in the fixed values in a dcerpc header
467 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
469 pkt->rpc_vers = 5;
470 pkt->rpc_vers_minor = 0;
471 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
472 pkt->drep[0] = 0;
473 } else {
474 pkt->drep[0] = DCERPC_DREP_LE;
476 pkt->drep[1] = 0;
477 pkt->drep[2] = 0;
478 pkt->drep[3] = 0;
482 map a bind nak reason to a NTSTATUS
484 static NTSTATUS dcerpc_map_reason(uint16_t reason)
486 switch (reason) {
487 case DCERPC_BIND_REASON_ASYNTAX:
488 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
489 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
490 return NT_STATUS_INVALID_PARAMETER;
492 return NT_STATUS_UNSUCCESSFUL;
496 a bind or alter context has failed
498 static void dcerpc_composite_fail(struct rpc_request *req)
500 struct composite_context *c = talloc_get_type(req->async.private_data,
501 struct composite_context);
502 composite_error(c, req->status);
506 remove requests from the pending or queued queues
508 static int dcerpc_req_dequeue(struct rpc_request *req)
510 switch (req->state) {
511 case RPC_REQUEST_QUEUED:
512 DLIST_REMOVE(req->p->conn->request_queue, req);
513 break;
514 case RPC_REQUEST_PENDING:
515 DLIST_REMOVE(req->p->conn->pending, req);
516 break;
517 case RPC_REQUEST_DONE:
518 break;
520 return 0;
525 mark the dcerpc connection dead. All outstanding requests get an error
527 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
529 if (conn->dead) return;
531 conn->dead = true;
533 if (conn->transport.shutdown_pipe) {
534 conn->transport.shutdown_pipe(conn, status);
537 /* all pending requests get the error */
538 while (conn->pending) {
539 struct rpc_request *req = conn->pending;
540 dcerpc_req_dequeue(req);
541 req->state = RPC_REQUEST_DONE;
542 req->status = status;
543 if (req->async.callback) {
544 req->async.callback(req);
548 talloc_set_destructor(conn, NULL);
549 if (conn->free_skipped) {
550 talloc_free(conn);
555 forward declarations of the recv_data handlers for the types of
556 packets we need to handle
558 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
559 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
562 receive a dcerpc reply from the transport. Here we work out what
563 type of reply it is (normal request, bind or alter context) and
564 dispatch to the appropriate handler
566 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
568 struct ncacn_packet pkt;
570 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
571 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
574 /* the transport may be telling us of a severe error, such as
575 a dropped socket */
576 if (!NT_STATUS_IS_OK(status)) {
577 data_blob_free(blob);
578 dcerpc_connection_dead(conn, status);
579 return;
582 /* parse the basic packet to work out what type of response this is */
583 status = ncacn_pull(conn, blob, blob->data, &pkt);
584 if (!NT_STATUS_IS_OK(status)) {
585 data_blob_free(blob);
586 dcerpc_connection_dead(conn, status);
589 dcerpc_request_recv_data(conn, blob, &pkt);
593 Receive a bind reply from the transport
595 static void dcerpc_bind_recv_handler(struct rpc_request *req,
596 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
598 struct composite_context *c;
599 struct dcerpc_connection *conn;
601 c = talloc_get_type(req->async.private_data, struct composite_context);
603 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
604 DEBUG(2,("dcerpc: bind_nak reason %d\n",
605 pkt->u.bind_nak.reject_reason));
606 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
607 reject_reason));
608 return;
611 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
612 (pkt->u.bind_ack.num_results == 0) ||
613 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
614 req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
615 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
616 return;
619 conn = req->p->conn;
621 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
622 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
624 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
625 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
626 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
629 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
630 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
631 conn->flags |= DCERPC_HEADER_SIGNING;
634 /* the bind_ack might contain a reply set of credentials */
635 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
636 NTSTATUS status;
637 uint32_t auth_length;
638 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
639 conn->security_state.auth_info, &auth_length, true);
640 if (!NT_STATUS_IS_OK(status)) {
641 composite_error(c, status);
642 return;
646 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
648 composite_done(c);
652 handle timeouts of individual dcerpc requests
654 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
655 struct timeval t, void *private_data)
657 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
659 if (req->ignore_timeout) {
660 dcerpc_req_dequeue(req);
661 req->state = RPC_REQUEST_DONE;
662 req->status = NT_STATUS_IO_TIMEOUT;
663 if (req->async.callback) {
664 req->async.callback(req);
666 return;
669 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
673 send a async dcerpc bind request
675 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
676 TALLOC_CTX *mem_ctx,
677 const struct ndr_syntax_id *syntax,
678 const struct ndr_syntax_id *transfer_syntax)
680 struct composite_context *c;
681 struct ncacn_packet pkt;
682 DATA_BLOB blob;
683 struct rpc_request *req;
685 c = composite_create(mem_ctx,p->conn->event_ctx);
686 if (c == NULL) return NULL;
688 c->private_data = p;
690 p->syntax = *syntax;
691 p->transfer_syntax = *transfer_syntax;
693 init_ncacn_hdr(p->conn, &pkt);
695 pkt.ptype = DCERPC_PKT_BIND;
696 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
697 pkt.call_id = p->conn->call_id;
698 pkt.auth_length = 0;
700 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
701 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
704 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
705 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
708 pkt.u.bind.max_xmit_frag = 5840;
709 pkt.u.bind.max_recv_frag = 5840;
710 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
711 pkt.u.bind.num_contexts = 1;
712 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
713 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
714 pkt.u.bind.ctx_list[0].context_id = p->context_id;
715 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
716 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
717 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
718 pkt.u.bind.auth_info = data_blob(NULL, 0);
720 /* construct the NDR form of the packet */
721 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
722 p->conn->security_state.auth_info);
723 if (!composite_is_ok(c)) return c;
725 p->conn->transport.recv_data = dcerpc_recv_data;
728 * we allocate a dcerpc_request so we can be in the same
729 * request queue as normal requests
731 req = talloc_zero(c, struct rpc_request);
732 if (composite_nomem(req, c)) return c;
734 req->state = RPC_REQUEST_PENDING;
735 req->call_id = pkt.call_id;
736 req->async.private_data = c;
737 req->async.callback = dcerpc_composite_fail;
738 req->p = p;
739 req->recv_handler = dcerpc_bind_recv_handler;
740 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
741 talloc_set_destructor(req, dcerpc_req_dequeue);
743 c->status = p->conn->transport.send_request(p->conn, &blob,
744 true);
745 if (!composite_is_ok(c)) return c;
747 event_add_timed(c->event_ctx, req,
748 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
749 dcerpc_timeout_handler, req);
751 return c;
755 recv side of async dcerpc bind request
757 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
759 NTSTATUS result = composite_wait(ctx);
760 talloc_free(ctx);
761 return result;
765 perform a continued bind (and auth3)
767 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
768 TALLOC_CTX *mem_ctx)
770 struct ncacn_packet pkt;
771 NTSTATUS status;
772 DATA_BLOB blob;
774 init_ncacn_hdr(p->conn, &pkt);
776 pkt.ptype = DCERPC_PKT_AUTH3;
777 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
778 pkt.call_id = next_call_id(p->conn);
779 pkt.auth_length = 0;
780 pkt.u.auth3.auth_info = data_blob(NULL, 0);
782 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
783 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
786 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
787 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
790 /* construct the NDR form of the packet */
791 status = ncacn_push_auth(&blob, mem_ctx,
792 p->conn->iconv_convenience,
793 &pkt,
794 p->conn->security_state.auth_info);
795 if (!NT_STATUS_IS_OK(status)) {
796 return status;
799 /* send it on its way */
800 status = p->conn->transport.send_request(p->conn, &blob, false);
801 if (!NT_STATUS_IS_OK(status)) {
802 return status;
805 return NT_STATUS_OK;
810 process a fragment received from the transport layer during a
811 request
813 This function frees the data
815 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
816 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
818 struct rpc_request *req;
819 unsigned int length;
820 NTSTATUS status = NT_STATUS_OK;
823 if this is an authenticated connection then parse and check
824 the auth info. We have to do this before finding the
825 matching packet, as the request structure might have been
826 removed due to a timeout, but if it has been we still need
827 to run the auth routines so that we don't get the sign/seal
828 info out of step with the server
830 if (c->security_state.auth_info && c->security_state.generic_state &&
831 pkt->ptype == DCERPC_PKT_RESPONSE) {
832 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
835 /* find the matching request */
836 for (req=c->pending;req;req=req->next) {
837 if (pkt->call_id == req->call_id) break;
840 #if 0
841 /* useful for testing certain vendors RPC servers */
842 if (req == NULL && c->pending && pkt->call_id == 0) {
843 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
844 req = c->pending;
846 #endif
848 if (req == NULL) {
849 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
850 data_blob_free(raw_packet);
851 return;
854 talloc_steal(req, raw_packet->data);
856 if (req->recv_handler != NULL) {
857 dcerpc_req_dequeue(req);
858 req->state = RPC_REQUEST_DONE;
859 req->recv_handler(req, raw_packet, pkt);
860 return;
863 if (pkt->ptype == DCERPC_PKT_FAULT) {
864 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
865 req->fault_code = pkt->u.fault.status;
866 req->status = NT_STATUS_NET_WRITE_FAULT;
867 goto req_done;
870 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
871 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
872 (int)pkt->ptype));
873 req->fault_code = DCERPC_FAULT_OTHER;
874 req->status = NT_STATUS_NET_WRITE_FAULT;
875 goto req_done;
878 /* now check the status from the auth routines, and if it failed then fail
879 this request accordingly */
880 if (!NT_STATUS_IS_OK(status)) {
881 req->status = status;
882 goto req_done;
885 length = pkt->u.response.stub_and_verifier.length;
887 if (length > 0) {
888 req->payload.data = talloc_realloc(req,
889 req->payload.data,
890 uint8_t,
891 req->payload.length + length);
892 if (!req->payload.data) {
893 req->status = NT_STATUS_NO_MEMORY;
894 goto req_done;
896 memcpy(req->payload.data+req->payload.length,
897 pkt->u.response.stub_and_verifier.data, length);
898 req->payload.length += length;
901 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
902 c->transport.send_read(c);
903 return;
906 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
907 req->flags |= DCERPC_PULL_BIGENDIAN;
908 } else {
909 req->flags &= ~DCERPC_PULL_BIGENDIAN;
913 req_done:
914 /* we've got the full payload */
915 req->state = RPC_REQUEST_DONE;
916 DLIST_REMOVE(c->pending, req);
918 if (c->request_queue != NULL) {
919 /* We have to look at shipping further requests before calling
920 * the async function, that one might close the pipe */
921 dcerpc_ship_next_request(c);
924 if (req->async.callback) {
925 req->async.callback(req);
930 perform the send side of a async dcerpc request
932 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
933 const struct GUID *object,
934 uint16_t opnum,
935 bool async,
936 DATA_BLOB *stub_data)
938 struct rpc_request *req;
940 p->conn->transport.recv_data = dcerpc_recv_data;
942 req = talloc(p, struct rpc_request);
943 if (req == NULL) {
944 return NULL;
947 req->p = p;
948 req->call_id = next_call_id(p->conn);
949 req->status = NT_STATUS_OK;
950 req->state = RPC_REQUEST_QUEUED;
951 req->payload = data_blob(NULL, 0);
952 req->flags = 0;
953 req->fault_code = 0;
954 req->async_call = async;
955 req->ignore_timeout = false;
956 req->async.callback = NULL;
957 req->async.private_data = NULL;
958 req->recv_handler = NULL;
960 if (object != NULL) {
961 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
962 if (req->object == NULL) {
963 talloc_free(req);
964 return NULL;
966 } else {
967 req->object = NULL;
970 req->opnum = opnum;
971 req->request_data.length = stub_data->length;
972 req->request_data.data = talloc_reference(req, stub_data->data);
973 if (req->request_data.length && req->request_data.data == NULL) {
974 return NULL;
977 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
978 talloc_set_destructor(req, dcerpc_req_dequeue);
980 dcerpc_ship_next_request(p->conn);
982 if (p->request_timeout) {
983 event_add_timed(dcerpc_event_context(p), req,
984 timeval_current_ofs(p->request_timeout, 0),
985 dcerpc_timeout_handler, req);
988 return req;
992 Send a request using the transport
995 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
997 struct rpc_request *req;
998 struct dcerpc_pipe *p;
999 DATA_BLOB *stub_data;
1000 struct ncacn_packet pkt;
1001 DATA_BLOB blob;
1002 uint32_t remaining, chunk_size;
1003 bool first_packet = true;
1004 size_t sig_size = 0;
1006 req = c->request_queue;
1007 if (req == NULL) {
1008 return;
1011 p = req->p;
1012 stub_data = &req->request_data;
1014 if (!req->async_call && (c->pending != NULL)) {
1015 return;
1018 DLIST_REMOVE(c->request_queue, req);
1019 DLIST_ADD(c->pending, req);
1020 req->state = RPC_REQUEST_PENDING;
1022 init_ncacn_hdr(p->conn, &pkt);
1024 remaining = stub_data->length;
1026 /* we can write a full max_recv_frag size, minus the dcerpc
1027 request header size */
1028 chunk_size = p->conn->srv_max_recv_frag;
1029 chunk_size -= DCERPC_REQUEST_LENGTH;
1030 if (c->security_state.auth_info &&
1031 c->security_state.generic_state) {
1032 sig_size = gensec_sig_size(c->security_state.generic_state,
1033 p->conn->srv_max_recv_frag);
1034 if (sig_size) {
1035 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1036 chunk_size -= sig_size;
1039 chunk_size -= (chunk_size % 16);
1041 pkt.ptype = DCERPC_PKT_REQUEST;
1042 pkt.call_id = req->call_id;
1043 pkt.auth_length = 0;
1044 pkt.pfc_flags = 0;
1045 pkt.u.request.alloc_hint = remaining;
1046 pkt.u.request.context_id = p->context_id;
1047 pkt.u.request.opnum = req->opnum;
1049 if (req->object) {
1050 pkt.u.request.object.object = *req->object;
1051 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1052 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1055 /* we send a series of pdus without waiting for a reply */
1056 while (remaining > 0 || first_packet) {
1057 uint32_t chunk = MIN(chunk_size, remaining);
1058 bool last_frag = false;
1059 bool do_trans = false;
1061 first_packet = false;
1062 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1064 if (remaining == stub_data->length) {
1065 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1067 if (chunk == remaining) {
1068 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1069 last_frag = true;
1072 pkt.u.request.stub_and_verifier.data = stub_data->data +
1073 (stub_data->length - remaining);
1074 pkt.u.request.stub_and_verifier.length = chunk;
1076 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1077 if (!NT_STATUS_IS_OK(req->status)) {
1078 req->state = RPC_REQUEST_DONE;
1079 DLIST_REMOVE(p->conn->pending, req);
1080 return;
1083 if (last_frag && !req->async_call) {
1084 do_trans = true;
1087 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1088 if (!NT_STATUS_IS_OK(req->status)) {
1089 req->state = RPC_REQUEST_DONE;
1090 DLIST_REMOVE(p->conn->pending, req);
1091 return;
1094 if (last_frag && !do_trans) {
1095 req->status = p->conn->transport.send_read(p->conn);
1096 if (!NT_STATUS_IS_OK(req->status)) {
1097 req->state = RPC_REQUEST_DONE;
1098 DLIST_REMOVE(p->conn->pending, req);
1099 return;
1103 remaining -= chunk;
1108 return the event context for a dcerpc pipe
1109 used by callers who wish to operate asynchronously
1111 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1113 return p->conn->event_ctx;
1119 perform the receive side of a async dcerpc request
1121 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1122 TALLOC_CTX *mem_ctx,
1123 DATA_BLOB *stub_data)
1125 NTSTATUS status;
1127 while (req->state != RPC_REQUEST_DONE) {
1128 struct tevent_context *ctx = dcerpc_event_context(req->p);
1129 if (event_loop_once(ctx) != 0) {
1130 return NT_STATUS_CONNECTION_DISCONNECTED;
1133 *stub_data = req->payload;
1134 status = req->status;
1135 if (stub_data->data) {
1136 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1138 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1139 req->p->last_fault_code = req->fault_code;
1141 talloc_unlink(talloc_parent(req), req);
1142 return status;
1146 perform a full request/response pair on a dcerpc pipe
1148 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1149 struct GUID *object,
1150 uint16_t opnum,
1151 TALLOC_CTX *mem_ctx,
1152 DATA_BLOB *stub_data_in,
1153 DATA_BLOB *stub_data_out)
1155 struct rpc_request *req;
1157 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1158 if (req == NULL) {
1159 return NT_STATUS_NO_MEMORY;
1162 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1167 this is a paranoid NDR validator. For every packet we push onto the wire
1168 we pull it back again, then push it again. Then we compare the raw NDR data
1169 for that to the NDR we initially generated. If they don't match then we know
1170 we must have a bug in either the pull or push side of our code
1172 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1173 TALLOC_CTX *mem_ctx,
1174 DATA_BLOB blob,
1175 size_t struct_size,
1176 ndr_push_flags_fn_t ndr_push,
1177 ndr_pull_flags_fn_t ndr_pull)
1179 void *st;
1180 struct ndr_pull *pull;
1181 struct ndr_push *push;
1182 DATA_BLOB blob2;
1183 enum ndr_err_code ndr_err;
1185 st = talloc_size(mem_ctx, struct_size);
1186 if (!st) {
1187 return NT_STATUS_NO_MEMORY;
1190 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1191 if (!pull) {
1192 return NT_STATUS_NO_MEMORY;
1194 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1196 ndr_err = ndr_pull(pull, NDR_IN, st);
1197 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1198 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1199 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1200 "failed input validation pull - %s",
1201 nt_errstr(status));
1202 return ndr_map_error2ntstatus(ndr_err);
1205 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1206 if (!push) {
1207 return NT_STATUS_NO_MEMORY;
1210 ndr_err = ndr_push(push, NDR_IN, st);
1211 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1212 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1213 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1214 "failed input validation push - %s",
1215 nt_errstr(status));
1216 return ndr_map_error2ntstatus(ndr_err);
1219 blob2 = ndr_push_blob(push);
1221 if (data_blob_cmp(&blob, &blob2) != 0) {
1222 DEBUG(3,("original:\n"));
1223 dump_data(3, blob.data, blob.length);
1224 DEBUG(3,("secondary:\n"));
1225 dump_data(3, blob2.data, blob2.length);
1226 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1227 "failed input validation blobs doesn't match");
1228 return ndr_map_error2ntstatus(ndr_err);
1231 return NT_STATUS_OK;
1235 this is a paranoid NDR input validator. For every packet we pull
1236 from the wire we push it back again then pull and push it
1237 again. Then we compare the raw NDR data for that to the NDR we
1238 initially generated. If they don't match then we know we must have a
1239 bug in either the pull or push side of our code
1241 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1242 struct ndr_pull *pull_in,
1243 void *struct_ptr,
1244 size_t struct_size,
1245 ndr_push_flags_fn_t ndr_push,
1246 ndr_pull_flags_fn_t ndr_pull,
1247 ndr_print_function_t ndr_print)
1249 void *st;
1250 struct ndr_pull *pull;
1251 struct ndr_push *push;
1252 DATA_BLOB blob, blob2;
1253 TALLOC_CTX *mem_ctx = pull_in;
1254 char *s1, *s2;
1255 enum ndr_err_code ndr_err;
1257 st = talloc_size(mem_ctx, struct_size);
1258 if (!st) {
1259 return NT_STATUS_NO_MEMORY;
1261 memcpy(st, struct_ptr, struct_size);
1263 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1264 if (!push) {
1265 return NT_STATUS_NO_MEMORY;
1268 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1269 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1270 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1271 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1272 "failed output validation push - %s",
1273 nt_errstr(status));
1274 return ndr_map_error2ntstatus(ndr_err);
1277 blob = ndr_push_blob(push);
1279 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1280 if (!pull) {
1281 return NT_STATUS_NO_MEMORY;
1284 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1285 ndr_err = ndr_pull(pull, NDR_OUT, st);
1286 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1287 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1288 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1289 "failed output validation pull - %s",
1290 nt_errstr(status));
1291 return ndr_map_error2ntstatus(ndr_err);
1294 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1295 if (!push) {
1296 return NT_STATUS_NO_MEMORY;
1299 ndr_err = ndr_push(push, NDR_OUT, st);
1300 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1301 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1302 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1303 "failed output validation push2 - %s",
1304 nt_errstr(status));
1305 return ndr_map_error2ntstatus(ndr_err);
1308 blob2 = ndr_push_blob(push);
1310 if (data_blob_cmp(&blob, &blob2) != 0) {
1311 DEBUG(3,("original:\n"));
1312 dump_data(3, blob.data, blob.length);
1313 DEBUG(3,("secondary:\n"));
1314 dump_data(3, blob2.data, blob2.length);
1315 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1316 "failed output validation blobs doesn't match");
1317 return ndr_map_error2ntstatus(ndr_err);
1320 /* this checks the printed forms of the two structures, which effectively
1321 tests all of the value() attributes */
1322 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1323 NDR_OUT, struct_ptr);
1324 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1325 NDR_OUT, st);
1326 if (strcmp(s1, s2) != 0) {
1327 #if 1
1328 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1329 #else
1330 /* this is sometimes useful */
1331 printf("VALIDATE ERROR\n");
1332 file_save("wire.dat", s1, strlen(s1));
1333 file_save("gen.dat", s2, strlen(s2));
1334 system("diff -u wire.dat gen.dat");
1335 #endif
1336 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1337 "failed output validation strings doesn't match");
1338 return ndr_map_error2ntstatus(ndr_err);
1341 return NT_STATUS_OK;
1346 send a rpc request given a dcerpc_call structure
1348 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1349 const struct GUID *object,
1350 const struct ndr_interface_table *table,
1351 uint32_t opnum,
1352 bool async,
1353 TALLOC_CTX *mem_ctx,
1354 void *r)
1356 const struct ndr_interface_call *call;
1357 struct ndr_push *push;
1358 NTSTATUS status;
1359 DATA_BLOB request;
1360 struct rpc_request *req;
1361 enum ndr_err_code ndr_err;
1363 call = &table->calls[opnum];
1365 /* setup for a ndr_push_* call */
1366 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1367 if (!push) {
1368 return NULL;
1371 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1372 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1375 if (p->conn->flags & DCERPC_NDR64) {
1376 push->flags |= LIBNDR_FLAG_NDR64;
1379 /* push the structure into a blob */
1380 ndr_err = call->ndr_push(push, NDR_IN, r);
1381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1382 status = ndr_map_error2ntstatus(ndr_err);
1383 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1384 nt_errstr(status)));
1385 talloc_free(push);
1386 return NULL;
1389 /* retrieve the blob */
1390 request = ndr_push_blob(push);
1392 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1393 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1394 call->ndr_push, call->ndr_pull);
1395 if (!NT_STATUS_IS_OK(status)) {
1396 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1397 nt_errstr(status)));
1398 talloc_free(push);
1399 return NULL;
1403 DEBUG(10,("rpc request data:\n"));
1404 dump_data(10, request.data, request.length);
1406 /* make the actual dcerpc request */
1407 req = dcerpc_request_send(p, object, opnum, async, &request);
1409 if (req != NULL) {
1410 req->ndr.table = table;
1411 req->ndr.opnum = opnum;
1412 req->ndr.struct_ptr = r;
1413 req->ndr.mem_ctx = mem_ctx;
1416 talloc_free(push);
1418 return req;
1422 receive the answer from a dcerpc_ndr_request_send()
1424 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1426 struct dcerpc_pipe *p = req->p;
1427 NTSTATUS status;
1428 DATA_BLOB response;
1429 struct ndr_pull *pull;
1430 unsigned int flags;
1431 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1432 void *r = req->ndr.struct_ptr;
1433 uint32_t opnum = req->ndr.opnum;
1434 const struct ndr_interface_table *table = req->ndr.table;
1435 const struct ndr_interface_call *call = &table->calls[opnum];
1436 enum ndr_err_code ndr_err;
1438 /* make sure the recv code doesn't free the request, as we
1439 need to grab the flags element before it is freed */
1440 if (talloc_reference(p, req) == NULL) {
1441 return NT_STATUS_NO_MEMORY;
1444 status = dcerpc_request_recv(req, mem_ctx, &response);
1445 if (!NT_STATUS_IS_OK(status)) {
1446 talloc_unlink(p, req);
1447 return status;
1450 flags = req->flags;
1452 /* prepare for ndr_pull_* */
1453 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1454 if (!pull) {
1455 talloc_unlink(p, req);
1456 return NT_STATUS_NO_MEMORY;
1459 if (pull->data) {
1460 pull->data = talloc_steal(pull, pull->data);
1462 talloc_unlink(p, req);
1464 if (flags & DCERPC_PULL_BIGENDIAN) {
1465 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1468 DEBUG(10,("rpc reply data:\n"));
1469 dump_data(10, pull->data, pull->data_size);
1471 /* pull the structure from the blob */
1472 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1473 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1474 status = ndr_map_error2ntstatus(ndr_err);
1475 dcerpc_log_packet(p->conn->packet_log_dir,
1476 table, opnum, NDR_OUT,
1477 &response);
1478 return status;
1481 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1482 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1483 call->ndr_push, call->ndr_pull,
1484 call->ndr_print);
1485 if (!NT_STATUS_IS_OK(status)) {
1486 dcerpc_log_packet(p->conn->packet_log_dir,
1487 table, opnum, NDR_OUT,
1488 &response);
1489 return status;
1493 if (pull->offset != pull->data_size) {
1494 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1495 pull->data_size - pull->offset));
1496 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1497 but it turns out that early versions of NT
1498 (specifically NT3.1) add junk onto the end of rpc
1499 packets, so if we want to interoperate at all with
1500 those versions then we need to ignore this error */
1503 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1505 return NT_STATUS_OK;
1510 a useful helper function for synchronous rpc requests
1512 this can be used when you have ndr push/pull functions in the
1513 standard format
1515 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1516 const struct GUID *object,
1517 const struct ndr_interface_table *table,
1518 uint32_t opnum,
1519 TALLOC_CTX *mem_ctx,
1520 void *r)
1522 struct rpc_request *req;
1524 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1525 if (req == NULL) {
1526 return NT_STATUS_NO_MEMORY;
1529 return dcerpc_ndr_request_recv(req);
1534 a useful function for retrieving the server name we connected to
1536 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1538 if (!p->conn->transport.target_hostname) {
1539 if (!p->conn->transport.peer_name) {
1540 return "";
1542 return p->conn->transport.peer_name(p->conn);
1544 return p->conn->transport.target_hostname(p->conn);
1549 get the dcerpc auth_level for a open connection
1551 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1553 uint8_t auth_level;
1555 if (c->flags & DCERPC_SEAL) {
1556 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1557 } else if (c->flags & DCERPC_SIGN) {
1558 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1559 } else if (c->flags & DCERPC_CONNECT) {
1560 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1561 } else {
1562 auth_level = DCERPC_AUTH_LEVEL_NONE;
1564 return auth_level;
1568 Receive an alter reply from the transport
1570 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1571 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1573 struct composite_context *c;
1574 struct dcerpc_pipe *recv_pipe;
1576 c = talloc_get_type(req->async.private_data, struct composite_context);
1577 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1579 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1580 pkt->u.alter_resp.num_results == 1 &&
1581 pkt->u.alter_resp.ctx_list[0].result != 0) {
1582 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1583 pkt->u.alter_resp.ctx_list[0].reason));
1584 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1585 return;
1588 if (pkt->ptype == DCERPC_PKT_FAULT) {
1589 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1590 recv_pipe->last_fault_code = pkt->u.fault.status;
1591 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1592 return;
1595 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1596 pkt->u.alter_resp.num_results == 0 ||
1597 pkt->u.alter_resp.ctx_list[0].result != 0) {
1598 recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1599 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1600 return;
1603 /* the alter_resp might contain a reply set of credentials */
1604 if (recv_pipe->conn->security_state.auth_info &&
1605 pkt->u.alter_resp.auth_info.length) {
1606 struct dcerpc_connection *conn = recv_pipe->conn;
1607 NTSTATUS status;
1608 uint32_t auth_length;
1609 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1610 conn->security_state.auth_info, &auth_length, true);
1611 if (!NT_STATUS_IS_OK(status)) {
1612 composite_error(c, status);
1613 return;
1617 composite_done(c);
1621 send a dcerpc alter_context request
1623 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1624 TALLOC_CTX *mem_ctx,
1625 const struct ndr_syntax_id *syntax,
1626 const struct ndr_syntax_id *transfer_syntax)
1628 struct composite_context *c;
1629 struct ncacn_packet pkt;
1630 DATA_BLOB blob;
1631 struct rpc_request *req;
1633 c = composite_create(mem_ctx, p->conn->event_ctx);
1634 if (c == NULL) return NULL;
1636 c->private_data = p;
1638 p->syntax = *syntax;
1639 p->transfer_syntax = *transfer_syntax;
1641 init_ncacn_hdr(p->conn, &pkt);
1643 pkt.ptype = DCERPC_PKT_ALTER;
1644 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1645 pkt.call_id = p->conn->call_id;
1646 pkt.auth_length = 0;
1648 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1649 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1652 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1653 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1656 pkt.u.alter.max_xmit_frag = 5840;
1657 pkt.u.alter.max_recv_frag = 5840;
1658 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1659 pkt.u.alter.num_contexts = 1;
1660 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1661 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1662 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1663 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1664 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1665 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1666 pkt.u.alter.auth_info = data_blob(NULL, 0);
1668 /* construct the NDR form of the packet */
1669 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1670 p->conn->security_state.auth_info);
1671 if (!composite_is_ok(c)) return c;
1673 p->conn->transport.recv_data = dcerpc_recv_data;
1676 * we allocate a dcerpc_request so we can be in the same
1677 * request queue as normal requests
1679 req = talloc_zero(c, struct rpc_request);
1680 if (composite_nomem(req, c)) return c;
1682 req->state = RPC_REQUEST_PENDING;
1683 req->call_id = pkt.call_id;
1684 req->async.private_data = c;
1685 req->async.callback = dcerpc_composite_fail;
1686 req->p = p;
1687 req->recv_handler = dcerpc_alter_recv_handler;
1688 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1689 talloc_set_destructor(req, dcerpc_req_dequeue);
1691 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1692 if (!composite_is_ok(c)) return c;
1694 event_add_timed(c->event_ctx, req,
1695 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1696 dcerpc_timeout_handler, req);
1698 return c;
1701 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1703 NTSTATUS result = composite_wait(ctx);
1704 talloc_free(ctx);
1705 return result;
1709 send a dcerpc alter_context request
1711 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1712 TALLOC_CTX *mem_ctx,
1713 const struct ndr_syntax_id *syntax,
1714 const struct ndr_syntax_id *transfer_syntax)
1716 struct composite_context *creq;
1717 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1718 return dcerpc_alter_context_recv(creq);