Change uint_t to unsigned int in source4
[Samba/gebeck_regimport.git] / source4 / librpc / rpc / dcerpc.c
blobc006693bab6404c1e65c0fda76f625d4754359f4
1 /*
2 Unix SMB/CIFS implementation.
3 raw dcerpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
34 _PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
36 return gensec_init(lp_ctx);
39 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
45 if (conn->dead) {
46 conn->free_skipped = true;
47 return -1;
49 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
50 return 0;
54 /* initialise a dcerpc connection.
55 the event context is optional
57 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
58 struct tevent_context *ev,
59 struct smb_iconv_convenience *ic)
61 struct dcerpc_connection *c;
63 c = talloc_zero(mem_ctx, struct dcerpc_connection);
64 if (!c) {
65 return NULL;
68 c->iconv_convenience = talloc_reference(c, ic);
70 c->event_ctx = ev;
72 if (c->event_ctx == NULL) {
73 talloc_free(c);
74 return NULL;
77 c->call_id = 1;
78 c->security_state.auth_info = NULL;
79 c->security_state.session_key = dcerpc_generic_session_key;
80 c->security_state.generic_state = NULL;
81 c->binding_string = NULL;
82 c->flags = 0;
83 c->srv_max_xmit_frag = 0;
84 c->srv_max_recv_frag = 0;
85 c->pending = NULL;
87 talloc_set_destructor(c, dcerpc_connection_destructor);
89 return c;
92 /* initialise a dcerpc pipe. */
93 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
94 struct smb_iconv_convenience *ic)
96 struct dcerpc_pipe *p;
98 p = talloc(mem_ctx, struct dcerpc_pipe);
99 if (!p) {
100 return NULL;
103 p->conn = dcerpc_connection_init(p, ev, ic);
104 if (p->conn == NULL) {
105 talloc_free(p);
106 return NULL;
109 p->last_fault_code = 0;
110 p->context_id = 0;
111 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
112 p->binding = NULL;
114 ZERO_STRUCT(p->syntax);
115 ZERO_STRUCT(p->transfer_syntax);
117 if (DEBUGLVL(100)) {
118 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
121 return p;
126 choose the next call id to use
128 static uint32_t next_call_id(struct dcerpc_connection *c)
130 c->call_id++;
131 if (c->call_id == 0) {
132 c->call_id++;
134 return c->call_id;
137 /* we need to be able to get/set the fragment length without doing a full
138 decode */
139 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
141 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
142 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
143 } else {
144 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
148 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
150 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
151 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
152 } else {
153 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
157 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
159 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
160 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
161 } else {
162 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
168 setup for a ndr pull, also setting up any flags from the binding string
170 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
171 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
173 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
175 if (ndr == NULL) return ndr;
177 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
178 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
181 if (c->flags & DCERPC_NDR_REF_ALLOC) {
182 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
185 if (c->flags & DCERPC_NDR64) {
186 ndr->flags |= LIBNDR_FLAG_NDR64;
189 return ndr;
193 parse a data blob into a ncacn_packet structure. This handles both
194 input and output packets
196 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
197 struct ncacn_packet *pkt)
199 struct ndr_pull *ndr;
200 enum ndr_err_code ndr_err;
202 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
203 if (!ndr) {
204 return NT_STATUS_NO_MEMORY;
207 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
208 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
211 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
212 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
213 return ndr_map_error2ntstatus(ndr_err);
216 return NT_STATUS_OK;
220 parse the authentication information on a dcerpc response packet
222 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
223 DATA_BLOB *raw_packet,
224 struct ncacn_packet *pkt)
226 struct ndr_pull *ndr;
227 NTSTATUS status;
228 struct dcerpc_auth auth;
229 DATA_BLOB auth_blob;
230 enum ndr_err_code ndr_err;
232 if (!c->security_state.auth_info ||
233 !c->security_state.generic_state) {
234 return NT_STATUS_OK;
237 switch (c->security_state.auth_info->auth_level) {
238 case DCERPC_AUTH_LEVEL_PRIVACY:
239 case DCERPC_AUTH_LEVEL_INTEGRITY:
240 break;
242 case DCERPC_AUTH_LEVEL_CONNECT:
243 if (pkt->auth_length != 0) {
244 break;
246 return NT_STATUS_OK;
247 case DCERPC_AUTH_LEVEL_NONE:
248 if (pkt->auth_length != 0) {
249 return NT_STATUS_INVALID_NETWORK_RESPONSE;
251 return NT_STATUS_OK;
253 default:
254 return NT_STATUS_INVALID_LEVEL;
257 auth_blob.length = 8 + pkt->auth_length;
259 /* check for a valid length */
260 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
261 return NT_STATUS_INFO_LENGTH_MISMATCH;
264 auth_blob.data =
265 pkt->u.response.stub_and_verifier.data +
266 pkt->u.response.stub_and_verifier.length - auth_blob.length;
267 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
269 /* pull the auth structure */
270 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
271 if (!ndr) {
272 return NT_STATUS_NO_MEMORY;
275 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
276 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
279 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
280 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
281 return ndr_map_error2ntstatus(ndr_err);
283 status = NT_STATUS_OK;
285 /* check signature or unseal the packet */
286 switch (c->security_state.auth_info->auth_level) {
287 case DCERPC_AUTH_LEVEL_PRIVACY:
288 status = gensec_unseal_packet(c->security_state.generic_state,
289 mem_ctx,
290 raw_packet->data + DCERPC_REQUEST_LENGTH,
291 pkt->u.response.stub_and_verifier.length,
292 raw_packet->data,
293 raw_packet->length - auth.credentials.length,
294 &auth.credentials);
295 memcpy(pkt->u.response.stub_and_verifier.data,
296 raw_packet->data + DCERPC_REQUEST_LENGTH,
297 pkt->u.response.stub_and_verifier.length);
298 break;
300 case DCERPC_AUTH_LEVEL_INTEGRITY:
301 status = gensec_check_packet(c->security_state.generic_state,
302 mem_ctx,
303 pkt->u.response.stub_and_verifier.data,
304 pkt->u.response.stub_and_verifier.length,
305 raw_packet->data,
306 raw_packet->length - auth.credentials.length,
307 &auth.credentials);
308 break;
310 case DCERPC_AUTH_LEVEL_CONNECT:
311 /* for now we ignore possible signatures here */
312 status = NT_STATUS_OK;
313 break;
315 default:
316 status = NT_STATUS_INVALID_LEVEL;
317 break;
320 /* remove the indicated amount of paddiing */
321 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
322 return NT_STATUS_INFO_LENGTH_MISMATCH;
324 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
326 return status;
331 push a dcerpc request packet into a blob, possibly signing it.
333 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
334 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
335 size_t sig_size,
336 struct ncacn_packet *pkt)
338 NTSTATUS status;
339 struct ndr_push *ndr;
340 DATA_BLOB creds2;
341 size_t payload_length;
342 enum ndr_err_code ndr_err;
343 size_t hdr_size = DCERPC_REQUEST_LENGTH;
345 /* non-signed packets are simpler */
346 if (sig_size == 0) {
347 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
350 switch (c->security_state.auth_info->auth_level) {
351 case DCERPC_AUTH_LEVEL_PRIVACY:
352 case DCERPC_AUTH_LEVEL_INTEGRITY:
353 break;
355 case DCERPC_AUTH_LEVEL_CONNECT:
356 /* TODO: let the gensec mech decide if it wants to generate a signature */
357 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
359 case DCERPC_AUTH_LEVEL_NONE:
360 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
362 default:
363 return NT_STATUS_INVALID_LEVEL;
366 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
367 if (!ndr) {
368 return NT_STATUS_NO_MEMORY;
371 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
372 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
375 if (c->flags & DCERPC_NDR64) {
376 ndr->flags |= LIBNDR_FLAG_NDR64;
379 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
380 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
381 hdr_size += 16;
384 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
385 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
386 return ndr_map_error2ntstatus(ndr_err);
388 status = NT_STATUS_OK;
390 /* pad to 16 byte multiple in the payload portion of the
391 packet. This matches what w2k3 does */
392 c->security_state.auth_info->auth_pad_length =
393 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
394 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
395 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
396 return ndr_map_error2ntstatus(ndr_err);
398 status = NT_STATUS_OK;
400 payload_length = pkt->u.request.stub_and_verifier.length +
401 c->security_state.auth_info->auth_pad_length;
403 /* we start without signature, it will appended later */
404 c->security_state.auth_info->credentials = data_blob(NULL,0);
406 /* add the auth verifier */
407 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
408 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
409 return ndr_map_error2ntstatus(ndr_err);
411 status = NT_STATUS_OK;
413 /* extract the whole packet as a blob */
414 *blob = ndr_push_blob(ndr);
417 * Setup the frag and auth length in the packet buffer.
418 * This is needed if the GENSEC mech does AEAD signing
419 * of the packet headers. The signature itself will be
420 * appended later.
422 dcerpc_set_frag_length(blob, blob->length + sig_size);
423 dcerpc_set_auth_length(blob, sig_size);
425 /* sign or seal the packet */
426 switch (c->security_state.auth_info->auth_level) {
427 case DCERPC_AUTH_LEVEL_PRIVACY:
428 status = gensec_seal_packet(c->security_state.generic_state,
429 mem_ctx,
430 blob->data + hdr_size,
431 payload_length,
432 blob->data,
433 blob->length,
434 &creds2);
435 if (!NT_STATUS_IS_OK(status)) {
436 return status;
438 break;
440 case DCERPC_AUTH_LEVEL_INTEGRITY:
441 status = gensec_sign_packet(c->security_state.generic_state,
442 mem_ctx,
443 blob->data + hdr_size,
444 payload_length,
445 blob->data,
446 blob->length,
447 &creds2);
448 if (!NT_STATUS_IS_OK(status)) {
449 return status;
451 break;
453 default:
454 status = NT_STATUS_INVALID_LEVEL;
455 break;
458 if (creds2.length != sig_size) {
459 DEBUG(0,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
460 (unsigned) creds2.length,
461 (unsigned) sig_size,
462 (unsigned) c->security_state.auth_info->auth_pad_length,
463 (unsigned) pkt->u.request.stub_and_verifier.length));
464 return NT_STATUS_INTERNAL_ERROR;
467 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
468 return NT_STATUS_NO_MEMORY;
471 return NT_STATUS_OK;
476 fill in the fixed values in a dcerpc header
478 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
480 pkt->rpc_vers = 5;
481 pkt->rpc_vers_minor = 0;
482 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
483 pkt->drep[0] = 0;
484 } else {
485 pkt->drep[0] = DCERPC_DREP_LE;
487 pkt->drep[1] = 0;
488 pkt->drep[2] = 0;
489 pkt->drep[3] = 0;
493 map a bind nak reason to a NTSTATUS
495 static NTSTATUS dcerpc_map_reason(uint16_t reason)
497 switch (reason) {
498 case DCERPC_BIND_REASON_ASYNTAX:
499 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
500 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
501 return NT_STATUS_INVALID_PARAMETER;
503 return NT_STATUS_UNSUCCESSFUL;
507 a bind or alter context has failed
509 static void dcerpc_composite_fail(struct rpc_request *req)
511 struct composite_context *c = talloc_get_type(req->async.private_data,
512 struct composite_context);
513 composite_error(c, req->status);
517 remove requests from the pending or queued queues
519 static int dcerpc_req_dequeue(struct rpc_request *req)
521 switch (req->state) {
522 case RPC_REQUEST_QUEUED:
523 DLIST_REMOVE(req->p->conn->request_queue, req);
524 break;
525 case RPC_REQUEST_PENDING:
526 DLIST_REMOVE(req->p->conn->pending, req);
527 break;
528 case RPC_REQUEST_DONE:
529 break;
531 return 0;
536 mark the dcerpc connection dead. All outstanding requests get an error
538 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
540 if (conn->dead) return;
542 conn->dead = true;
544 if (conn->transport.shutdown_pipe) {
545 conn->transport.shutdown_pipe(conn, status);
548 /* all pending requests get the error */
549 while (conn->pending) {
550 struct rpc_request *req = conn->pending;
551 dcerpc_req_dequeue(req);
552 req->state = RPC_REQUEST_DONE;
553 req->status = status;
554 if (req->async.callback) {
555 req->async.callback(req);
559 talloc_set_destructor(conn, NULL);
560 if (conn->free_skipped) {
561 talloc_free(conn);
566 forward declarations of the recv_data handlers for the types of
567 packets we need to handle
569 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
570 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
573 receive a dcerpc reply from the transport. Here we work out what
574 type of reply it is (normal request, bind or alter context) and
575 dispatch to the appropriate handler
577 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
579 struct ncacn_packet pkt;
581 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
582 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
585 /* the transport may be telling us of a severe error, such as
586 a dropped socket */
587 if (!NT_STATUS_IS_OK(status)) {
588 data_blob_free(blob);
589 dcerpc_connection_dead(conn, status);
590 return;
593 /* parse the basic packet to work out what type of response this is */
594 status = ncacn_pull(conn, blob, blob->data, &pkt);
595 if (!NT_STATUS_IS_OK(status)) {
596 data_blob_free(blob);
597 dcerpc_connection_dead(conn, status);
600 dcerpc_request_recv_data(conn, blob, &pkt);
605 Receive a bind reply from the transport
607 static void dcerpc_bind_recv_handler(struct rpc_request *req,
608 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
610 struct composite_context *c;
611 struct dcerpc_connection *conn;
613 c = talloc_get_type(req->async.private_data, struct composite_context);
615 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
616 DEBUG(2,("dcerpc: bind_nak reason %d\n",
617 pkt->u.bind_nak.reject_reason));
618 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
619 reject_reason));
620 return;
623 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
624 (pkt->u.bind_ack.num_results == 0) ||
625 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
626 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
627 return;
630 conn = req->p->conn;
632 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
633 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
635 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
636 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
637 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
640 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
641 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
642 conn->flags |= DCERPC_HEADER_SIGNING;
645 /* the bind_ack might contain a reply set of credentials */
646 if (conn->security_state.auth_info &&
647 pkt->u.bind_ack.auth_info.length) {
648 enum ndr_err_code ndr_err;
649 ndr_err = ndr_pull_struct_blob(
650 &pkt->u.bind_ack.auth_info, conn,
651 NULL,
652 conn->security_state.auth_info,
653 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
654 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
655 c->status = ndr_map_error2ntstatus(ndr_err);
656 if (!composite_is_ok(c)) return;
660 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
662 composite_done(c);
666 handle timeouts of individual dcerpc requests
668 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
669 struct timeval t, void *private_data)
671 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
673 if (req->ignore_timeout) {
674 dcerpc_req_dequeue(req);
675 req->state = RPC_REQUEST_DONE;
676 req->status = NT_STATUS_IO_TIMEOUT;
677 if (req->async.callback) {
678 req->async.callback(req);
680 return;
683 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
687 send a async dcerpc bind request
689 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
690 TALLOC_CTX *mem_ctx,
691 const struct ndr_syntax_id *syntax,
692 const struct ndr_syntax_id *transfer_syntax)
694 struct composite_context *c;
695 struct ncacn_packet pkt;
696 DATA_BLOB blob;
697 struct rpc_request *req;
699 c = composite_create(mem_ctx,p->conn->event_ctx);
700 if (c == NULL) return NULL;
702 c->private_data = p;
704 p->syntax = *syntax;
705 p->transfer_syntax = *transfer_syntax;
707 init_ncacn_hdr(p->conn, &pkt);
709 pkt.ptype = DCERPC_PKT_BIND;
710 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
711 pkt.call_id = p->conn->call_id;
712 pkt.auth_length = 0;
714 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
715 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
718 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
719 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
722 pkt.u.bind.max_xmit_frag = 5840;
723 pkt.u.bind.max_recv_frag = 5840;
724 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
725 pkt.u.bind.num_contexts = 1;
726 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
727 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
728 pkt.u.bind.ctx_list[0].context_id = p->context_id;
729 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
730 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
731 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
732 pkt.u.bind.auth_info = data_blob(NULL, 0);
734 /* construct the NDR form of the packet */
735 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
736 p->conn->security_state.auth_info);
737 if (!composite_is_ok(c)) return c;
739 p->conn->transport.recv_data = dcerpc_recv_data;
742 * we allocate a dcerpc_request so we can be in the same
743 * request queue as normal requests
745 req = talloc_zero(c, struct rpc_request);
746 if (composite_nomem(req, c)) return c;
748 req->state = RPC_REQUEST_PENDING;
749 req->call_id = pkt.call_id;
750 req->async.private_data = c;
751 req->async.callback = dcerpc_composite_fail;
752 req->p = p;
753 req->recv_handler = dcerpc_bind_recv_handler;
754 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
755 talloc_set_destructor(req, dcerpc_req_dequeue);
757 c->status = p->conn->transport.send_request(p->conn, &blob,
758 true);
759 if (!composite_is_ok(c)) return c;
761 event_add_timed(c->event_ctx, req,
762 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
763 dcerpc_timeout_handler, req);
765 return c;
769 recv side of async dcerpc bind request
771 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
773 NTSTATUS result = composite_wait(ctx);
774 talloc_free(ctx);
775 return result;
779 perform a continued bind (and auth3)
781 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
782 TALLOC_CTX *mem_ctx)
784 struct ncacn_packet pkt;
785 NTSTATUS status;
786 DATA_BLOB blob;
788 init_ncacn_hdr(p->conn, &pkt);
790 pkt.ptype = DCERPC_PKT_AUTH3;
791 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
792 pkt.call_id = next_call_id(p->conn);
793 pkt.auth_length = 0;
794 pkt.u.auth3._pad = 0;
795 pkt.u.auth3.auth_info = data_blob(NULL, 0);
797 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
798 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
801 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
802 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
805 /* construct the NDR form of the packet */
806 status = ncacn_push_auth(&blob, mem_ctx,
807 p->conn->iconv_convenience,
808 &pkt,
809 p->conn->security_state.auth_info);
810 if (!NT_STATUS_IS_OK(status)) {
811 return status;
814 /* send it on its way */
815 status = p->conn->transport.send_request(p->conn, &blob, false);
816 if (!NT_STATUS_IS_OK(status)) {
817 return status;
820 return NT_STATUS_OK;
825 process a fragment received from the transport layer during a
826 request
828 This function frees the data
830 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
831 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
833 struct rpc_request *req;
834 unsigned int length;
835 NTSTATUS status = NT_STATUS_OK;
838 if this is an authenticated connection then parse and check
839 the auth info. We have to do this before finding the
840 matching packet, as the request structure might have been
841 removed due to a timeout, but if it has been we still need
842 to run the auth routines so that we don't get the sign/seal
843 info out of step with the server
845 if (c->security_state.auth_info && c->security_state.generic_state &&
846 pkt->ptype == DCERPC_PKT_RESPONSE) {
847 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
850 /* find the matching request */
851 for (req=c->pending;req;req=req->next) {
852 if (pkt->call_id == req->call_id) break;
855 #if 0
856 /* useful for testing certain vendors RPC servers */
857 if (req == NULL && c->pending && pkt->call_id == 0) {
858 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
859 req = c->pending;
861 #endif
863 if (req == NULL) {
864 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
865 data_blob_free(raw_packet);
866 return;
869 talloc_steal(req, raw_packet->data);
871 if (req->recv_handler != NULL) {
872 dcerpc_req_dequeue(req);
873 req->state = RPC_REQUEST_DONE;
874 req->recv_handler(req, raw_packet, pkt);
875 return;
878 if (pkt->ptype == DCERPC_PKT_FAULT) {
879 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
880 req->fault_code = pkt->u.fault.status;
881 req->status = NT_STATUS_NET_WRITE_FAULT;
882 goto req_done;
885 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
886 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
887 (int)pkt->ptype));
888 req->fault_code = DCERPC_FAULT_OTHER;
889 req->status = NT_STATUS_NET_WRITE_FAULT;
890 goto req_done;
893 /* now check the status from the auth routines, and if it failed then fail
894 this request accordingly */
895 if (!NT_STATUS_IS_OK(status)) {
896 req->status = status;
897 goto req_done;
900 length = pkt->u.response.stub_and_verifier.length;
902 if (length > 0) {
903 req->payload.data = talloc_realloc(req,
904 req->payload.data,
905 uint8_t,
906 req->payload.length + length);
907 if (!req->payload.data) {
908 req->status = NT_STATUS_NO_MEMORY;
909 goto req_done;
911 memcpy(req->payload.data+req->payload.length,
912 pkt->u.response.stub_and_verifier.data, length);
913 req->payload.length += length;
916 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
917 c->transport.send_read(c);
918 return;
921 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
922 req->flags |= DCERPC_PULL_BIGENDIAN;
923 } else {
924 req->flags &= ~DCERPC_PULL_BIGENDIAN;
928 req_done:
929 /* we've got the full payload */
930 req->state = RPC_REQUEST_DONE;
931 DLIST_REMOVE(c->pending, req);
933 if (c->request_queue != NULL) {
934 /* We have to look at shipping further requests before calling
935 * the async function, that one might close the pipe */
936 dcerpc_ship_next_request(c);
939 if (req->async.callback) {
940 req->async.callback(req);
945 perform the send side of a async dcerpc request
947 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
948 const struct GUID *object,
949 uint16_t opnum,
950 bool async,
951 DATA_BLOB *stub_data)
953 struct rpc_request *req;
955 p->conn->transport.recv_data = dcerpc_recv_data;
957 req = talloc(p, struct rpc_request);
958 if (req == NULL) {
959 return NULL;
962 req->p = p;
963 req->call_id = next_call_id(p->conn);
964 req->status = NT_STATUS_OK;
965 req->state = RPC_REQUEST_QUEUED;
966 req->payload = data_blob(NULL, 0);
967 req->flags = 0;
968 req->fault_code = 0;
969 req->async_call = async;
970 req->ignore_timeout = false;
971 req->async.callback = NULL;
972 req->async.private_data = NULL;
973 req->recv_handler = NULL;
975 if (object != NULL) {
976 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
977 if (req->object == NULL) {
978 talloc_free(req);
979 return NULL;
981 } else {
982 req->object = NULL;
985 req->opnum = opnum;
986 req->request_data.length = stub_data->length;
987 req->request_data.data = talloc_reference(req, stub_data->data);
988 if (req->request_data.length && req->request_data.data == NULL) {
989 return NULL;
992 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
993 talloc_set_destructor(req, dcerpc_req_dequeue);
995 dcerpc_ship_next_request(p->conn);
997 if (p->request_timeout) {
998 event_add_timed(dcerpc_event_context(p), req,
999 timeval_current_ofs(p->request_timeout, 0),
1000 dcerpc_timeout_handler, req);
1003 return req;
1007 Send a request using the transport
1010 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1012 struct rpc_request *req;
1013 struct dcerpc_pipe *p;
1014 DATA_BLOB *stub_data;
1015 struct ncacn_packet pkt;
1016 DATA_BLOB blob;
1017 uint32_t remaining, chunk_size;
1018 bool first_packet = true;
1019 size_t sig_size = 0;
1021 req = c->request_queue;
1022 if (req == NULL) {
1023 return;
1026 p = req->p;
1027 stub_data = &req->request_data;
1029 if (!req->async_call && (c->pending != NULL)) {
1030 return;
1033 DLIST_REMOVE(c->request_queue, req);
1034 DLIST_ADD(c->pending, req);
1035 req->state = RPC_REQUEST_PENDING;
1037 init_ncacn_hdr(p->conn, &pkt);
1039 remaining = stub_data->length;
1041 /* we can write a full max_recv_frag size, minus the dcerpc
1042 request header size */
1043 chunk_size = p->conn->srv_max_recv_frag;
1044 chunk_size -= DCERPC_REQUEST_LENGTH;
1045 if (c->security_state.auth_info &&
1046 c->security_state.generic_state) {
1047 sig_size = gensec_sig_size(c->security_state.generic_state,
1048 p->conn->srv_max_recv_frag);
1049 if (sig_size) {
1050 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1051 chunk_size -= sig_size;
1054 chunk_size -= (chunk_size % 16);
1056 pkt.ptype = DCERPC_PKT_REQUEST;
1057 pkt.call_id = req->call_id;
1058 pkt.auth_length = 0;
1059 pkt.pfc_flags = 0;
1060 pkt.u.request.alloc_hint = remaining;
1061 pkt.u.request.context_id = p->context_id;
1062 pkt.u.request.opnum = req->opnum;
1064 if (req->object) {
1065 pkt.u.request.object.object = *req->object;
1066 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1067 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1070 /* we send a series of pdus without waiting for a reply */
1071 while (remaining > 0 || first_packet) {
1072 uint32_t chunk = MIN(chunk_size, remaining);
1073 bool last_frag = false;
1074 bool do_trans = false;
1076 first_packet = false;
1077 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1079 if (remaining == stub_data->length) {
1080 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1082 if (chunk == remaining) {
1083 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1084 last_frag = true;
1087 pkt.u.request.stub_and_verifier.data = stub_data->data +
1088 (stub_data->length - remaining);
1089 pkt.u.request.stub_and_verifier.length = chunk;
1091 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1092 if (!NT_STATUS_IS_OK(req->status)) {
1093 req->state = RPC_REQUEST_DONE;
1094 DLIST_REMOVE(p->conn->pending, req);
1095 return;
1098 if (last_frag && !req->async_call) {
1099 do_trans = true;
1102 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1103 if (!NT_STATUS_IS_OK(req->status)) {
1104 req->state = RPC_REQUEST_DONE;
1105 DLIST_REMOVE(p->conn->pending, req);
1106 return;
1109 if (last_frag && !do_trans) {
1110 req->status = p->conn->transport.send_read(p->conn);
1111 if (!NT_STATUS_IS_OK(req->status)) {
1112 req->state = RPC_REQUEST_DONE;
1113 DLIST_REMOVE(p->conn->pending, req);
1114 return;
1118 remaining -= chunk;
1123 return the event context for a dcerpc pipe
1124 used by callers who wish to operate asynchronously
1126 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1128 return p->conn->event_ctx;
1134 perform the receive side of a async dcerpc request
1136 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1137 TALLOC_CTX *mem_ctx,
1138 DATA_BLOB *stub_data)
1140 NTSTATUS status;
1142 while (req->state != RPC_REQUEST_DONE) {
1143 struct tevent_context *ctx = dcerpc_event_context(req->p);
1144 if (event_loop_once(ctx) != 0) {
1145 return NT_STATUS_CONNECTION_DISCONNECTED;
1148 *stub_data = req->payload;
1149 status = req->status;
1150 if (stub_data->data) {
1151 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1153 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1154 req->p->last_fault_code = req->fault_code;
1156 talloc_unlink(talloc_parent(req), req);
1157 return status;
1161 perform a full request/response pair on a dcerpc pipe
1163 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1164 struct GUID *object,
1165 uint16_t opnum,
1166 TALLOC_CTX *mem_ctx,
1167 DATA_BLOB *stub_data_in,
1168 DATA_BLOB *stub_data_out)
1170 struct rpc_request *req;
1172 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1173 if (req == NULL) {
1174 return NT_STATUS_NO_MEMORY;
1177 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1182 this is a paranoid NDR validator. For every packet we push onto the wire
1183 we pull it back again, then push it again. Then we compare the raw NDR data
1184 for that to the NDR we initially generated. If they don't match then we know
1185 we must have a bug in either the pull or push side of our code
1187 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1188 TALLOC_CTX *mem_ctx,
1189 DATA_BLOB blob,
1190 size_t struct_size,
1191 ndr_push_flags_fn_t ndr_push,
1192 ndr_pull_flags_fn_t ndr_pull)
1194 void *st;
1195 struct ndr_pull *pull;
1196 struct ndr_push *push;
1197 DATA_BLOB blob2;
1198 enum ndr_err_code ndr_err;
1200 st = talloc_size(mem_ctx, struct_size);
1201 if (!st) {
1202 return NT_STATUS_NO_MEMORY;
1205 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1206 if (!pull) {
1207 return NT_STATUS_NO_MEMORY;
1209 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1211 ndr_err = ndr_pull(pull, NDR_IN, st);
1212 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1213 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1214 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1215 "failed input validation pull - %s",
1216 nt_errstr(status));
1217 return ndr_map_error2ntstatus(ndr_err);
1220 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1221 if (!push) {
1222 return NT_STATUS_NO_MEMORY;
1225 ndr_err = ndr_push(push, NDR_IN, st);
1226 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1227 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1228 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1229 "failed input validation push - %s",
1230 nt_errstr(status));
1231 return ndr_map_error2ntstatus(ndr_err);
1234 blob2 = ndr_push_blob(push);
1236 if (data_blob_cmp(&blob, &blob2) != 0) {
1237 DEBUG(3,("original:\n"));
1238 dump_data(3, blob.data, blob.length);
1239 DEBUG(3,("secondary:\n"));
1240 dump_data(3, blob2.data, blob2.length);
1241 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1242 "failed input validation blobs doesn't match");
1243 return ndr_map_error2ntstatus(ndr_err);
1246 return NT_STATUS_OK;
1250 this is a paranoid NDR input validator. For every packet we pull
1251 from the wire we push it back again then pull and push it
1252 again. Then we compare the raw NDR data for that to the NDR we
1253 initially generated. If they don't match then we know we must have a
1254 bug in either the pull or push side of our code
1256 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1257 struct ndr_pull *pull_in,
1258 void *struct_ptr,
1259 size_t struct_size,
1260 ndr_push_flags_fn_t ndr_push,
1261 ndr_pull_flags_fn_t ndr_pull,
1262 ndr_print_function_t ndr_print)
1264 void *st;
1265 struct ndr_pull *pull;
1266 struct ndr_push *push;
1267 DATA_BLOB blob, blob2;
1268 TALLOC_CTX *mem_ctx = pull_in;
1269 char *s1, *s2;
1270 enum ndr_err_code ndr_err;
1272 st = talloc_size(mem_ctx, struct_size);
1273 if (!st) {
1274 return NT_STATUS_NO_MEMORY;
1276 memcpy(st, struct_ptr, struct_size);
1278 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1279 if (!push) {
1280 return NT_STATUS_NO_MEMORY;
1283 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1284 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1285 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1286 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1287 "failed output validation push - %s",
1288 nt_errstr(status));
1289 return ndr_map_error2ntstatus(ndr_err);
1292 blob = ndr_push_blob(push);
1294 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1295 if (!pull) {
1296 return NT_STATUS_NO_MEMORY;
1299 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1300 ndr_err = ndr_pull(pull, NDR_OUT, st);
1301 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1302 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1303 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1304 "failed output validation pull - %s",
1305 nt_errstr(status));
1306 return ndr_map_error2ntstatus(ndr_err);
1309 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1310 if (!push) {
1311 return NT_STATUS_NO_MEMORY;
1314 ndr_err = ndr_push(push, NDR_OUT, st);
1315 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1316 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1317 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1318 "failed output validation push2 - %s",
1319 nt_errstr(status));
1320 return ndr_map_error2ntstatus(ndr_err);
1323 blob2 = ndr_push_blob(push);
1325 if (data_blob_cmp(&blob, &blob2) != 0) {
1326 DEBUG(3,("original:\n"));
1327 dump_data(3, blob.data, blob.length);
1328 DEBUG(3,("secondary:\n"));
1329 dump_data(3, blob2.data, blob2.length);
1330 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1331 "failed output validation blobs doesn't match");
1332 return ndr_map_error2ntstatus(ndr_err);
1335 /* this checks the printed forms of the two structures, which effectively
1336 tests all of the value() attributes */
1337 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1338 NDR_OUT, struct_ptr);
1339 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1340 NDR_OUT, st);
1341 if (strcmp(s1, s2) != 0) {
1342 #if 1
1343 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1344 #else
1345 /* this is sometimes useful */
1346 printf("VALIDATE ERROR\n");
1347 file_save("wire.dat", s1, strlen(s1));
1348 file_save("gen.dat", s2, strlen(s2));
1349 system("diff -u wire.dat gen.dat");
1350 #endif
1351 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1352 "failed output validation strings doesn't match");
1353 return ndr_map_error2ntstatus(ndr_err);
1356 return NT_STATUS_OK;
1361 send a rpc request given a dcerpc_call structure
1363 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1364 const struct GUID *object,
1365 const struct ndr_interface_table *table,
1366 uint32_t opnum,
1367 bool async,
1368 TALLOC_CTX *mem_ctx,
1369 void *r)
1371 const struct ndr_interface_call *call;
1372 struct ndr_push *push;
1373 NTSTATUS status;
1374 DATA_BLOB request;
1375 struct rpc_request *req;
1376 enum ndr_err_code ndr_err;
1378 call = &table->calls[opnum];
1380 /* setup for a ndr_push_* call */
1381 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1382 if (!push) {
1383 return NULL;
1386 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1387 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1390 if (p->conn->flags & DCERPC_NDR64) {
1391 push->flags |= LIBNDR_FLAG_NDR64;
1394 /* push the structure into a blob */
1395 ndr_err = call->ndr_push(push, NDR_IN, r);
1396 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1397 status = ndr_map_error2ntstatus(ndr_err);
1398 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1399 nt_errstr(status)));
1400 talloc_free(push);
1401 return NULL;
1404 /* retrieve the blob */
1405 request = ndr_push_blob(push);
1407 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1408 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1409 call->ndr_push, call->ndr_pull);
1410 if (!NT_STATUS_IS_OK(status)) {
1411 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1412 nt_errstr(status)));
1413 talloc_free(push);
1414 return NULL;
1418 DEBUG(10,("rpc request data:\n"));
1419 dump_data(10, request.data, request.length);
1421 /* make the actual dcerpc request */
1422 req = dcerpc_request_send(p, object, opnum, async, &request);
1424 if (req != NULL) {
1425 req->ndr.table = table;
1426 req->ndr.opnum = opnum;
1427 req->ndr.struct_ptr = r;
1428 req->ndr.mem_ctx = mem_ctx;
1431 talloc_free(push);
1433 return req;
1437 receive the answer from a dcerpc_ndr_request_send()
1439 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1441 struct dcerpc_pipe *p = req->p;
1442 NTSTATUS status;
1443 DATA_BLOB response;
1444 struct ndr_pull *pull;
1445 unsigned int flags;
1446 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1447 void *r = req->ndr.struct_ptr;
1448 uint32_t opnum = req->ndr.opnum;
1449 const struct ndr_interface_table *table = req->ndr.table;
1450 const struct ndr_interface_call *call = &table->calls[opnum];
1451 enum ndr_err_code ndr_err;
1453 /* make sure the recv code doesn't free the request, as we
1454 need to grab the flags element before it is freed */
1455 if (talloc_reference(p, req) == NULL) {
1456 return NT_STATUS_NO_MEMORY;
1459 status = dcerpc_request_recv(req, mem_ctx, &response);
1460 if (!NT_STATUS_IS_OK(status)) {
1461 talloc_unlink(p, req);
1462 return status;
1465 flags = req->flags;
1467 /* prepare for ndr_pull_* */
1468 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1469 if (!pull) {
1470 talloc_unlink(p, req);
1471 return NT_STATUS_NO_MEMORY;
1474 if (pull->data) {
1475 pull->data = talloc_steal(pull, pull->data);
1477 talloc_unlink(p, req);
1479 if (flags & DCERPC_PULL_BIGENDIAN) {
1480 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1483 DEBUG(10,("rpc reply data:\n"));
1484 dump_data(10, pull->data, pull->data_size);
1486 /* pull the structure from the blob */
1487 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1488 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1489 status = ndr_map_error2ntstatus(ndr_err);
1490 dcerpc_log_packet(p->conn->packet_log_dir,
1491 table, opnum, NDR_OUT,
1492 &response);
1493 return status;
1496 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1497 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1498 call->ndr_push, call->ndr_pull,
1499 call->ndr_print);
1500 if (!NT_STATUS_IS_OK(status)) {
1501 dcerpc_log_packet(p->conn->packet_log_dir,
1502 table, opnum, NDR_OUT,
1503 &response);
1504 return status;
1508 if (pull->offset != pull->data_size) {
1509 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1510 pull->data_size - pull->offset));
1511 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1512 but it turns out that early versions of NT
1513 (specifically NT3.1) add junk onto the end of rpc
1514 packets, so if we want to interoperate at all with
1515 those versions then we need to ignore this error */
1518 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1520 return NT_STATUS_OK;
1525 a useful helper function for synchronous rpc requests
1527 this can be used when you have ndr push/pull functions in the
1528 standard format
1530 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1531 const struct GUID *object,
1532 const struct ndr_interface_table *table,
1533 uint32_t opnum,
1534 TALLOC_CTX *mem_ctx,
1535 void *r)
1537 struct rpc_request *req;
1539 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1540 if (req == NULL) {
1541 return NT_STATUS_NO_MEMORY;
1544 return dcerpc_ndr_request_recv(req);
1549 a useful function for retrieving the server name we connected to
1551 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1553 if (!p->conn->transport.target_hostname) {
1554 if (!p->conn->transport.peer_name) {
1555 return "";
1557 return p->conn->transport.peer_name(p->conn);
1559 return p->conn->transport.target_hostname(p->conn);
1564 get the dcerpc auth_level for a open connection
1566 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1568 uint8_t auth_level;
1570 if (c->flags & DCERPC_SEAL) {
1571 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1572 } else if (c->flags & DCERPC_SIGN) {
1573 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1574 } else if (c->flags & DCERPC_CONNECT) {
1575 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1576 } else {
1577 auth_level = DCERPC_AUTH_LEVEL_NONE;
1579 return auth_level;
1583 Receive an alter reply from the transport
1585 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1586 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1588 struct composite_context *c;
1589 struct dcerpc_pipe *recv_pipe;
1591 c = talloc_get_type(req->async.private_data, struct composite_context);
1592 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1594 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1595 pkt->u.alter_resp.num_results == 1 &&
1596 pkt->u.alter_resp.ctx_list[0].result != 0) {
1597 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1598 pkt->u.alter_resp.ctx_list[0].reason));
1599 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1600 return;
1603 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1604 pkt->u.alter_resp.num_results == 0 ||
1605 pkt->u.alter_resp.ctx_list[0].result != 0) {
1606 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1607 return;
1610 /* the alter_resp might contain a reply set of credentials */
1611 if (recv_pipe->conn->security_state.auth_info &&
1612 pkt->u.alter_resp.auth_info.length) {
1613 enum ndr_err_code ndr_err;
1614 ndr_err = ndr_pull_struct_blob(
1615 &pkt->u.alter_resp.auth_info, recv_pipe,
1616 NULL,
1617 recv_pipe->conn->security_state.auth_info,
1618 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1619 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1620 c->status = ndr_map_error2ntstatus(ndr_err);
1621 if (!composite_is_ok(c)) return;
1625 composite_done(c);
1629 send a dcerpc alter_context request
1631 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1632 TALLOC_CTX *mem_ctx,
1633 const struct ndr_syntax_id *syntax,
1634 const struct ndr_syntax_id *transfer_syntax)
1636 struct composite_context *c;
1637 struct ncacn_packet pkt;
1638 DATA_BLOB blob;
1639 struct rpc_request *req;
1641 c = composite_create(mem_ctx, p->conn->event_ctx);
1642 if (c == NULL) return NULL;
1644 c->private_data = p;
1646 p->syntax = *syntax;
1647 p->transfer_syntax = *transfer_syntax;
1649 init_ncacn_hdr(p->conn, &pkt);
1651 pkt.ptype = DCERPC_PKT_ALTER;
1652 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1653 pkt.call_id = p->conn->call_id;
1654 pkt.auth_length = 0;
1656 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1657 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1660 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1661 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1664 pkt.u.alter.max_xmit_frag = 5840;
1665 pkt.u.alter.max_recv_frag = 5840;
1666 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1667 pkt.u.alter.num_contexts = 1;
1668 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1669 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1670 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1671 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1672 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1673 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1674 pkt.u.alter.auth_info = data_blob(NULL, 0);
1676 /* construct the NDR form of the packet */
1677 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1678 p->conn->security_state.auth_info);
1679 if (!composite_is_ok(c)) return c;
1681 p->conn->transport.recv_data = dcerpc_recv_data;
1684 * we allocate a dcerpc_request so we can be in the same
1685 * request queue as normal requests
1687 req = talloc_zero(c, struct rpc_request);
1688 if (composite_nomem(req, c)) return c;
1690 req->state = RPC_REQUEST_PENDING;
1691 req->call_id = pkt.call_id;
1692 req->async.private_data = c;
1693 req->async.callback = dcerpc_composite_fail;
1694 req->p = p;
1695 req->recv_handler = dcerpc_alter_recv_handler;
1696 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1697 talloc_set_destructor(req, dcerpc_req_dequeue);
1699 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1700 if (!composite_is_ok(c)) return c;
1702 event_add_timed(c->event_ctx, req,
1703 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1704 dcerpc_timeout_handler, req);
1706 return c;
1709 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1711 NTSTATUS result = composite_wait(ctx);
1712 talloc_free(ctx);
1713 return result;
1717 send a dcerpc alter_context request
1719 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1720 TALLOC_CTX *mem_ctx,
1721 const struct ndr_syntax_id *syntax,
1722 const struct ndr_syntax_id *transfer_syntax)
1724 struct composite_context *creq;
1725 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1726 return dcerpc_alter_context_recv(creq);