lib/tdb/tools/tdbtorture.c: fixed memory leak.
[Samba/gebeck_regimport.git] / source4 / librpc / rpc / dcerpc.c
blobc8add30ef849606e1b3488c3d2b34a7d4bfaecfc
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 = talloc_reference(c, 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 return p;
122 choose the next call id to use
124 static uint32_t next_call_id(struct dcerpc_connection *c)
126 c->call_id++;
127 if (c->call_id == 0) {
128 c->call_id++;
130 return c->call_id;
133 /* we need to be able to get/set the fragment length without doing a full
134 decode */
135 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
137 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
138 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
139 } else {
140 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
144 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
146 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
147 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
148 } else {
149 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
153 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
155 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
156 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
157 } else {
158 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
164 setup for a ndr pull, also setting up any flags from the binding string
166 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
167 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
169 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
171 if (ndr == NULL) return ndr;
173 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
174 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
177 if (c->flags & DCERPC_NDR_REF_ALLOC) {
178 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
181 return ndr;
185 parse a data blob into a ncacn_packet structure. This handles both
186 input and output packets
188 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
189 struct ncacn_packet *pkt)
191 struct ndr_pull *ndr;
192 enum ndr_err_code ndr_err;
194 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
195 if (!ndr) {
196 return NT_STATUS_NO_MEMORY;
199 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
200 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
203 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
204 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
205 return ndr_map_error2ntstatus(ndr_err);
208 return NT_STATUS_OK;
212 parse the authentication information on a dcerpc response packet
214 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
215 DATA_BLOB *raw_packet,
216 struct ncacn_packet *pkt)
218 struct ndr_pull *ndr;
219 NTSTATUS status;
220 struct dcerpc_auth auth;
221 DATA_BLOB auth_blob;
222 enum ndr_err_code ndr_err;
224 if (!c->security_state.auth_info ||
225 !c->security_state.generic_state) {
226 return NT_STATUS_OK;
229 switch (c->security_state.auth_info->auth_level) {
230 case DCERPC_AUTH_LEVEL_PRIVACY:
231 case DCERPC_AUTH_LEVEL_INTEGRITY:
232 break;
234 case DCERPC_AUTH_LEVEL_CONNECT:
235 if (pkt->auth_length != 0) {
236 break;
238 return NT_STATUS_OK;
239 case DCERPC_AUTH_LEVEL_NONE:
240 if (pkt->auth_length != 0) {
241 return NT_STATUS_INVALID_NETWORK_RESPONSE;
243 return NT_STATUS_OK;
245 default:
246 return NT_STATUS_INVALID_LEVEL;
249 auth_blob.length = 8 + pkt->auth_length;
251 /* check for a valid length */
252 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
253 return NT_STATUS_INFO_LENGTH_MISMATCH;
256 auth_blob.data =
257 pkt->u.response.stub_and_verifier.data +
258 pkt->u.response.stub_and_verifier.length - auth_blob.length;
259 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
261 /* pull the auth structure */
262 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
263 if (!ndr) {
264 return NT_STATUS_NO_MEMORY;
267 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
268 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
271 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
272 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
273 return ndr_map_error2ntstatus(ndr_err);
275 status = NT_STATUS_OK;
277 /* check signature or unseal the packet */
278 switch (c->security_state.auth_info->auth_level) {
279 case DCERPC_AUTH_LEVEL_PRIVACY:
280 status = gensec_unseal_packet(c->security_state.generic_state,
281 mem_ctx,
282 raw_packet->data + DCERPC_REQUEST_LENGTH,
283 pkt->u.response.stub_and_verifier.length,
284 raw_packet->data,
285 raw_packet->length - auth.credentials.length,
286 &auth.credentials);
287 memcpy(pkt->u.response.stub_and_verifier.data,
288 raw_packet->data + DCERPC_REQUEST_LENGTH,
289 pkt->u.response.stub_and_verifier.length);
290 break;
292 case DCERPC_AUTH_LEVEL_INTEGRITY:
293 status = gensec_check_packet(c->security_state.generic_state,
294 mem_ctx,
295 pkt->u.response.stub_and_verifier.data,
296 pkt->u.response.stub_and_verifier.length,
297 raw_packet->data,
298 raw_packet->length - auth.credentials.length,
299 &auth.credentials);
300 break;
302 case DCERPC_AUTH_LEVEL_CONNECT:
303 /* for now we ignore possible signatures here */
304 status = NT_STATUS_OK;
305 break;
307 default:
308 status = NT_STATUS_INVALID_LEVEL;
309 break;
312 /* remove the indicated amount of paddiing */
313 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
314 return NT_STATUS_INFO_LENGTH_MISMATCH;
316 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
318 return status;
323 push a dcerpc request packet into a blob, possibly signing it.
325 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
326 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
327 size_t sig_size,
328 struct ncacn_packet *pkt)
330 NTSTATUS status;
331 struct ndr_push *ndr;
332 DATA_BLOB creds2;
333 size_t payload_length;
334 enum ndr_err_code ndr_err;
335 size_t hdr_size = DCERPC_REQUEST_LENGTH;
337 /* non-signed packets are simpler */
338 if (sig_size == 0) {
339 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
342 switch (c->security_state.auth_info->auth_level) {
343 case DCERPC_AUTH_LEVEL_PRIVACY:
344 case DCERPC_AUTH_LEVEL_INTEGRITY:
345 break;
347 case DCERPC_AUTH_LEVEL_CONNECT:
348 /* TODO: let the gensec mech decide if it wants to generate a signature */
349 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
351 case DCERPC_AUTH_LEVEL_NONE:
352 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
354 default:
355 return NT_STATUS_INVALID_LEVEL;
358 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
359 if (!ndr) {
360 return NT_STATUS_NO_MEMORY;
363 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
364 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
367 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
368 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
369 hdr_size += 16;
372 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
373 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
374 return ndr_map_error2ntstatus(ndr_err);
376 status = NT_STATUS_OK;
378 /* pad to 16 byte multiple in the payload portion of the
379 packet. This matches what w2k3 does */
380 c->security_state.auth_info->auth_pad_length =
381 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
382 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
383 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
384 return ndr_map_error2ntstatus(ndr_err);
386 status = NT_STATUS_OK;
388 payload_length = pkt->u.request.stub_and_verifier.length +
389 c->security_state.auth_info->auth_pad_length;
391 /* we start without signature, it will appended later */
392 c->security_state.auth_info->credentials = data_blob(NULL,0);
394 /* add the auth verifier */
395 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
396 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
397 return ndr_map_error2ntstatus(ndr_err);
399 status = NT_STATUS_OK;
401 /* extract the whole packet as a blob */
402 *blob = ndr_push_blob(ndr);
405 * Setup the frag and auth length in the packet buffer.
406 * This is needed if the GENSEC mech does AEAD signing
407 * of the packet headers. The signature itself will be
408 * appended later.
410 dcerpc_set_frag_length(blob, blob->length + sig_size);
411 dcerpc_set_auth_length(blob, sig_size);
413 /* sign or seal the packet */
414 switch (c->security_state.auth_info->auth_level) {
415 case DCERPC_AUTH_LEVEL_PRIVACY:
416 status = gensec_seal_packet(c->security_state.generic_state,
417 mem_ctx,
418 blob->data + hdr_size,
419 payload_length,
420 blob->data,
421 blob->length,
422 &creds2);
423 if (!NT_STATUS_IS_OK(status)) {
424 return status;
426 break;
428 case DCERPC_AUTH_LEVEL_INTEGRITY:
429 status = gensec_sign_packet(c->security_state.generic_state,
430 mem_ctx,
431 blob->data + hdr_size,
432 payload_length,
433 blob->data,
434 blob->length,
435 &creds2);
436 if (!NT_STATUS_IS_OK(status)) {
437 return status;
439 break;
441 default:
442 status = NT_STATUS_INVALID_LEVEL;
443 break;
446 if (creds2.length != sig_size) {
447 DEBUG(0,("dcesrv_auth_response: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
448 creds2.length, (uint32_t)sig_size,
449 c->security_state.auth_info->auth_pad_length,
450 pkt->u.request.stub_and_verifier.length));
451 return NT_STATUS_INTERNAL_ERROR;
454 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
455 return NT_STATUS_NO_MEMORY;
458 return NT_STATUS_OK;
463 fill in the fixed values in a dcerpc header
465 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
467 pkt->rpc_vers = 5;
468 pkt->rpc_vers_minor = 0;
469 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
470 pkt->drep[0] = 0;
471 } else {
472 pkt->drep[0] = DCERPC_DREP_LE;
474 pkt->drep[1] = 0;
475 pkt->drep[2] = 0;
476 pkt->drep[3] = 0;
480 map a bind nak reason to a NTSTATUS
482 static NTSTATUS dcerpc_map_reason(uint16_t reason)
484 switch (reason) {
485 case DCERPC_BIND_REASON_ASYNTAX:
486 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
487 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
488 return NT_STATUS_INVALID_PARAMETER;
490 return NT_STATUS_UNSUCCESSFUL;
494 a bind or alter context has failed
496 static void dcerpc_composite_fail(struct rpc_request *req)
498 struct composite_context *c = talloc_get_type(req->async.private_data,
499 struct composite_context);
500 composite_error(c, req->status);
504 remove requests from the pending or queued queues
506 static int dcerpc_req_dequeue(struct rpc_request *req)
508 switch (req->state) {
509 case RPC_REQUEST_QUEUED:
510 DLIST_REMOVE(req->p->conn->request_queue, req);
511 break;
512 case RPC_REQUEST_PENDING:
513 DLIST_REMOVE(req->p->conn->pending, req);
514 break;
515 case RPC_REQUEST_DONE:
516 break;
518 return 0;
523 mark the dcerpc connection dead. All outstanding requests get an error
525 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
527 if (conn->dead) return;
529 conn->dead = true;
531 if (conn->transport.shutdown_pipe) {
532 conn->transport.shutdown_pipe(conn, status);
535 /* all pending requests get the error */
536 while (conn->pending) {
537 struct rpc_request *req = conn->pending;
538 dcerpc_req_dequeue(req);
539 req->state = RPC_REQUEST_DONE;
540 req->status = status;
541 if (req->async.callback) {
542 req->async.callback(req);
546 talloc_set_destructor(conn, NULL);
547 if (conn->free_skipped) {
548 talloc_free(conn);
553 forward declarations of the recv_data handlers for the types of
554 packets we need to handle
556 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
557 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
560 receive a dcerpc reply from the transport. Here we work out what
561 type of reply it is (normal request, bind or alter context) and
562 dispatch to the appropriate handler
564 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
566 struct ncacn_packet pkt;
568 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
569 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
572 /* the transport may be telling us of a severe error, such as
573 a dropped socket */
574 if (!NT_STATUS_IS_OK(status)) {
575 data_blob_free(blob);
576 dcerpc_connection_dead(conn, status);
577 return;
580 /* parse the basic packet to work out what type of response this is */
581 status = ncacn_pull(conn, blob, blob->data, &pkt);
582 if (!NT_STATUS_IS_OK(status)) {
583 data_blob_free(blob);
584 dcerpc_connection_dead(conn, status);
587 dcerpc_request_recv_data(conn, blob, &pkt);
592 Receive a bind reply from the transport
594 static void dcerpc_bind_recv_handler(struct rpc_request *req,
595 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
597 struct composite_context *c;
598 struct dcerpc_connection *conn;
600 c = talloc_get_type(req->async.private_data, struct composite_context);
602 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
603 DEBUG(2,("dcerpc: bind_nak reason %d\n",
604 pkt->u.bind_nak.reject_reason));
605 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
606 reject_reason));
607 return;
610 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
611 (pkt->u.bind_ack.num_results == 0) ||
612 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
613 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
614 return;
617 conn = req->p->conn;
619 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
620 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
622 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
623 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
624 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
627 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
628 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
629 conn->flags |= DCERPC_HEADER_SIGNING;
632 /* the bind_ack might contain a reply set of credentials */
633 if (conn->security_state.auth_info &&
634 pkt->u.bind_ack.auth_info.length) {
635 enum ndr_err_code ndr_err;
636 ndr_err = ndr_pull_struct_blob(
637 &pkt->u.bind_ack.auth_info, conn,
638 NULL,
639 conn->security_state.auth_info,
640 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
641 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
642 c->status = ndr_map_error2ntstatus(ndr_err);
643 if (!composite_is_ok(c)) return;
647 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
649 composite_done(c);
653 handle timeouts of individual dcerpc requests
655 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
656 struct timeval t, void *private_data)
658 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
660 if (req->ignore_timeout) {
661 dcerpc_req_dequeue(req);
662 req->state = RPC_REQUEST_DONE;
663 req->status = NT_STATUS_IO_TIMEOUT;
664 if (req->async.callback) {
665 req->async.callback(req);
667 return;
670 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
674 send a async dcerpc bind request
676 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
677 TALLOC_CTX *mem_ctx,
678 const struct ndr_syntax_id *syntax,
679 const struct ndr_syntax_id *transfer_syntax)
681 struct composite_context *c;
682 struct ncacn_packet pkt;
683 DATA_BLOB blob;
684 struct rpc_request *req;
686 c = composite_create(mem_ctx,p->conn->event_ctx);
687 if (c == NULL) return NULL;
689 c->private_data = p;
691 p->syntax = *syntax;
692 p->transfer_syntax = *transfer_syntax;
694 init_ncacn_hdr(p->conn, &pkt);
696 pkt.ptype = DCERPC_PKT_BIND;
697 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
698 pkt.call_id = p->conn->call_id;
699 pkt.auth_length = 0;
701 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
702 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
705 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
706 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
709 pkt.u.bind.max_xmit_frag = 5840;
710 pkt.u.bind.max_recv_frag = 5840;
711 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
712 pkt.u.bind.num_contexts = 1;
713 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
714 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
715 pkt.u.bind.ctx_list[0].context_id = p->context_id;
716 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
717 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
718 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
719 pkt.u.bind.auth_info = data_blob(NULL, 0);
721 /* construct the NDR form of the packet */
722 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
723 p->conn->security_state.auth_info);
724 if (!composite_is_ok(c)) return c;
726 p->conn->transport.recv_data = dcerpc_recv_data;
729 * we allocate a dcerpc_request so we can be in the same
730 * request queue as normal requests
732 req = talloc_zero(c, struct rpc_request);
733 if (composite_nomem(req, c)) return c;
735 req->state = RPC_REQUEST_PENDING;
736 req->call_id = pkt.call_id;
737 req->async.private_data = c;
738 req->async.callback = dcerpc_composite_fail;
739 req->p = p;
740 req->recv_handler = dcerpc_bind_recv_handler;
741 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
742 talloc_set_destructor(req, dcerpc_req_dequeue);
744 c->status = p->conn->transport.send_request(p->conn, &blob,
745 true);
746 if (!composite_is_ok(c)) return c;
748 event_add_timed(c->event_ctx, req,
749 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
750 dcerpc_timeout_handler, req);
752 return c;
756 recv side of async dcerpc bind request
758 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
760 NTSTATUS result = composite_wait(ctx);
761 talloc_free(ctx);
762 return result;
766 perform a continued bind (and auth3)
768 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
769 TALLOC_CTX *mem_ctx)
771 struct ncacn_packet pkt;
772 NTSTATUS status;
773 DATA_BLOB blob;
775 init_ncacn_hdr(p->conn, &pkt);
777 pkt.ptype = DCERPC_PKT_AUTH3;
778 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
779 pkt.call_id = next_call_id(p->conn);
780 pkt.auth_length = 0;
781 pkt.u.auth3._pad = 0;
782 pkt.u.auth3.auth_info = data_blob(NULL, 0);
784 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
785 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
788 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
789 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
792 /* construct the NDR form of the packet */
793 status = ncacn_push_auth(&blob, mem_ctx,
794 p->conn->iconv_convenience,
795 &pkt,
796 p->conn->security_state.auth_info);
797 if (!NT_STATUS_IS_OK(status)) {
798 return status;
801 /* send it on its way */
802 status = p->conn->transport.send_request(p->conn, &blob, false);
803 if (!NT_STATUS_IS_OK(status)) {
804 return status;
807 return NT_STATUS_OK;
812 process a fragment received from the transport layer during a
813 request
815 This function frees the data
817 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
818 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
820 struct rpc_request *req;
821 uint_t length;
822 NTSTATUS status = NT_STATUS_OK;
825 if this is an authenticated connection then parse and check
826 the auth info. We have to do this before finding the
827 matching packet, as the request structure might have been
828 removed due to a timeout, but if it has been we still need
829 to run the auth routines so that we don't get the sign/seal
830 info out of step with the server
832 if (c->security_state.auth_info && c->security_state.generic_state &&
833 pkt->ptype == DCERPC_PKT_RESPONSE) {
834 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
837 /* find the matching request */
838 for (req=c->pending;req;req=req->next) {
839 if (pkt->call_id == req->call_id) break;
842 #if 0
843 /* useful for testing certain vendors RPC servers */
844 if (req == NULL && c->pending && pkt->call_id == 0) {
845 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
846 req = c->pending;
848 #endif
850 if (req == NULL) {
851 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
852 data_blob_free(raw_packet);
853 return;
856 talloc_steal(req, raw_packet->data);
858 if (req->recv_handler != NULL) {
859 dcerpc_req_dequeue(req);
860 req->state = RPC_REQUEST_DONE;
861 req->recv_handler(req, raw_packet, pkt);
862 return;
865 if (pkt->ptype == DCERPC_PKT_FAULT) {
866 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
867 req->fault_code = pkt->u.fault.status;
868 req->status = NT_STATUS_NET_WRITE_FAULT;
869 goto req_done;
872 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
873 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
874 (int)pkt->ptype));
875 req->fault_code = DCERPC_FAULT_OTHER;
876 req->status = NT_STATUS_NET_WRITE_FAULT;
877 goto req_done;
880 /* now check the status from the auth routines, and if it failed then fail
881 this request accordingly */
882 if (!NT_STATUS_IS_OK(status)) {
883 req->status = status;
884 goto req_done;
887 length = pkt->u.response.stub_and_verifier.length;
889 if (length > 0) {
890 req->payload.data = talloc_realloc(req,
891 req->payload.data,
892 uint8_t,
893 req->payload.length + length);
894 if (!req->payload.data) {
895 req->status = NT_STATUS_NO_MEMORY;
896 goto req_done;
898 memcpy(req->payload.data+req->payload.length,
899 pkt->u.response.stub_and_verifier.data, length);
900 req->payload.length += length;
903 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
904 c->transport.send_read(c);
905 return;
908 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
909 req->flags |= DCERPC_PULL_BIGENDIAN;
910 } else {
911 req->flags &= ~DCERPC_PULL_BIGENDIAN;
915 req_done:
916 /* we've got the full payload */
917 req->state = RPC_REQUEST_DONE;
918 DLIST_REMOVE(c->pending, req);
920 if (c->request_queue != NULL) {
921 /* We have to look at shipping further requests before calling
922 * the async function, that one might close the pipe */
923 dcerpc_ship_next_request(c);
926 if (req->async.callback) {
927 req->async.callback(req);
932 perform the send side of a async dcerpc request
934 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
935 const struct GUID *object,
936 uint16_t opnum,
937 bool async,
938 DATA_BLOB *stub_data)
940 struct rpc_request *req;
942 p->conn->transport.recv_data = dcerpc_recv_data;
944 req = talloc(p, struct rpc_request);
945 if (req == NULL) {
946 return NULL;
949 req->p = p;
950 req->call_id = next_call_id(p->conn);
951 req->status = NT_STATUS_OK;
952 req->state = RPC_REQUEST_QUEUED;
953 req->payload = data_blob(NULL, 0);
954 req->flags = 0;
955 req->fault_code = 0;
956 req->async_call = async;
957 req->ignore_timeout = false;
958 req->async.callback = NULL;
959 req->async.private_data = NULL;
960 req->recv_handler = NULL;
962 if (object != NULL) {
963 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
964 if (req->object == NULL) {
965 talloc_free(req);
966 return NULL;
968 } else {
969 req->object = NULL;
972 req->opnum = opnum;
973 req->request_data.length = stub_data->length;
974 req->request_data.data = talloc_reference(req, stub_data->data);
975 if (req->request_data.length && req->request_data.data == NULL) {
976 return NULL;
979 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
980 talloc_set_destructor(req, dcerpc_req_dequeue);
982 dcerpc_ship_next_request(p->conn);
984 if (p->request_timeout) {
985 event_add_timed(dcerpc_event_context(p), req,
986 timeval_current_ofs(p->request_timeout, 0),
987 dcerpc_timeout_handler, req);
990 return req;
994 Send a request using the transport
997 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
999 struct rpc_request *req;
1000 struct dcerpc_pipe *p;
1001 DATA_BLOB *stub_data;
1002 struct ncacn_packet pkt;
1003 DATA_BLOB blob;
1004 uint32_t remaining, chunk_size;
1005 bool first_packet = true;
1006 size_t sig_size = 0;
1008 req = c->request_queue;
1009 if (req == NULL) {
1010 return;
1013 p = req->p;
1014 stub_data = &req->request_data;
1016 if (!req->async_call && (c->pending != NULL)) {
1017 return;
1020 DLIST_REMOVE(c->request_queue, req);
1021 DLIST_ADD(c->pending, req);
1022 req->state = RPC_REQUEST_PENDING;
1024 init_ncacn_hdr(p->conn, &pkt);
1026 remaining = stub_data->length;
1028 /* we can write a full max_recv_frag size, minus the dcerpc
1029 request header size */
1030 chunk_size = p->conn->srv_max_recv_frag;
1031 chunk_size -= DCERPC_REQUEST_LENGTH;
1032 if (c->security_state.auth_info &&
1033 c->security_state.generic_state) {
1034 sig_size = gensec_sig_size(c->security_state.generic_state,
1035 p->conn->srv_max_recv_frag);
1036 if (sig_size) {
1037 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1038 chunk_size -= sig_size;
1041 chunk_size -= (chunk_size % 16);
1043 pkt.ptype = DCERPC_PKT_REQUEST;
1044 pkt.call_id = req->call_id;
1045 pkt.auth_length = 0;
1046 pkt.pfc_flags = 0;
1047 pkt.u.request.alloc_hint = remaining;
1048 pkt.u.request.context_id = p->context_id;
1049 pkt.u.request.opnum = req->opnum;
1051 if (req->object) {
1052 pkt.u.request.object.object = *req->object;
1053 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1054 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1057 /* we send a series of pdus without waiting for a reply */
1058 while (remaining > 0 || first_packet) {
1059 uint32_t chunk = MIN(chunk_size, remaining);
1060 bool last_frag = false;
1061 bool do_trans = false;
1063 first_packet = false;
1064 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1066 if (remaining == stub_data->length) {
1067 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1069 if (chunk == remaining) {
1070 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1071 last_frag = true;
1074 pkt.u.request.stub_and_verifier.data = stub_data->data +
1075 (stub_data->length - remaining);
1076 pkt.u.request.stub_and_verifier.length = chunk;
1078 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1079 if (!NT_STATUS_IS_OK(req->status)) {
1080 req->state = RPC_REQUEST_DONE;
1081 DLIST_REMOVE(p->conn->pending, req);
1082 return;
1085 if (last_frag && !req->async_call) {
1086 do_trans = true;
1089 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1090 if (!NT_STATUS_IS_OK(req->status)) {
1091 req->state = RPC_REQUEST_DONE;
1092 DLIST_REMOVE(p->conn->pending, req);
1093 return;
1096 if (last_frag && !do_trans) {
1097 req->status = p->conn->transport.send_read(p->conn);
1098 if (!NT_STATUS_IS_OK(req->status)) {
1099 req->state = RPC_REQUEST_DONE;
1100 DLIST_REMOVE(p->conn->pending, req);
1101 return;
1105 remaining -= chunk;
1110 return the event context for a dcerpc pipe
1111 used by callers who wish to operate asynchronously
1113 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1115 return p->conn->event_ctx;
1121 perform the receive side of a async dcerpc request
1123 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1124 TALLOC_CTX *mem_ctx,
1125 DATA_BLOB *stub_data)
1127 NTSTATUS status;
1129 while (req->state != RPC_REQUEST_DONE) {
1130 struct tevent_context *ctx = dcerpc_event_context(req->p);
1131 if (event_loop_once(ctx) != 0) {
1132 return NT_STATUS_CONNECTION_DISCONNECTED;
1135 *stub_data = req->payload;
1136 status = req->status;
1137 if (stub_data->data) {
1138 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1140 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1141 req->p->last_fault_code = req->fault_code;
1143 talloc_free(req);
1144 return status;
1148 perform a full request/response pair on a dcerpc pipe
1150 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1151 struct GUID *object,
1152 uint16_t opnum,
1153 TALLOC_CTX *mem_ctx,
1154 DATA_BLOB *stub_data_in,
1155 DATA_BLOB *stub_data_out)
1157 struct rpc_request *req;
1159 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1160 if (req == NULL) {
1161 return NT_STATUS_NO_MEMORY;
1164 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1169 this is a paranoid NDR validator. For every packet we push onto the wire
1170 we pull it back again, then push it again. Then we compare the raw NDR data
1171 for that to the NDR we initially generated. If they don't match then we know
1172 we must have a bug in either the pull or push side of our code
1174 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1175 TALLOC_CTX *mem_ctx,
1176 DATA_BLOB blob,
1177 size_t struct_size,
1178 ndr_push_flags_fn_t ndr_push,
1179 ndr_pull_flags_fn_t ndr_pull)
1181 void *st;
1182 struct ndr_pull *pull;
1183 struct ndr_push *push;
1184 DATA_BLOB blob2;
1185 enum ndr_err_code ndr_err;
1187 st = talloc_size(mem_ctx, struct_size);
1188 if (!st) {
1189 return NT_STATUS_NO_MEMORY;
1192 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1193 if (!pull) {
1194 return NT_STATUS_NO_MEMORY;
1196 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1198 ndr_err = ndr_pull(pull, NDR_IN, st);
1199 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1200 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1201 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1202 "failed input validation pull - %s",
1203 nt_errstr(status));
1204 return ndr_map_error2ntstatus(ndr_err);
1207 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1208 if (!push) {
1209 return NT_STATUS_NO_MEMORY;
1212 ndr_err = ndr_push(push, NDR_IN, st);
1213 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1214 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1215 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1216 "failed input validation push - %s",
1217 nt_errstr(status));
1218 return ndr_map_error2ntstatus(ndr_err);
1221 blob2 = ndr_push_blob(push);
1223 if (data_blob_cmp(&blob, &blob2) != 0) {
1224 DEBUG(3,("original:\n"));
1225 dump_data(3, blob.data, blob.length);
1226 DEBUG(3,("secondary:\n"));
1227 dump_data(3, blob2.data, blob2.length);
1228 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1229 "failed input validation blobs doesn't match");
1230 return ndr_map_error2ntstatus(ndr_err);
1233 return NT_STATUS_OK;
1237 this is a paranoid NDR input validator. For every packet we pull
1238 from the wire we push it back again then pull and push it
1239 again. Then we compare the raw NDR data for that to the NDR we
1240 initially generated. If they don't match then we know we must have a
1241 bug in either the pull or push side of our code
1243 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1244 struct ndr_pull *pull_in,
1245 void *struct_ptr,
1246 size_t struct_size,
1247 ndr_push_flags_fn_t ndr_push,
1248 ndr_pull_flags_fn_t ndr_pull,
1249 ndr_print_function_t ndr_print)
1251 void *st;
1252 struct ndr_pull *pull;
1253 struct ndr_push *push;
1254 DATA_BLOB blob, blob2;
1255 TALLOC_CTX *mem_ctx = pull_in;
1256 char *s1, *s2;
1257 enum ndr_err_code ndr_err;
1259 st = talloc_size(mem_ctx, struct_size);
1260 if (!st) {
1261 return NT_STATUS_NO_MEMORY;
1263 memcpy(st, struct_ptr, struct_size);
1265 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1266 if (!push) {
1267 return NT_STATUS_NO_MEMORY;
1270 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1271 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1272 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1273 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1274 "failed output validation push - %s",
1275 nt_errstr(status));
1276 return ndr_map_error2ntstatus(ndr_err);
1279 blob = ndr_push_blob(push);
1281 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1282 if (!pull) {
1283 return NT_STATUS_NO_MEMORY;
1286 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1287 ndr_err = ndr_pull(pull, NDR_OUT, st);
1288 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1289 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1290 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1291 "failed output validation pull - %s",
1292 nt_errstr(status));
1293 return ndr_map_error2ntstatus(ndr_err);
1296 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1297 if (!push) {
1298 return NT_STATUS_NO_MEMORY;
1301 ndr_err = ndr_push(push, NDR_OUT, st);
1302 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1303 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1304 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1305 "failed output validation push2 - %s",
1306 nt_errstr(status));
1307 return ndr_map_error2ntstatus(ndr_err);
1310 blob2 = ndr_push_blob(push);
1312 if (data_blob_cmp(&blob, &blob2) != 0) {
1313 DEBUG(3,("original:\n"));
1314 dump_data(3, blob.data, blob.length);
1315 DEBUG(3,("secondary:\n"));
1316 dump_data(3, blob2.data, blob2.length);
1317 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1318 "failed output validation blobs doesn't match");
1319 return ndr_map_error2ntstatus(ndr_err);
1322 /* this checks the printed forms of the two structures, which effectively
1323 tests all of the value() attributes */
1324 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1325 NDR_OUT, struct_ptr);
1326 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1327 NDR_OUT, st);
1328 if (strcmp(s1, s2) != 0) {
1329 #if 1
1330 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1331 #else
1332 /* this is sometimes useful */
1333 printf("VALIDATE ERROR\n");
1334 file_save("wire.dat", s1, strlen(s1));
1335 file_save("gen.dat", s2, strlen(s2));
1336 system("diff -u wire.dat gen.dat");
1337 #endif
1338 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1339 "failed output validation strings doesn't match");
1340 return ndr_map_error2ntstatus(ndr_err);
1343 return NT_STATUS_OK;
1348 send a rpc request given a dcerpc_call structure
1350 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1351 const struct GUID *object,
1352 const struct ndr_interface_table *table,
1353 uint32_t opnum,
1354 bool async,
1355 TALLOC_CTX *mem_ctx,
1356 void *r)
1358 const struct ndr_interface_call *call;
1359 struct ndr_push *push;
1360 NTSTATUS status;
1361 DATA_BLOB request;
1362 struct rpc_request *req;
1363 enum ndr_err_code ndr_err;
1365 call = &table->calls[opnum];
1367 /* setup for a ndr_push_* call */
1368 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1369 if (!push) {
1370 return NULL;
1373 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1374 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1377 /* push the structure into a blob */
1378 ndr_err = call->ndr_push(push, NDR_IN, r);
1379 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1380 status = ndr_map_error2ntstatus(ndr_err);
1381 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1382 nt_errstr(status)));
1383 talloc_free(push);
1384 return NULL;
1387 /* retrieve the blob */
1388 request = ndr_push_blob(push);
1390 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1391 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1392 call->ndr_push, call->ndr_pull);
1393 if (!NT_STATUS_IS_OK(status)) {
1394 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1395 nt_errstr(status)));
1396 talloc_free(push);
1397 return NULL;
1401 DEBUG(10,("rpc request data:\n"));
1402 dump_data(10, request.data, request.length);
1404 /* make the actual dcerpc request */
1405 req = dcerpc_request_send(p, object, opnum, async, &request);
1407 if (req != NULL) {
1408 req->ndr.table = table;
1409 req->ndr.opnum = opnum;
1410 req->ndr.struct_ptr = r;
1411 req->ndr.mem_ctx = mem_ctx;
1414 talloc_free(push);
1416 return req;
1420 receive the answer from a dcerpc_ndr_request_send()
1422 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1424 struct dcerpc_pipe *p = req->p;
1425 NTSTATUS status;
1426 DATA_BLOB response;
1427 struct ndr_pull *pull;
1428 uint_t flags;
1429 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1430 void *r = req->ndr.struct_ptr;
1431 uint32_t opnum = req->ndr.opnum;
1432 const struct ndr_interface_table *table = req->ndr.table;
1433 const struct ndr_interface_call *call = &table->calls[opnum];
1434 enum ndr_err_code ndr_err;
1436 /* make sure the recv code doesn't free the request, as we
1437 need to grab the flags element before it is freed */
1438 if (talloc_reference(p, req) == NULL) {
1439 return NT_STATUS_NO_MEMORY;
1442 status = dcerpc_request_recv(req, mem_ctx, &response);
1443 if (!NT_STATUS_IS_OK(status)) {
1444 talloc_unlink(p, req);
1445 return status;
1448 flags = req->flags;
1450 /* prepare for ndr_pull_* */
1451 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1452 if (!pull) {
1453 talloc_unlink(p, req);
1454 return NT_STATUS_NO_MEMORY;
1457 if (pull->data) {
1458 pull->data = talloc_steal(pull, pull->data);
1460 talloc_unlink(p, req);
1462 if (flags & DCERPC_PULL_BIGENDIAN) {
1463 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1466 DEBUG(10,("rpc reply data:\n"));
1467 dump_data(10, pull->data, pull->data_size);
1469 /* pull the structure from the blob */
1470 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1471 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1472 status = ndr_map_error2ntstatus(ndr_err);
1473 dcerpc_log_packet(p->conn->packet_log_dir,
1474 table, opnum, NDR_OUT,
1475 &response);
1476 return status;
1479 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1480 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1481 call->ndr_push, call->ndr_pull,
1482 call->ndr_print);
1483 if (!NT_STATUS_IS_OK(status)) {
1484 dcerpc_log_packet(p->conn->packet_log_dir,
1485 table, opnum, NDR_OUT,
1486 &response);
1487 return status;
1491 if (pull->offset != pull->data_size) {
1492 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1493 pull->data_size - pull->offset));
1494 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1495 but it turns out that early versions of NT
1496 (specifically NT3.1) add junk onto the end of rpc
1497 packets, so if we want to interoperate at all with
1498 those versions then we need to ignore this error */
1501 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1503 return NT_STATUS_OK;
1508 a useful helper function for synchronous rpc requests
1510 this can be used when you have ndr push/pull functions in the
1511 standard format
1513 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1514 const struct GUID *object,
1515 const struct ndr_interface_table *table,
1516 uint32_t opnum,
1517 TALLOC_CTX *mem_ctx,
1518 void *r)
1520 struct rpc_request *req;
1522 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1523 if (req == NULL) {
1524 return NT_STATUS_NO_MEMORY;
1527 return dcerpc_ndr_request_recv(req);
1532 a useful function for retrieving the server name we connected to
1534 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1536 if (!p->conn->transport.target_hostname) {
1537 if (!p->conn->transport.peer_name) {
1538 return "";
1540 return p->conn->transport.peer_name(p->conn);
1542 return p->conn->transport.target_hostname(p->conn);
1547 get the dcerpc auth_level for a open connection
1549 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1551 uint8_t auth_level;
1553 if (c->flags & DCERPC_SEAL) {
1554 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1555 } else if (c->flags & DCERPC_SIGN) {
1556 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1557 } else if (c->flags & DCERPC_CONNECT) {
1558 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1559 } else {
1560 auth_level = DCERPC_AUTH_LEVEL_NONE;
1562 return auth_level;
1566 Receive an alter reply from the transport
1568 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1569 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1571 struct composite_context *c;
1572 struct dcerpc_pipe *recv_pipe;
1574 c = talloc_get_type(req->async.private_data, struct composite_context);
1575 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1577 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1578 pkt->u.alter_resp.num_results == 1 &&
1579 pkt->u.alter_resp.ctx_list[0].result != 0) {
1580 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1581 pkt->u.alter_resp.ctx_list[0].reason));
1582 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1583 return;
1586 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1587 pkt->u.alter_resp.num_results == 0 ||
1588 pkt->u.alter_resp.ctx_list[0].result != 0) {
1589 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1590 return;
1593 /* the alter_resp might contain a reply set of credentials */
1594 if (recv_pipe->conn->security_state.auth_info &&
1595 pkt->u.alter_resp.auth_info.length) {
1596 enum ndr_err_code ndr_err;
1597 ndr_err = ndr_pull_struct_blob(
1598 &pkt->u.alter_resp.auth_info, recv_pipe,
1599 NULL,
1600 recv_pipe->conn->security_state.auth_info,
1601 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1602 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1603 c->status = ndr_map_error2ntstatus(ndr_err);
1604 if (!composite_is_ok(c)) return;
1608 composite_done(c);
1612 send a dcerpc alter_context request
1614 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1615 TALLOC_CTX *mem_ctx,
1616 const struct ndr_syntax_id *syntax,
1617 const struct ndr_syntax_id *transfer_syntax)
1619 struct composite_context *c;
1620 struct ncacn_packet pkt;
1621 DATA_BLOB blob;
1622 struct rpc_request *req;
1624 c = composite_create(mem_ctx, p->conn->event_ctx);
1625 if (c == NULL) return NULL;
1627 c->private_data = p;
1629 p->syntax = *syntax;
1630 p->transfer_syntax = *transfer_syntax;
1632 init_ncacn_hdr(p->conn, &pkt);
1634 pkt.ptype = DCERPC_PKT_ALTER;
1635 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1636 pkt.call_id = p->conn->call_id;
1637 pkt.auth_length = 0;
1639 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1640 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1643 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1644 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1647 pkt.u.alter.max_xmit_frag = 5840;
1648 pkt.u.alter.max_recv_frag = 5840;
1649 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1650 pkt.u.alter.num_contexts = 1;
1651 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1652 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1653 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1654 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1655 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1656 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1657 pkt.u.alter.auth_info = data_blob(NULL, 0);
1659 /* construct the NDR form of the packet */
1660 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1661 p->conn->security_state.auth_info);
1662 if (!composite_is_ok(c)) return c;
1664 p->conn->transport.recv_data = dcerpc_recv_data;
1667 * we allocate a dcerpc_request so we can be in the same
1668 * request queue as normal requests
1670 req = talloc_zero(c, struct rpc_request);
1671 if (composite_nomem(req, c)) return c;
1673 req->state = RPC_REQUEST_PENDING;
1674 req->call_id = pkt.call_id;
1675 req->async.private_data = c;
1676 req->async.callback = dcerpc_composite_fail;
1677 req->p = p;
1678 req->recv_handler = dcerpc_alter_recv_handler;
1679 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1680 talloc_set_destructor(req, dcerpc_req_dequeue);
1682 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1683 if (!composite_is_ok(c)) return c;
1685 event_add_timed(c->event_ctx, req,
1686 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1687 dcerpc_timeout_handler, req);
1689 return c;
1692 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1694 NTSTATUS result = composite_wait(ctx);
1695 talloc_free(ctx);
1696 return result;
1700 send a dcerpc alter_context request
1702 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1703 TALLOC_CTX *mem_ctx,
1704 const struct ndr_syntax_id *syntax,
1705 const struct ndr_syntax_id *transfer_syntax)
1707 struct composite_context *creq;
1708 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1709 return dcerpc_alter_context_recv(creq);