r26432: Require ndr_pull users to specify iconv_convenience.
[Samba.git] / source4 / librpc / rpc / dcerpc.c
blobf5eae1b09add75238dc85f2ef9e17d93a0ba721d
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/gen_ndr/ndr_misc.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 #include "libcli/composite/composite.h"
30 #include "auth/gensec/gensec.h"
31 #include "param/param.h"
33 NTSTATUS dcerpc_init(void)
35 gensec_init(global_loadparm);
37 return NT_STATUS_OK;
40 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
41 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
43 /* destroy a dcerpc connection */
44 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
46 if (conn->dead) {
47 conn->free_skipped = true;
48 return -1;
50 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
51 return 0;
55 /* initialise a dcerpc connection.
56 the event context is optional
58 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
59 struct event_context *ev)
61 struct dcerpc_connection *c;
63 c = talloc_zero(mem_ctx, struct dcerpc_connection);
64 if (!c) {
65 return NULL;
68 if (ev == NULL) {
69 ev = event_context_init(c);
70 if (ev == NULL) {
71 talloc_free(c);
72 return NULL;
76 c->event_ctx = ev;
78 if (!talloc_reference(c, ev)) {
79 talloc_free(c);
80 return NULL;
82 c->call_id = 1;
83 c->security_state.auth_info = NULL;
84 c->security_state.session_key = dcerpc_generic_session_key;
85 c->security_state.generic_state = NULL;
86 c->binding_string = NULL;
87 c->flags = 0;
88 c->srv_max_xmit_frag = 0;
89 c->srv_max_recv_frag = 0;
90 c->pending = NULL;
92 talloc_set_destructor(c, dcerpc_connection_destructor);
94 return c;
97 /* initialise a dcerpc pipe. */
98 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev)
100 struct dcerpc_pipe *p;
102 p = talloc(mem_ctx, struct dcerpc_pipe);
103 if (!p) {
104 return NULL;
107 p->conn = dcerpc_connection_init(p, ev);
108 if (p->conn == NULL) {
109 talloc_free(p);
110 return NULL;
113 p->last_fault_code = 0;
114 p->context_id = 0;
115 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
116 p->binding = NULL;
118 ZERO_STRUCT(p->syntax);
119 ZERO_STRUCT(p->transfer_syntax);
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, lp_iconv_convenience(global_loadparm));
175 if (ndr == NULL) return ndr;
177 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
178 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
181 if (c->flags & DCERPC_NDR_REF_ALLOC) {
182 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
185 return ndr;
189 parse a data blob into a ncacn_packet structure. This handles both
190 input and output packets
192 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
193 struct ncacn_packet *pkt)
195 struct ndr_pull *ndr;
196 enum ndr_err_code ndr_err;
198 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
199 if (!ndr) {
200 return NT_STATUS_NO_MEMORY;
203 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
204 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
207 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
208 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
209 return ndr_map_error2ntstatus(ndr_err);
212 return NT_STATUS_OK;
216 generate a CONNECT level verifier
218 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
220 *blob = data_blob_talloc(mem_ctx, NULL, 16);
221 if (blob->data == NULL) {
222 return NT_STATUS_NO_MEMORY;
224 SIVAL(blob->data, 0, 1);
225 memset(blob->data+4, 0, 12);
226 return NT_STATUS_OK;
230 check a CONNECT level verifier
232 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
234 if (blob->length != 16 ||
235 IVAL(blob->data, 0) != 1) {
236 return NT_STATUS_ACCESS_DENIED;
238 return NT_STATUS_OK;
242 parse the authentication information on a dcerpc response packet
244 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
245 DATA_BLOB *raw_packet,
246 struct ncacn_packet *pkt)
248 struct ndr_pull *ndr;
249 NTSTATUS status;
250 struct dcerpc_auth auth;
251 DATA_BLOB auth_blob;
252 enum ndr_err_code ndr_err;
254 if (pkt->auth_length == 0 &&
255 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
256 return NT_STATUS_OK;
259 auth_blob.length = 8 + pkt->auth_length;
261 /* check for a valid length */
262 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
263 return NT_STATUS_INFO_LENGTH_MISMATCH;
266 auth_blob.data =
267 pkt->u.response.stub_and_verifier.data +
268 pkt->u.response.stub_and_verifier.length - auth_blob.length;
269 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
271 /* pull the auth structure */
272 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
273 if (!ndr) {
274 return NT_STATUS_NO_MEMORY;
277 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
278 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
281 ndr_err = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
282 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
283 return ndr_map_error2ntstatus(ndr_err);
285 status = NT_STATUS_OK;
287 /* check signature or unseal the packet */
288 switch (c->security_state.auth_info->auth_level) {
289 case DCERPC_AUTH_LEVEL_PRIVACY:
290 status = gensec_unseal_packet(c->security_state.generic_state,
291 mem_ctx,
292 raw_packet->data + DCERPC_REQUEST_LENGTH,
293 pkt->u.response.stub_and_verifier.length,
294 raw_packet->data,
295 raw_packet->length - auth.credentials.length,
296 &auth.credentials);
297 memcpy(pkt->u.response.stub_and_verifier.data,
298 raw_packet->data + DCERPC_REQUEST_LENGTH,
299 pkt->u.response.stub_and_verifier.length);
300 break;
302 case DCERPC_AUTH_LEVEL_INTEGRITY:
303 status = gensec_check_packet(c->security_state.generic_state,
304 mem_ctx,
305 pkt->u.response.stub_and_verifier.data,
306 pkt->u.response.stub_and_verifier.length,
307 raw_packet->data,
308 raw_packet->length - auth.credentials.length,
309 &auth.credentials);
310 break;
312 case DCERPC_AUTH_LEVEL_CONNECT:
313 status = dcerpc_check_connect_verifier(&auth.credentials);
314 break;
316 case DCERPC_AUTH_LEVEL_NONE:
317 break;
319 default:
320 status = NT_STATUS_INVALID_LEVEL;
321 break;
324 /* remove the indicated amount of paddiing */
325 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
326 return NT_STATUS_INFO_LENGTH_MISMATCH;
328 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
330 return status;
335 push a dcerpc request packet into a blob, possibly signing it.
337 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
338 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
339 struct ncacn_packet *pkt)
341 NTSTATUS status;
342 struct ndr_push *ndr;
343 DATA_BLOB creds2;
344 size_t payload_length;
345 enum ndr_err_code ndr_err;
347 /* non-signed packets are simpler */
348 if (!c->security_state.auth_info ||
349 !c->security_state.generic_state) {
350 return ncacn_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
353 ndr = ndr_push_init_ctx(mem_ctx, lp_iconv_convenience(global_loadparm));
354 if (!ndr) {
355 return NT_STATUS_NO_MEMORY;
358 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
359 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
362 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
363 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
366 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
367 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
368 return ndr_map_error2ntstatus(ndr_err);
370 status = NT_STATUS_OK;
372 /* pad to 16 byte multiple in the payload portion of the
373 packet. This matches what w2k3 does */
374 c->security_state.auth_info->auth_pad_length =
375 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
376 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
378 payload_length = pkt->u.request.stub_and_verifier.length +
379 c->security_state.auth_info->auth_pad_length;
381 /* sign or seal the packet */
382 switch (c->security_state.auth_info->auth_level) {
383 case DCERPC_AUTH_LEVEL_PRIVACY:
384 case DCERPC_AUTH_LEVEL_INTEGRITY:
385 /* We hope this length is accruate. If must be if the
386 * GENSEC mech does AEAD signing of the packet
387 * headers */
388 c->security_state.auth_info->credentials
389 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
390 payload_length));
391 data_blob_clear(&c->security_state.auth_info->credentials);
392 break;
394 case DCERPC_AUTH_LEVEL_CONNECT:
395 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
396 break;
398 case DCERPC_AUTH_LEVEL_NONE:
399 c->security_state.auth_info->credentials = data_blob(NULL, 0);
400 break;
402 default:
403 status = NT_STATUS_INVALID_LEVEL;
404 break;
407 if (!NT_STATUS_IS_OK(status)) {
408 return status;
411 /* add the auth verifier */
412 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
413 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
414 return ndr_map_error2ntstatus(ndr_err);
416 status = NT_STATUS_OK;
418 /* extract the whole packet as a blob */
419 *blob = ndr_push_blob(ndr);
421 /* fill in the fragment length and auth_length, we can't fill
422 in these earlier as we don't know the signature length (it
423 could be variable length) */
424 dcerpc_set_frag_length(blob, blob->length);
425 /* We hope this value is accruate. If must be if the GENSEC
426 * mech does AEAD signing of the packet headers */
427 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
429 /* sign or seal the packet */
430 switch (c->security_state.auth_info->auth_level) {
431 case DCERPC_AUTH_LEVEL_PRIVACY:
432 status = gensec_seal_packet(c->security_state.generic_state,
433 mem_ctx,
434 blob->data + DCERPC_REQUEST_LENGTH,
435 payload_length,
436 blob->data,
437 blob->length -
438 c->security_state.auth_info->credentials.length,
439 &creds2);
440 if (!NT_STATUS_IS_OK(status)) {
441 return status;
443 blob->length -= c->security_state.auth_info->credentials.length;
444 if (!data_blob_append(mem_ctx, blob,
445 creds2.data, creds2.length)) {
446 return NT_STATUS_NO_MEMORY;
448 dcerpc_set_auth_length(blob, creds2.length);
449 if (c->security_state.auth_info->credentials.length == 0) {
450 /* this is needed for krb5 only, to correct the total packet
451 length */
452 dcerpc_set_frag_length(blob,
453 dcerpc_get_frag_length(blob)
454 +creds2.length);
456 break;
458 case DCERPC_AUTH_LEVEL_INTEGRITY:
459 status = gensec_sign_packet(c->security_state.generic_state,
460 mem_ctx,
461 blob->data + DCERPC_REQUEST_LENGTH,
462 payload_length,
463 blob->data,
464 blob->length -
465 c->security_state.auth_info->credentials.length,
466 &creds2);
467 if (!NT_STATUS_IS_OK(status)) {
468 return status;
470 blob->length -= c->security_state.auth_info->credentials.length;
471 if (!data_blob_append(mem_ctx, blob,
472 creds2.data, creds2.length)) {
473 return NT_STATUS_NO_MEMORY;
475 dcerpc_set_auth_length(blob, creds2.length);
476 if (c->security_state.auth_info->credentials.length == 0) {
477 /* this is needed for krb5 only, to correct the total packet
478 length */
479 dcerpc_set_frag_length(blob,
480 dcerpc_get_frag_length(blob)
481 +creds2.length);
483 break;
485 case DCERPC_AUTH_LEVEL_CONNECT:
486 break;
488 case DCERPC_AUTH_LEVEL_NONE:
489 c->security_state.auth_info->credentials = data_blob(NULL, 0);
490 break;
492 default:
493 status = NT_STATUS_INVALID_LEVEL;
494 break;
497 data_blob_free(&c->security_state.auth_info->credentials);
499 return NT_STATUS_OK;
504 fill in the fixed values in a dcerpc header
506 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
508 pkt->rpc_vers = 5;
509 pkt->rpc_vers_minor = 0;
510 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
511 pkt->drep[0] = 0;
512 } else {
513 pkt->drep[0] = DCERPC_DREP_LE;
515 pkt->drep[1] = 0;
516 pkt->drep[2] = 0;
517 pkt->drep[3] = 0;
521 map a bind nak reason to a NTSTATUS
523 static NTSTATUS dcerpc_map_reason(uint16_t reason)
525 switch (reason) {
526 case DCERPC_BIND_REASON_ASYNTAX:
527 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
528 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
529 return NT_STATUS_INVALID_PARAMETER;
531 return NT_STATUS_UNSUCCESSFUL;
535 a bind or alter context has failed
537 static void dcerpc_composite_fail(struct rpc_request *req)
539 struct composite_context *c = talloc_get_type(req->async.private_data,
540 struct composite_context);
541 composite_error(c, req->status);
545 remove requests from the pending or queued queues
547 static int dcerpc_req_dequeue(struct rpc_request *req)
549 switch (req->state) {
550 case RPC_REQUEST_QUEUED:
551 DLIST_REMOVE(req->p->conn->request_queue, req);
552 break;
553 case RPC_REQUEST_PENDING:
554 DLIST_REMOVE(req->p->conn->pending, req);
555 break;
556 case RPC_REQUEST_DONE:
557 break;
559 return 0;
564 mark the dcerpc connection dead. All outstanding requests get an error
566 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
568 if (conn->dead) return;
570 conn->dead = true;
572 if (conn->transport.shutdown_pipe) {
573 conn->transport.shutdown_pipe(conn, status);
576 /* all pending requests get the error */
577 while (conn->pending) {
578 struct rpc_request *req = conn->pending;
579 dcerpc_req_dequeue(req);
580 req->state = RPC_REQUEST_DONE;
581 req->status = status;
582 if (req->async.callback) {
583 req->async.callback(req);
587 talloc_set_destructor(conn, NULL);
588 if (conn->free_skipped) {
589 talloc_free(conn);
594 forward declarations of the recv_data handlers for the types of
595 packets we need to handle
597 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
598 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
601 receive a dcerpc reply from the transport. Here we work out what
602 type of reply it is (normal request, bind or alter context) and
603 dispatch to the appropriate handler
605 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
607 struct ncacn_packet pkt;
609 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
610 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
613 /* the transport may be telling us of a severe error, such as
614 a dropped socket */
615 if (!NT_STATUS_IS_OK(status)) {
616 data_blob_free(blob);
617 dcerpc_connection_dead(conn, status);
618 return;
621 /* parse the basic packet to work out what type of response this is */
622 status = ncacn_pull(conn, blob, blob->data, &pkt);
623 if (!NT_STATUS_IS_OK(status)) {
624 data_blob_free(blob);
625 dcerpc_connection_dead(conn, status);
628 dcerpc_request_recv_data(conn, blob, &pkt);
633 Receive a bind reply from the transport
635 static void dcerpc_bind_recv_handler(struct rpc_request *req,
636 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
638 struct composite_context *c;
639 struct dcerpc_connection *conn;
641 c = talloc_get_type(req->async.private_data, struct composite_context);
643 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
644 DEBUG(2,("dcerpc: bind_nak reason %d\n",
645 pkt->u.bind_nak.reject_reason));
646 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
647 reject_reason));
648 return;
651 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
652 (pkt->u.bind_ack.num_results == 0) ||
653 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
654 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
655 return;
658 conn = req->p->conn;
660 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
661 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
663 /* the bind_ack might contain a reply set of credentials */
664 if (conn->security_state.auth_info &&
665 pkt->u.bind_ack.auth_info.length) {
666 enum ndr_err_code ndr_err;
667 ndr_err = ndr_pull_struct_blob(
668 &pkt->u.bind_ack.auth_info, conn,
669 conn->security_state.auth_info,
670 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
671 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
672 c->status = ndr_map_error2ntstatus(ndr_err);
673 if (!composite_is_ok(c)) return;
677 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
679 composite_done(c);
683 handle timeouts of individual dcerpc requests
685 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
686 struct timeval t, void *private)
688 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
690 if (req->ignore_timeout) {
691 dcerpc_req_dequeue(req);
692 req->state = RPC_REQUEST_DONE;
693 req->status = NT_STATUS_IO_TIMEOUT;
694 if (req->async.callback) {
695 req->async.callback(req);
697 return;
700 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
704 send a async dcerpc bind request
706 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
707 TALLOC_CTX *mem_ctx,
708 const struct ndr_syntax_id *syntax,
709 const struct ndr_syntax_id *transfer_syntax)
711 struct composite_context *c;
712 struct ncacn_packet pkt;
713 DATA_BLOB blob;
714 struct rpc_request *req;
716 c = composite_create(mem_ctx,p->conn->event_ctx);
717 if (c == NULL) return NULL;
719 c->private_data = p;
721 p->syntax = *syntax;
722 p->transfer_syntax = *transfer_syntax;
724 init_ncacn_hdr(p->conn, &pkt);
726 pkt.ptype = DCERPC_PKT_BIND;
727 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
728 pkt.call_id = p->conn->call_id;
729 pkt.auth_length = 0;
731 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
732 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
735 pkt.u.bind.max_xmit_frag = 5840;
736 pkt.u.bind.max_recv_frag = 5840;
737 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
738 pkt.u.bind.num_contexts = 1;
739 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
740 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
741 pkt.u.bind.ctx_list[0].context_id = p->context_id;
742 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
743 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
744 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
745 pkt.u.bind.auth_info = data_blob(NULL, 0);
747 /* construct the NDR form of the packet */
748 c->status = ncacn_push_auth(&blob, c, &pkt,
749 p->conn->security_state.auth_info);
750 if (!composite_is_ok(c)) return c;
752 p->conn->transport.recv_data = dcerpc_recv_data;
755 * we allocate a dcerpc_request so we can be in the same
756 * request queue as normal requests
758 req = talloc_zero(c, struct rpc_request);
759 if (composite_nomem(req, c)) return c;
761 req->state = RPC_REQUEST_PENDING;
762 req->call_id = pkt.call_id;
763 req->async.private_data = c;
764 req->async.callback = dcerpc_composite_fail;
765 req->p = p;
766 req->recv_handler = dcerpc_bind_recv_handler;
767 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
768 talloc_set_destructor(req, dcerpc_req_dequeue);
770 c->status = p->conn->transport.send_request(p->conn, &blob,
771 true);
772 if (!composite_is_ok(c)) return c;
774 event_add_timed(c->event_ctx, req,
775 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
776 dcerpc_timeout_handler, req);
778 return c;
782 recv side of async dcerpc bind request
784 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
786 NTSTATUS result = composite_wait(ctx);
787 talloc_free(ctx);
788 return result;
792 perform a continued bind (and auth3)
794 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
795 TALLOC_CTX *mem_ctx)
797 struct ncacn_packet pkt;
798 NTSTATUS status;
799 DATA_BLOB blob;
801 init_ncacn_hdr(c, &pkt);
803 pkt.ptype = DCERPC_PKT_AUTH3;
804 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
805 pkt.call_id = next_call_id(c);
806 pkt.auth_length = 0;
807 pkt.u.auth3._pad = 0;
808 pkt.u.auth3.auth_info = data_blob(NULL, 0);
810 /* construct the NDR form of the packet */
811 status = ncacn_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
812 if (!NT_STATUS_IS_OK(status)) {
813 return status;
816 /* send it on its way */
817 status = c->transport.send_request(c, &blob, false);
818 if (!NT_STATUS_IS_OK(status)) {
819 return status;
822 return NT_STATUS_OK;
827 process a fragment received from the transport layer during a
828 request
830 This function frees the data
832 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
833 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
835 struct rpc_request *req;
836 uint_t length;
837 NTSTATUS status = NT_STATUS_OK;
840 if this is an authenticated connection then parse and check
841 the auth info. We have to do this before finding the
842 matching packet, as the request structure might have been
843 removed due to a timeout, but if it has been we still need
844 to run the auth routines so that we don't get the sign/seal
845 info out of step with the server
847 if (c->security_state.auth_info && c->security_state.generic_state &&
848 pkt->ptype == DCERPC_PKT_RESPONSE) {
849 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
852 /* find the matching request */
853 for (req=c->pending;req;req=req->next) {
854 if (pkt->call_id == req->call_id) break;
857 #if 0
858 /* useful for testing certain vendors RPC servers */
859 if (req == NULL && c->pending && pkt->call_id == 0) {
860 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
861 req = c->pending;
863 #endif
865 if (req == NULL) {
866 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
867 data_blob_free(raw_packet);
868 return;
871 talloc_steal(req, raw_packet->data);
873 if (req->recv_handler != NULL) {
874 dcerpc_req_dequeue(req);
875 req->state = RPC_REQUEST_DONE;
876 req->recv_handler(req, raw_packet, pkt);
877 return;
880 if (pkt->ptype == DCERPC_PKT_FAULT) {
881 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
882 req->fault_code = pkt->u.fault.status;
883 req->status = NT_STATUS_NET_WRITE_FAULT;
884 goto req_done;
887 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
888 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
889 (int)pkt->ptype));
890 req->fault_code = DCERPC_FAULT_OTHER;
891 req->status = NT_STATUS_NET_WRITE_FAULT;
892 goto req_done;
895 /* now check the status from the auth routines, and if it failed then fail
896 this request accordingly */
897 if (!NT_STATUS_IS_OK(status)) {
898 req->status = status;
899 goto req_done;
902 length = pkt->u.response.stub_and_verifier.length;
904 if (length > 0) {
905 req->payload.data = talloc_realloc(req,
906 req->payload.data,
907 uint8_t,
908 req->payload.length + length);
909 if (!req->payload.data) {
910 req->status = NT_STATUS_NO_MEMORY;
911 goto req_done;
913 memcpy(req->payload.data+req->payload.length,
914 pkt->u.response.stub_and_verifier.data, length);
915 req->payload.length += length;
918 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
919 c->transport.send_read(c);
920 return;
923 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
924 req->flags |= DCERPC_PULL_BIGENDIAN;
925 } else {
926 req->flags &= ~DCERPC_PULL_BIGENDIAN;
930 req_done:
931 /* we've got the full payload */
932 req->state = RPC_REQUEST_DONE;
933 DLIST_REMOVE(c->pending, req);
935 if (c->request_queue != NULL) {
936 /* We have to look at shipping further requests before calling
937 * the async function, that one might close the pipe */
938 dcerpc_ship_next_request(c);
941 if (req->async.callback) {
942 req->async.callback(req);
947 perform the send side of a async dcerpc request
949 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
950 const struct GUID *object,
951 uint16_t opnum,
952 bool async,
953 DATA_BLOB *stub_data)
955 struct rpc_request *req;
957 p->conn->transport.recv_data = dcerpc_recv_data;
959 req = talloc(p, struct rpc_request);
960 if (req == NULL) {
961 return NULL;
964 req->p = p;
965 req->call_id = next_call_id(p->conn);
966 req->status = NT_STATUS_OK;
967 req->state = RPC_REQUEST_QUEUED;
968 req->payload = data_blob(NULL, 0);
969 req->flags = 0;
970 req->fault_code = 0;
971 req->async_call = async;
972 req->ignore_timeout = false;
973 req->async.callback = NULL;
974 req->async.private_data = NULL;
975 req->recv_handler = NULL;
977 if (object != NULL) {
978 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
979 if (req->object == NULL) {
980 talloc_free(req);
981 return NULL;
983 } else {
984 req->object = NULL;
987 req->opnum = opnum;
988 req->request_data.length = stub_data->length;
989 req->request_data.data = talloc_reference(req, stub_data->data);
990 if (req->request_data.length && req->request_data.data == NULL) {
991 return NULL;
994 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
995 talloc_set_destructor(req, dcerpc_req_dequeue);
997 dcerpc_ship_next_request(p->conn);
999 if (p->request_timeout) {
1000 event_add_timed(dcerpc_event_context(p), req,
1001 timeval_current_ofs(p->request_timeout, 0),
1002 dcerpc_timeout_handler, req);
1005 return req;
1009 Send a request using the transport
1012 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1014 struct rpc_request *req;
1015 struct dcerpc_pipe *p;
1016 DATA_BLOB *stub_data;
1017 struct ncacn_packet pkt;
1018 DATA_BLOB blob;
1019 uint32_t remaining, chunk_size;
1020 bool first_packet = true;
1022 req = c->request_queue;
1023 if (req == NULL) {
1024 return;
1027 p = req->p;
1028 stub_data = &req->request_data;
1030 if (!req->async_call && (c->pending != NULL)) {
1031 return;
1034 DLIST_REMOVE(c->request_queue, req);
1035 DLIST_ADD(c->pending, req);
1036 req->state = RPC_REQUEST_PENDING;
1038 init_ncacn_hdr(p->conn, &pkt);
1040 remaining = stub_data->length;
1042 /* we can write a full max_recv_frag size, minus the dcerpc
1043 request header size */
1044 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1046 pkt.ptype = DCERPC_PKT_REQUEST;
1047 pkt.call_id = req->call_id;
1048 pkt.auth_length = 0;
1049 pkt.pfc_flags = 0;
1050 pkt.u.request.alloc_hint = remaining;
1051 pkt.u.request.context_id = p->context_id;
1052 pkt.u.request.opnum = req->opnum;
1054 if (req->object) {
1055 pkt.u.request.object.object = *req->object;
1056 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1057 chunk_size -= ndr_size_GUID(req->object,0);
1060 /* we send a series of pdus without waiting for a reply */
1061 while (remaining > 0 || first_packet) {
1062 uint32_t chunk = MIN(chunk_size, remaining);
1063 bool last_frag = false;
1065 first_packet = false;
1066 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1068 if (remaining == stub_data->length) {
1069 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1071 if (chunk == remaining) {
1072 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1073 last_frag = true;
1076 pkt.u.request.stub_and_verifier.data = stub_data->data +
1077 (stub_data->length - remaining);
1078 pkt.u.request.stub_and_verifier.length = chunk;
1080 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1081 if (!NT_STATUS_IS_OK(req->status)) {
1082 req->state = RPC_REQUEST_DONE;
1083 DLIST_REMOVE(p->conn->pending, req);
1084 return;
1087 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1088 if (!NT_STATUS_IS_OK(req->status)) {
1089 req->state = RPC_REQUEST_DONE;
1090 DLIST_REMOVE(p->conn->pending, req);
1091 return;
1094 remaining -= chunk;
1099 return the event context for a dcerpc pipe
1100 used by callers who wish to operate asynchronously
1102 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1104 return p->conn->event_ctx;
1110 perform the receive side of a async dcerpc request
1112 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1113 TALLOC_CTX *mem_ctx,
1114 DATA_BLOB *stub_data)
1116 NTSTATUS status;
1118 while (req->state != RPC_REQUEST_DONE) {
1119 struct event_context *ctx = dcerpc_event_context(req->p);
1120 if (event_loop_once(ctx) != 0) {
1121 return NT_STATUS_CONNECTION_DISCONNECTED;
1124 *stub_data = req->payload;
1125 status = req->status;
1126 if (stub_data->data) {
1127 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1129 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1130 req->p->last_fault_code = req->fault_code;
1132 talloc_free(req);
1133 return status;
1137 perform a full request/response pair on a dcerpc pipe
1139 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1140 struct GUID *object,
1141 uint16_t opnum,
1142 bool async,
1143 TALLOC_CTX *mem_ctx,
1144 DATA_BLOB *stub_data_in,
1145 DATA_BLOB *stub_data_out)
1147 struct rpc_request *req;
1149 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1150 if (req == NULL) {
1151 return NT_STATUS_NO_MEMORY;
1154 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1159 this is a paranoid NDR validator. For every packet we push onto the wire
1160 we pull it back again, then push it again. Then we compare the raw NDR data
1161 for that to the NDR we initially generated. If they don't match then we know
1162 we must have a bug in either the pull or push side of our code
1164 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1165 TALLOC_CTX *mem_ctx,
1166 DATA_BLOB blob,
1167 size_t struct_size,
1168 ndr_push_flags_fn_t ndr_push,
1169 ndr_pull_flags_fn_t ndr_pull)
1171 void *st;
1172 struct ndr_pull *pull;
1173 struct ndr_push *push;
1174 DATA_BLOB blob2;
1175 enum ndr_err_code ndr_err;
1177 st = talloc_size(mem_ctx, struct_size);
1178 if (!st) {
1179 return NT_STATUS_NO_MEMORY;
1182 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1183 if (!pull) {
1184 return NT_STATUS_NO_MEMORY;
1186 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1188 ndr_err = ndr_pull(pull, NDR_IN, st);
1189 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1190 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1191 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1192 "failed input validation pull - %s",
1193 nt_errstr(status));
1194 return ndr_map_error2ntstatus(ndr_err);
1197 push = ndr_push_init_ctx(mem_ctx, lp_iconv_convenience(global_loadparm));
1198 if (!push) {
1199 return NT_STATUS_NO_MEMORY;
1202 ndr_err = ndr_push(push, NDR_IN, st);
1203 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1204 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1205 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1206 "failed input validation push - %s",
1207 nt_errstr(status));
1208 return ndr_map_error2ntstatus(ndr_err);
1211 blob2 = ndr_push_blob(push);
1213 if (data_blob_cmp(&blob, &blob2) != 0) {
1214 DEBUG(3,("original:\n"));
1215 dump_data(3, blob.data, blob.length);
1216 DEBUG(3,("secondary:\n"));
1217 dump_data(3, blob2.data, blob2.length);
1218 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1219 "failed input validation blobs doesn't match");
1220 return ndr_map_error2ntstatus(ndr_err);
1223 return NT_STATUS_OK;
1227 this is a paranoid NDR input validator. For every packet we pull
1228 from the wire we push it back again then pull and push it
1229 again. Then we compare the raw NDR data for that to the NDR we
1230 initially generated. If they don't match then we know we must have a
1231 bug in either the pull or push side of our code
1233 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1234 struct ndr_pull *pull_in,
1235 void *struct_ptr,
1236 size_t struct_size,
1237 ndr_push_flags_fn_t ndr_push,
1238 ndr_pull_flags_fn_t ndr_pull,
1239 ndr_print_function_t ndr_print)
1241 void *st;
1242 struct ndr_pull *pull;
1243 struct ndr_push *push;
1244 DATA_BLOB blob, blob2;
1245 TALLOC_CTX *mem_ctx = pull_in;
1246 char *s1, *s2;
1247 enum ndr_err_code ndr_err;
1249 st = talloc_size(mem_ctx, struct_size);
1250 if (!st) {
1251 return NT_STATUS_NO_MEMORY;
1253 memcpy(st, struct_ptr, struct_size);
1255 push = ndr_push_init_ctx(mem_ctx, lp_iconv_convenience(global_loadparm));
1256 if (!push) {
1257 return NT_STATUS_NO_MEMORY;
1260 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1261 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1262 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1263 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1264 "failed output validation push - %s",
1265 nt_errstr(status));
1266 return ndr_map_error2ntstatus(ndr_err);
1269 blob = ndr_push_blob(push);
1271 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1272 if (!pull) {
1273 return NT_STATUS_NO_MEMORY;
1276 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1277 ndr_err = ndr_pull(pull, NDR_OUT, st);
1278 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1279 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1280 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1281 "failed output validation pull - %s",
1282 nt_errstr(status));
1283 return ndr_map_error2ntstatus(ndr_err);
1286 push = ndr_push_init_ctx(mem_ctx, lp_iconv_convenience(global_loadparm));
1287 if (!push) {
1288 return NT_STATUS_NO_MEMORY;
1291 ndr_err = ndr_push(push, NDR_OUT, st);
1292 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1293 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1294 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1295 "failed output validation push2 - %s",
1296 nt_errstr(status));
1297 return ndr_map_error2ntstatus(ndr_err);
1300 blob2 = ndr_push_blob(push);
1302 if (data_blob_cmp(&blob, &blob2) != 0) {
1303 DEBUG(3,("original:\n"));
1304 dump_data(3, blob.data, blob.length);
1305 DEBUG(3,("secondary:\n"));
1306 dump_data(3, blob2.data, blob2.length);
1307 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1308 "failed output validation blobs doesn't match");
1309 return ndr_map_error2ntstatus(ndr_err);
1312 /* this checks the printed forms of the two structures, which effectively
1313 tests all of the value() attributes */
1314 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1315 NDR_OUT, struct_ptr);
1316 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1317 NDR_OUT, st);
1318 if (strcmp(s1, s2) != 0) {
1319 #if 1
1320 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1321 #else
1322 /* this is sometimes useful */
1323 printf("VALIDATE ERROR\n");
1324 file_save("wire.dat", s1, strlen(s1));
1325 file_save("gen.dat", s2, strlen(s2));
1326 system("diff -u wire.dat gen.dat");
1327 #endif
1328 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1329 "failed output validation strings doesn't match");
1330 return ndr_map_error2ntstatus(ndr_err);
1333 return NT_STATUS_OK;
1338 send a rpc request given a dcerpc_call structure
1340 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1341 const struct GUID *object,
1342 const struct ndr_interface_table *table,
1343 uint32_t opnum,
1344 TALLOC_CTX *mem_ctx,
1345 void *r)
1347 const struct ndr_interface_call *call;
1348 struct ndr_push *push;
1349 NTSTATUS status;
1350 DATA_BLOB request;
1351 struct rpc_request *req;
1352 enum ndr_err_code ndr_err;
1354 call = &table->calls[opnum];
1356 /* setup for a ndr_push_* call */
1357 push = ndr_push_init_ctx(mem_ctx, lp_iconv_convenience(global_loadparm));
1358 if (!push) {
1359 return NULL;
1362 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1363 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1366 /* push the structure into a blob */
1367 ndr_err = call->ndr_push(push, NDR_IN, r);
1368 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1369 status = ndr_map_error2ntstatus(ndr_err);
1370 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1371 nt_errstr(status)));
1372 talloc_free(push);
1373 return NULL;
1376 /* retrieve the blob */
1377 request = ndr_push_blob(push);
1379 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1380 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1381 call->ndr_push, call->ndr_pull);
1382 if (!NT_STATUS_IS_OK(status)) {
1383 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1384 nt_errstr(status)));
1385 talloc_free(push);
1386 return NULL;
1390 DEBUG(10,("rpc request data:\n"));
1391 dump_data(10, request.data, request.length);
1393 /* make the actual dcerpc request */
1394 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1395 &request);
1397 if (req != NULL) {
1398 req->ndr.table = table;
1399 req->ndr.opnum = opnum;
1400 req->ndr.struct_ptr = r;
1401 req->ndr.mem_ctx = mem_ctx;
1404 talloc_free(push);
1406 return req;
1410 receive the answer from a dcerpc_ndr_request_send()
1412 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1414 struct dcerpc_pipe *p = req->p;
1415 NTSTATUS status;
1416 DATA_BLOB response;
1417 struct ndr_pull *pull;
1418 uint_t flags;
1419 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1420 void *r = req->ndr.struct_ptr;
1421 uint32_t opnum = req->ndr.opnum;
1422 const struct ndr_interface_table *table = req->ndr.table;
1423 const struct ndr_interface_call *call = &table->calls[opnum];
1424 enum ndr_err_code ndr_err;
1426 /* make sure the recv code doesn't free the request, as we
1427 need to grab the flags element before it is freed */
1428 if (talloc_reference(p, req) == NULL) {
1429 return NT_STATUS_NO_MEMORY;
1432 status = dcerpc_request_recv(req, mem_ctx, &response);
1433 if (!NT_STATUS_IS_OK(status)) {
1434 talloc_unlink(p, req);
1435 return status;
1438 flags = req->flags;
1440 /* prepare for ndr_pull_* */
1441 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1442 if (!pull) {
1443 talloc_unlink(p, req);
1444 return NT_STATUS_NO_MEMORY;
1447 if (pull->data) {
1448 pull->data = talloc_steal(pull, pull->data);
1450 talloc_unlink(p, req);
1452 if (flags & DCERPC_PULL_BIGENDIAN) {
1453 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1456 DEBUG(10,("rpc reply data:\n"));
1457 dump_data(10, pull->data, pull->data_size);
1459 /* pull the structure from the blob */
1460 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1461 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1462 status = ndr_map_error2ntstatus(ndr_err);
1463 dcerpc_log_packet(table, opnum, NDR_OUT,
1464 &response);
1465 return status;
1468 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1469 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1470 call->ndr_push, call->ndr_pull,
1471 call->ndr_print);
1472 if (!NT_STATUS_IS_OK(status)) {
1473 dcerpc_log_packet(table, opnum, NDR_OUT,
1474 &response);
1475 return status;
1479 if (pull->offset != pull->data_size) {
1480 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1481 pull->data_size - pull->offset));
1482 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1483 but it turns out that early versions of NT
1484 (specifically NT3.1) add junk onto the end of rpc
1485 packets, so if we want to interoperate at all with
1486 those versions then we need to ignore this error */
1489 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1491 return NT_STATUS_OK;
1496 a useful helper function for synchronous rpc requests
1498 this can be used when you have ndr push/pull functions in the
1499 standard format
1501 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1502 const struct GUID *object,
1503 const struct ndr_interface_table *table,
1504 uint32_t opnum,
1505 TALLOC_CTX *mem_ctx,
1506 void *r)
1508 struct rpc_request *req;
1510 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1511 if (req == NULL) {
1512 return NT_STATUS_NO_MEMORY;
1515 return dcerpc_ndr_request_recv(req);
1520 a useful function for retrieving the server name we connected to
1522 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1524 if (!p->conn->transport.target_hostname) {
1525 if (!p->conn->transport.peer_name) {
1526 return "";
1528 return p->conn->transport.peer_name(p->conn);
1530 return p->conn->transport.target_hostname(p->conn);
1535 get the dcerpc auth_level for a open connection
1537 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1539 uint8_t auth_level;
1541 if (c->flags & DCERPC_SEAL) {
1542 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1543 } else if (c->flags & DCERPC_SIGN) {
1544 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1545 } else if (c->flags & DCERPC_CONNECT) {
1546 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1547 } else {
1548 auth_level = DCERPC_AUTH_LEVEL_NONE;
1550 return auth_level;
1554 Receive an alter reply from the transport
1556 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1557 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1559 struct composite_context *c;
1560 struct dcerpc_pipe *recv_pipe;
1562 c = talloc_get_type(req->async.private_data, struct composite_context);
1563 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1565 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1566 pkt->u.alter_resp.num_results == 1 &&
1567 pkt->u.alter_resp.ctx_list[0].result != 0) {
1568 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1569 pkt->u.alter_resp.ctx_list[0].reason));
1570 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1571 return;
1574 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1575 pkt->u.alter_resp.num_results == 0 ||
1576 pkt->u.alter_resp.ctx_list[0].result != 0) {
1577 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1578 return;
1581 /* the alter_resp might contain a reply set of credentials */
1582 if (recv_pipe->conn->security_state.auth_info &&
1583 pkt->u.alter_resp.auth_info.length) {
1584 enum ndr_err_code ndr_err;
1585 ndr_err = ndr_pull_struct_blob(
1586 &pkt->u.alter_resp.auth_info, recv_pipe,
1587 recv_pipe->conn->security_state.auth_info,
1588 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1589 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1590 c->status = ndr_map_error2ntstatus(ndr_err);
1591 if (!composite_is_ok(c)) return;
1595 composite_done(c);
1599 send a dcerpc alter_context request
1601 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1602 TALLOC_CTX *mem_ctx,
1603 const struct ndr_syntax_id *syntax,
1604 const struct ndr_syntax_id *transfer_syntax)
1606 struct composite_context *c;
1607 struct ncacn_packet pkt;
1608 DATA_BLOB blob;
1609 struct rpc_request *req;
1611 c = composite_create(mem_ctx, p->conn->event_ctx);
1612 if (c == NULL) return NULL;
1614 c->private_data = p;
1616 p->syntax = *syntax;
1617 p->transfer_syntax = *transfer_syntax;
1619 init_ncacn_hdr(p->conn, &pkt);
1621 pkt.ptype = DCERPC_PKT_ALTER;
1622 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1623 pkt.call_id = p->conn->call_id;
1624 pkt.auth_length = 0;
1626 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1627 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1630 pkt.u.alter.max_xmit_frag = 5840;
1631 pkt.u.alter.max_recv_frag = 5840;
1632 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1633 pkt.u.alter.num_contexts = 1;
1634 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1635 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1636 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1637 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1638 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1639 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1640 pkt.u.alter.auth_info = data_blob(NULL, 0);
1642 /* construct the NDR form of the packet */
1643 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1644 p->conn->security_state.auth_info);
1645 if (!composite_is_ok(c)) return c;
1647 p->conn->transport.recv_data = dcerpc_recv_data;
1650 * we allocate a dcerpc_request so we can be in the same
1651 * request queue as normal requests
1653 req = talloc_zero(c, struct rpc_request);
1654 if (composite_nomem(req, c)) return c;
1656 req->state = RPC_REQUEST_PENDING;
1657 req->call_id = pkt.call_id;
1658 req->async.private_data = c;
1659 req->async.callback = dcerpc_composite_fail;
1660 req->p = p;
1661 req->recv_handler = dcerpc_alter_recv_handler;
1662 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1663 talloc_set_destructor(req, dcerpc_req_dequeue);
1665 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1666 if (!composite_is_ok(c)) return c;
1668 event_add_timed(c->event_ctx, req,
1669 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1670 dcerpc_timeout_handler, req);
1672 return c;
1675 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1677 NTSTATUS result = composite_wait(ctx);
1678 talloc_free(ctx);
1679 return result;
1683 send a dcerpc alter_context request
1685 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1686 TALLOC_CTX *mem_ctx,
1687 const struct ndr_syntax_id *syntax,
1688 const struct ndr_syntax_id *transfer_syntax)
1690 struct composite_context *creq;
1691 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1692 return dcerpc_alter_context_recv(creq);