s4-rpc: added NDR64 support
[Samba/aatanasov.git] / source4 / librpc / rpc / dcerpc.c
blob87d44384ce5541465162eb5a4f6ba2eb9544f550
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 creds2.length, (uint32_t)sig_size,
461 c->security_state.auth_info->auth_pad_length,
462 pkt->u.request.stub_and_verifier.length));
463 return NT_STATUS_INTERNAL_ERROR;
466 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
467 return NT_STATUS_NO_MEMORY;
470 return NT_STATUS_OK;
475 fill in the fixed values in a dcerpc header
477 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
479 pkt->rpc_vers = 5;
480 pkt->rpc_vers_minor = 0;
481 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
482 pkt->drep[0] = 0;
483 } else {
484 pkt->drep[0] = DCERPC_DREP_LE;
486 pkt->drep[1] = 0;
487 pkt->drep[2] = 0;
488 pkt->drep[3] = 0;
492 map a bind nak reason to a NTSTATUS
494 static NTSTATUS dcerpc_map_reason(uint16_t reason)
496 switch (reason) {
497 case DCERPC_BIND_REASON_ASYNTAX:
498 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
499 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
500 return NT_STATUS_INVALID_PARAMETER;
502 return NT_STATUS_UNSUCCESSFUL;
506 a bind or alter context has failed
508 static void dcerpc_composite_fail(struct rpc_request *req)
510 struct composite_context *c = talloc_get_type(req->async.private_data,
511 struct composite_context);
512 composite_error(c, req->status);
516 remove requests from the pending or queued queues
518 static int dcerpc_req_dequeue(struct rpc_request *req)
520 switch (req->state) {
521 case RPC_REQUEST_QUEUED:
522 DLIST_REMOVE(req->p->conn->request_queue, req);
523 break;
524 case RPC_REQUEST_PENDING:
525 DLIST_REMOVE(req->p->conn->pending, req);
526 break;
527 case RPC_REQUEST_DONE:
528 break;
530 return 0;
535 mark the dcerpc connection dead. All outstanding requests get an error
537 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
539 if (conn->dead) return;
541 conn->dead = true;
543 if (conn->transport.shutdown_pipe) {
544 conn->transport.shutdown_pipe(conn, status);
547 /* all pending requests get the error */
548 while (conn->pending) {
549 struct rpc_request *req = conn->pending;
550 dcerpc_req_dequeue(req);
551 req->state = RPC_REQUEST_DONE;
552 req->status = status;
553 if (req->async.callback) {
554 req->async.callback(req);
558 talloc_set_destructor(conn, NULL);
559 if (conn->free_skipped) {
560 talloc_free(conn);
565 forward declarations of the recv_data handlers for the types of
566 packets we need to handle
568 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
569 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
572 receive a dcerpc reply from the transport. Here we work out what
573 type of reply it is (normal request, bind or alter context) and
574 dispatch to the appropriate handler
576 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
578 struct ncacn_packet pkt;
580 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
581 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
584 /* the transport may be telling us of a severe error, such as
585 a dropped socket */
586 if (!NT_STATUS_IS_OK(status)) {
587 data_blob_free(blob);
588 dcerpc_connection_dead(conn, status);
589 return;
592 /* parse the basic packet to work out what type of response this is */
593 status = ncacn_pull(conn, blob, blob->data, &pkt);
594 if (!NT_STATUS_IS_OK(status)) {
595 data_blob_free(blob);
596 dcerpc_connection_dead(conn, status);
599 dcerpc_request_recv_data(conn, blob, &pkt);
604 Receive a bind reply from the transport
606 static void dcerpc_bind_recv_handler(struct rpc_request *req,
607 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
609 struct composite_context *c;
610 struct dcerpc_connection *conn;
612 c = talloc_get_type(req->async.private_data, struct composite_context);
614 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
615 DEBUG(2,("dcerpc: bind_nak reason %d\n",
616 pkt->u.bind_nak.reject_reason));
617 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
618 reject_reason));
619 return;
622 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
623 (pkt->u.bind_ack.num_results == 0) ||
624 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
625 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
626 return;
629 conn = req->p->conn;
631 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
632 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
634 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
635 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
636 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
639 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
640 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
641 conn->flags |= DCERPC_HEADER_SIGNING;
644 /* the bind_ack might contain a reply set of credentials */
645 if (conn->security_state.auth_info &&
646 pkt->u.bind_ack.auth_info.length) {
647 enum ndr_err_code ndr_err;
648 ndr_err = ndr_pull_struct_blob(
649 &pkt->u.bind_ack.auth_info, conn,
650 NULL,
651 conn->security_state.auth_info,
652 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
653 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
654 c->status = ndr_map_error2ntstatus(ndr_err);
655 if (!composite_is_ok(c)) return;
659 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
661 composite_done(c);
665 handle timeouts of individual dcerpc requests
667 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
668 struct timeval t, void *private_data)
670 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
672 if (req->ignore_timeout) {
673 dcerpc_req_dequeue(req);
674 req->state = RPC_REQUEST_DONE;
675 req->status = NT_STATUS_IO_TIMEOUT;
676 if (req->async.callback) {
677 req->async.callback(req);
679 return;
682 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
686 send a async dcerpc bind request
688 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
689 TALLOC_CTX *mem_ctx,
690 const struct ndr_syntax_id *syntax,
691 const struct ndr_syntax_id *transfer_syntax)
693 struct composite_context *c;
694 struct ncacn_packet pkt;
695 DATA_BLOB blob;
696 struct rpc_request *req;
698 c = composite_create(mem_ctx,p->conn->event_ctx);
699 if (c == NULL) return NULL;
701 c->private_data = p;
703 p->syntax = *syntax;
704 p->transfer_syntax = *transfer_syntax;
706 init_ncacn_hdr(p->conn, &pkt);
708 pkt.ptype = DCERPC_PKT_BIND;
709 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
710 pkt.call_id = p->conn->call_id;
711 pkt.auth_length = 0;
713 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
714 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
717 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
718 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
721 pkt.u.bind.max_xmit_frag = 5840;
722 pkt.u.bind.max_recv_frag = 5840;
723 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
724 pkt.u.bind.num_contexts = 1;
725 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
726 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
727 pkt.u.bind.ctx_list[0].context_id = p->context_id;
728 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
729 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
730 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
731 pkt.u.bind.auth_info = data_blob(NULL, 0);
733 /* construct the NDR form of the packet */
734 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
735 p->conn->security_state.auth_info);
736 if (!composite_is_ok(c)) return c;
738 p->conn->transport.recv_data = dcerpc_recv_data;
741 * we allocate a dcerpc_request so we can be in the same
742 * request queue as normal requests
744 req = talloc_zero(c, struct rpc_request);
745 if (composite_nomem(req, c)) return c;
747 req->state = RPC_REQUEST_PENDING;
748 req->call_id = pkt.call_id;
749 req->async.private_data = c;
750 req->async.callback = dcerpc_composite_fail;
751 req->p = p;
752 req->recv_handler = dcerpc_bind_recv_handler;
753 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
754 talloc_set_destructor(req, dcerpc_req_dequeue);
756 c->status = p->conn->transport.send_request(p->conn, &blob,
757 true);
758 if (!composite_is_ok(c)) return c;
760 event_add_timed(c->event_ctx, req,
761 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
762 dcerpc_timeout_handler, req);
764 return c;
768 recv side of async dcerpc bind request
770 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
772 NTSTATUS result = composite_wait(ctx);
773 talloc_free(ctx);
774 return result;
778 perform a continued bind (and auth3)
780 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
781 TALLOC_CTX *mem_ctx)
783 struct ncacn_packet pkt;
784 NTSTATUS status;
785 DATA_BLOB blob;
787 init_ncacn_hdr(p->conn, &pkt);
789 pkt.ptype = DCERPC_PKT_AUTH3;
790 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
791 pkt.call_id = next_call_id(p->conn);
792 pkt.auth_length = 0;
793 pkt.u.auth3._pad = 0;
794 pkt.u.auth3.auth_info = data_blob(NULL, 0);
796 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
797 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
800 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
801 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
804 /* construct the NDR form of the packet */
805 status = ncacn_push_auth(&blob, mem_ctx,
806 p->conn->iconv_convenience,
807 &pkt,
808 p->conn->security_state.auth_info);
809 if (!NT_STATUS_IS_OK(status)) {
810 return status;
813 /* send it on its way */
814 status = p->conn->transport.send_request(p->conn, &blob, false);
815 if (!NT_STATUS_IS_OK(status)) {
816 return status;
819 return NT_STATUS_OK;
824 process a fragment received from the transport layer during a
825 request
827 This function frees the data
829 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
830 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
832 struct rpc_request *req;
833 uint_t length;
834 NTSTATUS status = NT_STATUS_OK;
837 if this is an authenticated connection then parse and check
838 the auth info. We have to do this before finding the
839 matching packet, as the request structure might have been
840 removed due to a timeout, but if it has been we still need
841 to run the auth routines so that we don't get the sign/seal
842 info out of step with the server
844 if (c->security_state.auth_info && c->security_state.generic_state &&
845 pkt->ptype == DCERPC_PKT_RESPONSE) {
846 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
849 /* find the matching request */
850 for (req=c->pending;req;req=req->next) {
851 if (pkt->call_id == req->call_id) break;
854 #if 0
855 /* useful for testing certain vendors RPC servers */
856 if (req == NULL && c->pending && pkt->call_id == 0) {
857 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
858 req = c->pending;
860 #endif
862 if (req == NULL) {
863 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
864 data_blob_free(raw_packet);
865 return;
868 talloc_steal(req, raw_packet->data);
870 if (req->recv_handler != NULL) {
871 dcerpc_req_dequeue(req);
872 req->state = RPC_REQUEST_DONE;
873 req->recv_handler(req, raw_packet, pkt);
874 return;
877 if (pkt->ptype == DCERPC_PKT_FAULT) {
878 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
879 req->fault_code = pkt->u.fault.status;
880 req->status = NT_STATUS_NET_WRITE_FAULT;
881 goto req_done;
884 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
885 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
886 (int)pkt->ptype));
887 req->fault_code = DCERPC_FAULT_OTHER;
888 req->status = NT_STATUS_NET_WRITE_FAULT;
889 goto req_done;
892 /* now check the status from the auth routines, and if it failed then fail
893 this request accordingly */
894 if (!NT_STATUS_IS_OK(status)) {
895 req->status = status;
896 goto req_done;
899 length = pkt->u.response.stub_and_verifier.length;
901 if (length > 0) {
902 req->payload.data = talloc_realloc(req,
903 req->payload.data,
904 uint8_t,
905 req->payload.length + length);
906 if (!req->payload.data) {
907 req->status = NT_STATUS_NO_MEMORY;
908 goto req_done;
910 memcpy(req->payload.data+req->payload.length,
911 pkt->u.response.stub_and_verifier.data, length);
912 req->payload.length += length;
915 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
916 c->transport.send_read(c);
917 return;
920 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
921 req->flags |= DCERPC_PULL_BIGENDIAN;
922 } else {
923 req->flags &= ~DCERPC_PULL_BIGENDIAN;
927 req_done:
928 /* we've got the full payload */
929 req->state = RPC_REQUEST_DONE;
930 DLIST_REMOVE(c->pending, req);
932 if (c->request_queue != NULL) {
933 /* We have to look at shipping further requests before calling
934 * the async function, that one might close the pipe */
935 dcerpc_ship_next_request(c);
938 if (req->async.callback) {
939 req->async.callback(req);
944 perform the send side of a async dcerpc request
946 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
947 const struct GUID *object,
948 uint16_t opnum,
949 bool async,
950 DATA_BLOB *stub_data)
952 struct rpc_request *req;
954 p->conn->transport.recv_data = dcerpc_recv_data;
956 req = talloc(p, struct rpc_request);
957 if (req == NULL) {
958 return NULL;
961 req->p = p;
962 req->call_id = next_call_id(p->conn);
963 req->status = NT_STATUS_OK;
964 req->state = RPC_REQUEST_QUEUED;
965 req->payload = data_blob(NULL, 0);
966 req->flags = 0;
967 req->fault_code = 0;
968 req->async_call = async;
969 req->ignore_timeout = false;
970 req->async.callback = NULL;
971 req->async.private_data = NULL;
972 req->recv_handler = NULL;
974 if (object != NULL) {
975 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
976 if (req->object == NULL) {
977 talloc_free(req);
978 return NULL;
980 } else {
981 req->object = NULL;
984 req->opnum = opnum;
985 req->request_data.length = stub_data->length;
986 req->request_data.data = talloc_reference(req, stub_data->data);
987 if (req->request_data.length && req->request_data.data == NULL) {
988 return NULL;
991 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
992 talloc_set_destructor(req, dcerpc_req_dequeue);
994 dcerpc_ship_next_request(p->conn);
996 if (p->request_timeout) {
997 event_add_timed(dcerpc_event_context(p), req,
998 timeval_current_ofs(p->request_timeout, 0),
999 dcerpc_timeout_handler, req);
1002 return req;
1006 Send a request using the transport
1009 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1011 struct rpc_request *req;
1012 struct dcerpc_pipe *p;
1013 DATA_BLOB *stub_data;
1014 struct ncacn_packet pkt;
1015 DATA_BLOB blob;
1016 uint32_t remaining, chunk_size;
1017 bool first_packet = true;
1018 size_t sig_size = 0;
1020 req = c->request_queue;
1021 if (req == NULL) {
1022 return;
1025 p = req->p;
1026 stub_data = &req->request_data;
1028 if (!req->async_call && (c->pending != NULL)) {
1029 return;
1032 DLIST_REMOVE(c->request_queue, req);
1033 DLIST_ADD(c->pending, req);
1034 req->state = RPC_REQUEST_PENDING;
1036 init_ncacn_hdr(p->conn, &pkt);
1038 remaining = stub_data->length;
1040 /* we can write a full max_recv_frag size, minus the dcerpc
1041 request header size */
1042 chunk_size = p->conn->srv_max_recv_frag;
1043 chunk_size -= DCERPC_REQUEST_LENGTH;
1044 if (c->security_state.auth_info &&
1045 c->security_state.generic_state) {
1046 sig_size = gensec_sig_size(c->security_state.generic_state,
1047 p->conn->srv_max_recv_frag);
1048 if (sig_size) {
1049 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1050 chunk_size -= sig_size;
1053 chunk_size -= (chunk_size % 16);
1055 pkt.ptype = DCERPC_PKT_REQUEST;
1056 pkt.call_id = req->call_id;
1057 pkt.auth_length = 0;
1058 pkt.pfc_flags = 0;
1059 pkt.u.request.alloc_hint = remaining;
1060 pkt.u.request.context_id = p->context_id;
1061 pkt.u.request.opnum = req->opnum;
1063 if (req->object) {
1064 pkt.u.request.object.object = *req->object;
1065 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1066 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1069 /* we send a series of pdus without waiting for a reply */
1070 while (remaining > 0 || first_packet) {
1071 uint32_t chunk = MIN(chunk_size, remaining);
1072 bool last_frag = false;
1073 bool do_trans = false;
1075 first_packet = false;
1076 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1078 if (remaining == stub_data->length) {
1079 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1081 if (chunk == remaining) {
1082 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1083 last_frag = true;
1086 pkt.u.request.stub_and_verifier.data = stub_data->data +
1087 (stub_data->length - remaining);
1088 pkt.u.request.stub_and_verifier.length = chunk;
1090 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1091 if (!NT_STATUS_IS_OK(req->status)) {
1092 req->state = RPC_REQUEST_DONE;
1093 DLIST_REMOVE(p->conn->pending, req);
1094 return;
1097 if (last_frag && !req->async_call) {
1098 do_trans = true;
1101 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1102 if (!NT_STATUS_IS_OK(req->status)) {
1103 req->state = RPC_REQUEST_DONE;
1104 DLIST_REMOVE(p->conn->pending, req);
1105 return;
1108 if (last_frag && !do_trans) {
1109 req->status = p->conn->transport.send_read(p->conn);
1110 if (!NT_STATUS_IS_OK(req->status)) {
1111 req->state = RPC_REQUEST_DONE;
1112 DLIST_REMOVE(p->conn->pending, req);
1113 return;
1117 remaining -= chunk;
1122 return the event context for a dcerpc pipe
1123 used by callers who wish to operate asynchronously
1125 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1127 return p->conn->event_ctx;
1133 perform the receive side of a async dcerpc request
1135 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1136 TALLOC_CTX *mem_ctx,
1137 DATA_BLOB *stub_data)
1139 NTSTATUS status;
1141 while (req->state != RPC_REQUEST_DONE) {
1142 struct tevent_context *ctx = dcerpc_event_context(req->p);
1143 if (event_loop_once(ctx) != 0) {
1144 return NT_STATUS_CONNECTION_DISCONNECTED;
1147 *stub_data = req->payload;
1148 status = req->status;
1149 if (stub_data->data) {
1150 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1152 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1153 req->p->last_fault_code = req->fault_code;
1155 talloc_unlink(talloc_parent(req), req);
1156 return status;
1160 perform a full request/response pair on a dcerpc pipe
1162 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1163 struct GUID *object,
1164 uint16_t opnum,
1165 TALLOC_CTX *mem_ctx,
1166 DATA_BLOB *stub_data_in,
1167 DATA_BLOB *stub_data_out)
1169 struct rpc_request *req;
1171 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1172 if (req == NULL) {
1173 return NT_STATUS_NO_MEMORY;
1176 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1181 this is a paranoid NDR validator. For every packet we push onto the wire
1182 we pull it back again, then push it again. Then we compare the raw NDR data
1183 for that to the NDR we initially generated. If they don't match then we know
1184 we must have a bug in either the pull or push side of our code
1186 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1187 TALLOC_CTX *mem_ctx,
1188 DATA_BLOB blob,
1189 size_t struct_size,
1190 ndr_push_flags_fn_t ndr_push,
1191 ndr_pull_flags_fn_t ndr_pull)
1193 void *st;
1194 struct ndr_pull *pull;
1195 struct ndr_push *push;
1196 DATA_BLOB blob2;
1197 enum ndr_err_code ndr_err;
1199 st = talloc_size(mem_ctx, struct_size);
1200 if (!st) {
1201 return NT_STATUS_NO_MEMORY;
1204 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1205 if (!pull) {
1206 return NT_STATUS_NO_MEMORY;
1208 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1210 ndr_err = ndr_pull(pull, NDR_IN, st);
1211 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1212 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1213 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1214 "failed input validation pull - %s",
1215 nt_errstr(status));
1216 return ndr_map_error2ntstatus(ndr_err);
1219 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1220 if (!push) {
1221 return NT_STATUS_NO_MEMORY;
1224 ndr_err = ndr_push(push, NDR_IN, st);
1225 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1226 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1227 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1228 "failed input validation push - %s",
1229 nt_errstr(status));
1230 return ndr_map_error2ntstatus(ndr_err);
1233 blob2 = ndr_push_blob(push);
1235 if (data_blob_cmp(&blob, &blob2) != 0) {
1236 DEBUG(3,("original:\n"));
1237 dump_data(3, blob.data, blob.length);
1238 DEBUG(3,("secondary:\n"));
1239 dump_data(3, blob2.data, blob2.length);
1240 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1241 "failed input validation blobs doesn't match");
1242 return ndr_map_error2ntstatus(ndr_err);
1245 return NT_STATUS_OK;
1249 this is a paranoid NDR input validator. For every packet we pull
1250 from the wire we push it back again then pull and push it
1251 again. Then we compare the raw NDR data for that to the NDR we
1252 initially generated. If they don't match then we know we must have a
1253 bug in either the pull or push side of our code
1255 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1256 struct ndr_pull *pull_in,
1257 void *struct_ptr,
1258 size_t struct_size,
1259 ndr_push_flags_fn_t ndr_push,
1260 ndr_pull_flags_fn_t ndr_pull,
1261 ndr_print_function_t ndr_print)
1263 void *st;
1264 struct ndr_pull *pull;
1265 struct ndr_push *push;
1266 DATA_BLOB blob, blob2;
1267 TALLOC_CTX *mem_ctx = pull_in;
1268 char *s1, *s2;
1269 enum ndr_err_code ndr_err;
1271 st = talloc_size(mem_ctx, struct_size);
1272 if (!st) {
1273 return NT_STATUS_NO_MEMORY;
1275 memcpy(st, struct_ptr, struct_size);
1277 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1278 if (!push) {
1279 return NT_STATUS_NO_MEMORY;
1282 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1283 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1284 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1285 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1286 "failed output validation push - %s",
1287 nt_errstr(status));
1288 return ndr_map_error2ntstatus(ndr_err);
1291 blob = ndr_push_blob(push);
1293 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1294 if (!pull) {
1295 return NT_STATUS_NO_MEMORY;
1298 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1299 ndr_err = ndr_pull(pull, NDR_OUT, st);
1300 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1301 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1302 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1303 "failed output validation pull - %s",
1304 nt_errstr(status));
1305 return ndr_map_error2ntstatus(ndr_err);
1308 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1309 if (!push) {
1310 return NT_STATUS_NO_MEMORY;
1313 ndr_err = ndr_push(push, NDR_OUT, st);
1314 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1315 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1316 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1317 "failed output validation push2 - %s",
1318 nt_errstr(status));
1319 return ndr_map_error2ntstatus(ndr_err);
1322 blob2 = ndr_push_blob(push);
1324 if (data_blob_cmp(&blob, &blob2) != 0) {
1325 DEBUG(3,("original:\n"));
1326 dump_data(3, blob.data, blob.length);
1327 DEBUG(3,("secondary:\n"));
1328 dump_data(3, blob2.data, blob2.length);
1329 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1330 "failed output validation blobs doesn't match");
1331 return ndr_map_error2ntstatus(ndr_err);
1334 /* this checks the printed forms of the two structures, which effectively
1335 tests all of the value() attributes */
1336 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1337 NDR_OUT, struct_ptr);
1338 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1339 NDR_OUT, st);
1340 if (strcmp(s1, s2) != 0) {
1341 #if 1
1342 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1343 #else
1344 /* this is sometimes useful */
1345 printf("VALIDATE ERROR\n");
1346 file_save("wire.dat", s1, strlen(s1));
1347 file_save("gen.dat", s2, strlen(s2));
1348 system("diff -u wire.dat gen.dat");
1349 #endif
1350 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1351 "failed output validation strings doesn't match");
1352 return ndr_map_error2ntstatus(ndr_err);
1355 return NT_STATUS_OK;
1360 send a rpc request given a dcerpc_call structure
1362 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1363 const struct GUID *object,
1364 const struct ndr_interface_table *table,
1365 uint32_t opnum,
1366 bool async,
1367 TALLOC_CTX *mem_ctx,
1368 void *r)
1370 const struct ndr_interface_call *call;
1371 struct ndr_push *push;
1372 NTSTATUS status;
1373 DATA_BLOB request;
1374 struct rpc_request *req;
1375 enum ndr_err_code ndr_err;
1377 call = &table->calls[opnum];
1379 /* setup for a ndr_push_* call */
1380 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1381 if (!push) {
1382 return NULL;
1385 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1386 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1389 if (p->conn->flags & DCERPC_NDR64) {
1390 push->flags |= LIBNDR_FLAG_NDR64;
1393 /* push the structure into a blob */
1394 ndr_err = call->ndr_push(push, NDR_IN, r);
1395 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1396 status = ndr_map_error2ntstatus(ndr_err);
1397 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1398 nt_errstr(status)));
1399 talloc_free(push);
1400 return NULL;
1403 /* retrieve the blob */
1404 request = ndr_push_blob(push);
1406 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1407 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1408 call->ndr_push, call->ndr_pull);
1409 if (!NT_STATUS_IS_OK(status)) {
1410 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1411 nt_errstr(status)));
1412 talloc_free(push);
1413 return NULL;
1417 DEBUG(10,("rpc request data:\n"));
1418 dump_data(10, request.data, request.length);
1420 /* make the actual dcerpc request */
1421 req = dcerpc_request_send(p, object, opnum, async, &request);
1423 if (req != NULL) {
1424 req->ndr.table = table;
1425 req->ndr.opnum = opnum;
1426 req->ndr.struct_ptr = r;
1427 req->ndr.mem_ctx = mem_ctx;
1430 talloc_free(push);
1432 return req;
1436 receive the answer from a dcerpc_ndr_request_send()
1438 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1440 struct dcerpc_pipe *p = req->p;
1441 NTSTATUS status;
1442 DATA_BLOB response;
1443 struct ndr_pull *pull;
1444 uint_t flags;
1445 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1446 void *r = req->ndr.struct_ptr;
1447 uint32_t opnum = req->ndr.opnum;
1448 const struct ndr_interface_table *table = req->ndr.table;
1449 const struct ndr_interface_call *call = &table->calls[opnum];
1450 enum ndr_err_code ndr_err;
1452 /* make sure the recv code doesn't free the request, as we
1453 need to grab the flags element before it is freed */
1454 if (talloc_reference(p, req) == NULL) {
1455 return NT_STATUS_NO_MEMORY;
1458 status = dcerpc_request_recv(req, mem_ctx, &response);
1459 if (!NT_STATUS_IS_OK(status)) {
1460 talloc_unlink(p, req);
1461 return status;
1464 flags = req->flags;
1466 /* prepare for ndr_pull_* */
1467 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1468 if (!pull) {
1469 talloc_unlink(p, req);
1470 return NT_STATUS_NO_MEMORY;
1473 if (pull->data) {
1474 pull->data = talloc_steal(pull, pull->data);
1476 talloc_unlink(p, req);
1478 if (flags & DCERPC_PULL_BIGENDIAN) {
1479 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1482 DEBUG(10,("rpc reply data:\n"));
1483 dump_data(10, pull->data, pull->data_size);
1485 /* pull the structure from the blob */
1486 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1487 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1488 status = ndr_map_error2ntstatus(ndr_err);
1489 dcerpc_log_packet(p->conn->packet_log_dir,
1490 table, opnum, NDR_OUT,
1491 &response);
1492 return status;
1495 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1496 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1497 call->ndr_push, call->ndr_pull,
1498 call->ndr_print);
1499 if (!NT_STATUS_IS_OK(status)) {
1500 dcerpc_log_packet(p->conn->packet_log_dir,
1501 table, opnum, NDR_OUT,
1502 &response);
1503 return status;
1507 if (pull->offset != pull->data_size) {
1508 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1509 pull->data_size - pull->offset));
1510 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1511 but it turns out that early versions of NT
1512 (specifically NT3.1) add junk onto the end of rpc
1513 packets, so if we want to interoperate at all with
1514 those versions then we need to ignore this error */
1517 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1519 return NT_STATUS_OK;
1524 a useful helper function for synchronous rpc requests
1526 this can be used when you have ndr push/pull functions in the
1527 standard format
1529 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1530 const struct GUID *object,
1531 const struct ndr_interface_table *table,
1532 uint32_t opnum,
1533 TALLOC_CTX *mem_ctx,
1534 void *r)
1536 struct rpc_request *req;
1538 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1539 if (req == NULL) {
1540 return NT_STATUS_NO_MEMORY;
1543 return dcerpc_ndr_request_recv(req);
1548 a useful function for retrieving the server name we connected to
1550 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1552 if (!p->conn->transport.target_hostname) {
1553 if (!p->conn->transport.peer_name) {
1554 return "";
1556 return p->conn->transport.peer_name(p->conn);
1558 return p->conn->transport.target_hostname(p->conn);
1563 get the dcerpc auth_level for a open connection
1565 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1567 uint8_t auth_level;
1569 if (c->flags & DCERPC_SEAL) {
1570 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1571 } else if (c->flags & DCERPC_SIGN) {
1572 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1573 } else if (c->flags & DCERPC_CONNECT) {
1574 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1575 } else {
1576 auth_level = DCERPC_AUTH_LEVEL_NONE;
1578 return auth_level;
1582 Receive an alter reply from the transport
1584 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1585 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1587 struct composite_context *c;
1588 struct dcerpc_pipe *recv_pipe;
1590 c = talloc_get_type(req->async.private_data, struct composite_context);
1591 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1593 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1594 pkt->u.alter_resp.num_results == 1 &&
1595 pkt->u.alter_resp.ctx_list[0].result != 0) {
1596 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1597 pkt->u.alter_resp.ctx_list[0].reason));
1598 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1599 return;
1602 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1603 pkt->u.alter_resp.num_results == 0 ||
1604 pkt->u.alter_resp.ctx_list[0].result != 0) {
1605 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1606 return;
1609 /* the alter_resp might contain a reply set of credentials */
1610 if (recv_pipe->conn->security_state.auth_info &&
1611 pkt->u.alter_resp.auth_info.length) {
1612 enum ndr_err_code ndr_err;
1613 ndr_err = ndr_pull_struct_blob(
1614 &pkt->u.alter_resp.auth_info, recv_pipe,
1615 NULL,
1616 recv_pipe->conn->security_state.auth_info,
1617 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1618 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1619 c->status = ndr_map_error2ntstatus(ndr_err);
1620 if (!composite_is_ok(c)) return;
1624 composite_done(c);
1628 send a dcerpc alter_context request
1630 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1631 TALLOC_CTX *mem_ctx,
1632 const struct ndr_syntax_id *syntax,
1633 const struct ndr_syntax_id *transfer_syntax)
1635 struct composite_context *c;
1636 struct ncacn_packet pkt;
1637 DATA_BLOB blob;
1638 struct rpc_request *req;
1640 c = composite_create(mem_ctx, p->conn->event_ctx);
1641 if (c == NULL) return NULL;
1643 c->private_data = p;
1645 p->syntax = *syntax;
1646 p->transfer_syntax = *transfer_syntax;
1648 init_ncacn_hdr(p->conn, &pkt);
1650 pkt.ptype = DCERPC_PKT_ALTER;
1651 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1652 pkt.call_id = p->conn->call_id;
1653 pkt.auth_length = 0;
1655 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1656 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1659 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1660 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1663 pkt.u.alter.max_xmit_frag = 5840;
1664 pkt.u.alter.max_recv_frag = 5840;
1665 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1666 pkt.u.alter.num_contexts = 1;
1667 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1668 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1669 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1670 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1671 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1672 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1673 pkt.u.alter.auth_info = data_blob(NULL, 0);
1675 /* construct the NDR form of the packet */
1676 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1677 p->conn->security_state.auth_info);
1678 if (!composite_is_ok(c)) return c;
1680 p->conn->transport.recv_data = dcerpc_recv_data;
1683 * we allocate a dcerpc_request so we can be in the same
1684 * request queue as normal requests
1686 req = talloc_zero(c, struct rpc_request);
1687 if (composite_nomem(req, c)) return c;
1689 req->state = RPC_REQUEST_PENDING;
1690 req->call_id = pkt.call_id;
1691 req->async.private_data = c;
1692 req->async.callback = dcerpc_composite_fail;
1693 req->p = p;
1694 req->recv_handler = dcerpc_alter_recv_handler;
1695 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1696 talloc_set_destructor(req, dcerpc_req_dequeue);
1698 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1699 if (!composite_is_ok(c)) return c;
1701 event_add_timed(c->event_ctx, req,
1702 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1703 dcerpc_timeout_handler, req);
1705 return c;
1708 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1710 NTSTATUS result = composite_wait(ctx);
1711 talloc_free(ctx);
1712 return result;
1716 send a dcerpc alter_context request
1718 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1719 TALLOC_CTX *mem_ctx,
1720 const struct ndr_syntax_id *syntax,
1721 const struct ndr_syntax_id *transfer_syntax)
1723 struct composite_context *creq;
1724 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1725 return dcerpc_alter_context_recv(creq);