Remove more event_context_init() uses from function calls within deep down the code.
[Samba/aatanasov.git] / source4 / librpc / rpc / dcerpc.c
blob4758189d3b38f3cf42d9e1958702ce8d4d2e993b
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(void)
36 gensec_init(global_loadparm);
38 return NT_STATUS_OK;
41 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
42 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
44 /* destroy a dcerpc connection */
45 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
47 if (conn->dead) {
48 conn->free_skipped = true;
49 return -1;
51 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
52 return 0;
56 /* initialise a dcerpc connection.
57 the event context is optional
59 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
60 struct event_context *ev,
61 struct smb_iconv_convenience *ic)
63 struct dcerpc_connection *c;
65 c = talloc_zero(mem_ctx, struct dcerpc_connection);
66 if (!c) {
67 return NULL;
70 c->iconv_convenience = talloc_reference(c, ic);
72 c->event_ctx = talloc_reference(c, ev);
74 if (c->event_ctx == NULL) {
75 talloc_free(c);
76 return NULL;
79 c->call_id = 1;
80 c->security_state.auth_info = NULL;
81 c->security_state.session_key = dcerpc_generic_session_key;
82 c->security_state.generic_state = NULL;
83 c->binding_string = NULL;
84 c->flags = 0;
85 c->srv_max_xmit_frag = 0;
86 c->srv_max_recv_frag = 0;
87 c->pending = NULL;
89 talloc_set_destructor(c, dcerpc_connection_destructor);
91 return c;
94 /* initialise a dcerpc pipe. */
95 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct event_context *ev,
96 struct smb_iconv_convenience *ic)
98 struct dcerpc_pipe *p;
100 p = talloc(mem_ctx, struct dcerpc_pipe);
101 if (!p) {
102 return NULL;
105 p->conn = dcerpc_connection_init(p, ev, ic);
106 if (p->conn == NULL) {
107 talloc_free(p);
108 return NULL;
111 p->last_fault_code = 0;
112 p->context_id = 0;
113 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
114 p->binding = NULL;
116 ZERO_STRUCT(p->syntax);
117 ZERO_STRUCT(p->transfer_syntax);
119 return p;
124 choose the next call id to use
126 static uint32_t next_call_id(struct dcerpc_connection *c)
128 c->call_id++;
129 if (c->call_id == 0) {
130 c->call_id++;
132 return c->call_id;
135 /* we need to be able to get/set the fragment length without doing a full
136 decode */
137 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
139 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
140 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
141 } else {
142 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
146 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
148 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
149 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
150 } else {
151 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
155 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
157 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
158 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
159 } else {
160 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
166 setup for a ndr pull, also setting up any flags from the binding string
168 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
169 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
171 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
173 if (ndr == NULL) return ndr;
175 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
176 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
179 if (c->flags & DCERPC_NDR_REF_ALLOC) {
180 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
183 return ndr;
187 parse a data blob into a ncacn_packet structure. This handles both
188 input and output packets
190 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
191 struct ncacn_packet *pkt)
193 struct ndr_pull *ndr;
194 enum ndr_err_code ndr_err;
196 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
197 if (!ndr) {
198 return NT_STATUS_NO_MEMORY;
201 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
202 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
205 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
206 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
207 return ndr_map_error2ntstatus(ndr_err);
210 return NT_STATUS_OK;
214 generate a CONNECT level verifier
216 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
218 *blob = data_blob_talloc(mem_ctx, NULL, 16);
219 if (blob->data == NULL) {
220 return NT_STATUS_NO_MEMORY;
222 SIVAL(blob->data, 0, 1);
223 memset(blob->data+4, 0, 12);
224 return NT_STATUS_OK;
228 check a CONNECT level verifier
230 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
232 if (blob->length != 16 ||
233 IVAL(blob->data, 0) != 1) {
234 return NT_STATUS_ACCESS_DENIED;
236 return NT_STATUS_OK;
240 parse the authentication information on a dcerpc response packet
242 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
243 DATA_BLOB *raw_packet,
244 struct ncacn_packet *pkt)
246 struct ndr_pull *ndr;
247 NTSTATUS status;
248 struct dcerpc_auth auth;
249 DATA_BLOB auth_blob;
250 enum ndr_err_code ndr_err;
252 if (pkt->auth_length == 0 &&
253 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
254 return NT_STATUS_OK;
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 status = dcerpc_check_connect_verifier(&auth.credentials);
312 break;
314 case DCERPC_AUTH_LEVEL_NONE:
315 break;
317 default:
318 status = NT_STATUS_INVALID_LEVEL;
319 break;
322 /* remove the indicated amount of paddiing */
323 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
324 return NT_STATUS_INFO_LENGTH_MISMATCH;
326 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
328 return status;
333 push a dcerpc request packet into a blob, possibly signing it.
335 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
336 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
337 struct ncacn_packet *pkt)
339 NTSTATUS status;
340 struct ndr_push *ndr;
341 DATA_BLOB creds2;
342 size_t payload_length;
343 enum ndr_err_code ndr_err;
345 /* non-signed packets are simpler */
346 if (!c->security_state.auth_info ||
347 !c->security_state.generic_state) {
348 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, c->security_state.auth_info);
351 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
352 if (!ndr) {
353 return NT_STATUS_NO_MEMORY;
356 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
357 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
360 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
361 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
364 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
365 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
366 return ndr_map_error2ntstatus(ndr_err);
368 status = NT_STATUS_OK;
370 /* pad to 16 byte multiple in the payload portion of the
371 packet. This matches what w2k3 does */
372 c->security_state.auth_info->auth_pad_length =
373 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
374 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
376 payload_length = pkt->u.request.stub_and_verifier.length +
377 c->security_state.auth_info->auth_pad_length;
379 /* sign or seal the packet */
380 switch (c->security_state.auth_info->auth_level) {
381 case DCERPC_AUTH_LEVEL_PRIVACY:
382 case DCERPC_AUTH_LEVEL_INTEGRITY:
383 /* We hope this length is accruate. If must be if the
384 * GENSEC mech does AEAD signing of the packet
385 * headers */
386 c->security_state.auth_info->credentials
387 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state,
388 payload_length));
389 data_blob_clear(&c->security_state.auth_info->credentials);
390 break;
392 case DCERPC_AUTH_LEVEL_CONNECT:
393 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
394 break;
396 case DCERPC_AUTH_LEVEL_NONE:
397 c->security_state.auth_info->credentials = data_blob(NULL, 0);
398 break;
400 default:
401 status = NT_STATUS_INVALID_LEVEL;
402 break;
405 if (!NT_STATUS_IS_OK(status)) {
406 return status;
409 /* add the auth verifier */
410 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
411 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
412 return ndr_map_error2ntstatus(ndr_err);
414 status = NT_STATUS_OK;
416 /* extract the whole packet as a blob */
417 *blob = ndr_push_blob(ndr);
419 /* fill in the fragment length and auth_length, we can't fill
420 in these earlier as we don't know the signature length (it
421 could be variable length) */
422 dcerpc_set_frag_length(blob, blob->length);
423 /* We hope this value is accruate. If must be if the GENSEC
424 * mech does AEAD signing of the packet headers */
425 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
427 /* sign or seal the packet */
428 switch (c->security_state.auth_info->auth_level) {
429 case DCERPC_AUTH_LEVEL_PRIVACY:
430 status = gensec_seal_packet(c->security_state.generic_state,
431 mem_ctx,
432 blob->data + DCERPC_REQUEST_LENGTH,
433 payload_length,
434 blob->data,
435 blob->length -
436 c->security_state.auth_info->credentials.length,
437 &creds2);
438 if (!NT_STATUS_IS_OK(status)) {
439 return status;
441 blob->length -= c->security_state.auth_info->credentials.length;
442 if (!data_blob_append(mem_ctx, blob,
443 creds2.data, creds2.length)) {
444 return NT_STATUS_NO_MEMORY;
446 dcerpc_set_auth_length(blob, creds2.length);
447 if (c->security_state.auth_info->credentials.length == 0) {
448 /* this is needed for krb5 only, to correct the total packet
449 length */
450 dcerpc_set_frag_length(blob,
451 dcerpc_get_frag_length(blob)
452 +creds2.length);
454 break;
456 case DCERPC_AUTH_LEVEL_INTEGRITY:
457 status = gensec_sign_packet(c->security_state.generic_state,
458 mem_ctx,
459 blob->data + DCERPC_REQUEST_LENGTH,
460 payload_length,
461 blob->data,
462 blob->length -
463 c->security_state.auth_info->credentials.length,
464 &creds2);
465 if (!NT_STATUS_IS_OK(status)) {
466 return status;
468 blob->length -= c->security_state.auth_info->credentials.length;
469 if (!data_blob_append(mem_ctx, blob,
470 creds2.data, creds2.length)) {
471 return NT_STATUS_NO_MEMORY;
473 dcerpc_set_auth_length(blob, creds2.length);
474 if (c->security_state.auth_info->credentials.length == 0) {
475 /* this is needed for krb5 only, to correct the total packet
476 length */
477 dcerpc_set_frag_length(blob,
478 dcerpc_get_frag_length(blob)
479 +creds2.length);
481 break;
483 case DCERPC_AUTH_LEVEL_CONNECT:
484 break;
486 case DCERPC_AUTH_LEVEL_NONE:
487 c->security_state.auth_info->credentials = data_blob(NULL, 0);
488 break;
490 default:
491 status = NT_STATUS_INVALID_LEVEL;
492 break;
495 data_blob_free(&c->security_state.auth_info->credentials);
497 return NT_STATUS_OK;
502 fill in the fixed values in a dcerpc header
504 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
506 pkt->rpc_vers = 5;
507 pkt->rpc_vers_minor = 0;
508 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
509 pkt->drep[0] = 0;
510 } else {
511 pkt->drep[0] = DCERPC_DREP_LE;
513 pkt->drep[1] = 0;
514 pkt->drep[2] = 0;
515 pkt->drep[3] = 0;
519 map a bind nak reason to a NTSTATUS
521 static NTSTATUS dcerpc_map_reason(uint16_t reason)
523 switch (reason) {
524 case DCERPC_BIND_REASON_ASYNTAX:
525 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
526 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
527 return NT_STATUS_INVALID_PARAMETER;
529 return NT_STATUS_UNSUCCESSFUL;
533 a bind or alter context has failed
535 static void dcerpc_composite_fail(struct rpc_request *req)
537 struct composite_context *c = talloc_get_type(req->async.private_data,
538 struct composite_context);
539 composite_error(c, req->status);
543 remove requests from the pending or queued queues
545 static int dcerpc_req_dequeue(struct rpc_request *req)
547 switch (req->state) {
548 case RPC_REQUEST_QUEUED:
549 DLIST_REMOVE(req->p->conn->request_queue, req);
550 break;
551 case RPC_REQUEST_PENDING:
552 DLIST_REMOVE(req->p->conn->pending, req);
553 break;
554 case RPC_REQUEST_DONE:
555 break;
557 return 0;
562 mark the dcerpc connection dead. All outstanding requests get an error
564 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
566 if (conn->dead) return;
568 conn->dead = true;
570 if (conn->transport.shutdown_pipe) {
571 conn->transport.shutdown_pipe(conn, status);
574 /* all pending requests get the error */
575 while (conn->pending) {
576 struct rpc_request *req = conn->pending;
577 dcerpc_req_dequeue(req);
578 req->state = RPC_REQUEST_DONE;
579 req->status = status;
580 if (req->async.callback) {
581 req->async.callback(req);
585 talloc_set_destructor(conn, NULL);
586 if (conn->free_skipped) {
587 talloc_free(conn);
592 forward declarations of the recv_data handlers for the types of
593 packets we need to handle
595 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
596 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
599 receive a dcerpc reply from the transport. Here we work out what
600 type of reply it is (normal request, bind or alter context) and
601 dispatch to the appropriate handler
603 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
605 struct ncacn_packet pkt;
607 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
608 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
611 /* the transport may be telling us of a severe error, such as
612 a dropped socket */
613 if (!NT_STATUS_IS_OK(status)) {
614 data_blob_free(blob);
615 dcerpc_connection_dead(conn, status);
616 return;
619 /* parse the basic packet to work out what type of response this is */
620 status = ncacn_pull(conn, blob, blob->data, &pkt);
621 if (!NT_STATUS_IS_OK(status)) {
622 data_blob_free(blob);
623 dcerpc_connection_dead(conn, status);
626 dcerpc_request_recv_data(conn, blob, &pkt);
631 Receive a bind reply from the transport
633 static void dcerpc_bind_recv_handler(struct rpc_request *req,
634 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
636 struct composite_context *c;
637 struct dcerpc_connection *conn;
639 c = talloc_get_type(req->async.private_data, struct composite_context);
641 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
642 DEBUG(2,("dcerpc: bind_nak reason %d\n",
643 pkt->u.bind_nak.reject_reason));
644 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
645 reject_reason));
646 return;
649 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
650 (pkt->u.bind_ack.num_results == 0) ||
651 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
652 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
653 return;
656 conn = req->p->conn;
658 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
659 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
661 /* the bind_ack might contain a reply set of credentials */
662 if (conn->security_state.auth_info &&
663 pkt->u.bind_ack.auth_info.length) {
664 enum ndr_err_code ndr_err;
665 ndr_err = ndr_pull_struct_blob(
666 &pkt->u.bind_ack.auth_info, conn,
667 NULL,
668 conn->security_state.auth_info,
669 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
670 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
671 c->status = ndr_map_error2ntstatus(ndr_err);
672 if (!composite_is_ok(c)) return;
676 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
678 composite_done(c);
682 handle timeouts of individual dcerpc requests
684 static void dcerpc_timeout_handler(struct event_context *ev, struct timed_event *te,
685 struct timeval t, void *private)
687 struct rpc_request *req = talloc_get_type(private, struct rpc_request);
689 if (req->ignore_timeout) {
690 dcerpc_req_dequeue(req);
691 req->state = RPC_REQUEST_DONE;
692 req->status = NT_STATUS_IO_TIMEOUT;
693 if (req->async.callback) {
694 req->async.callback(req);
696 return;
699 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
703 send a async dcerpc bind request
705 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
706 TALLOC_CTX *mem_ctx,
707 const struct ndr_syntax_id *syntax,
708 const struct ndr_syntax_id *transfer_syntax)
710 struct composite_context *c;
711 struct ncacn_packet pkt;
712 DATA_BLOB blob;
713 struct rpc_request *req;
715 c = composite_create(mem_ctx,p->conn->event_ctx);
716 if (c == NULL) return NULL;
718 c->private_data = p;
720 p->syntax = *syntax;
721 p->transfer_syntax = *transfer_syntax;
723 init_ncacn_hdr(p->conn, &pkt);
725 pkt.ptype = DCERPC_PKT_BIND;
726 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
727 pkt.call_id = p->conn->call_id;
728 pkt.auth_length = 0;
730 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
731 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
734 pkt.u.bind.max_xmit_frag = 5840;
735 pkt.u.bind.max_recv_frag = 5840;
736 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
737 pkt.u.bind.num_contexts = 1;
738 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
739 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
740 pkt.u.bind.ctx_list[0].context_id = p->context_id;
741 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
742 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
743 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
744 pkt.u.bind.auth_info = data_blob(NULL, 0);
746 /* construct the NDR form of the packet */
747 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
748 p->conn->security_state.auth_info);
749 if (!composite_is_ok(c)) return c;
751 p->conn->transport.recv_data = dcerpc_recv_data;
754 * we allocate a dcerpc_request so we can be in the same
755 * request queue as normal requests
757 req = talloc_zero(c, struct rpc_request);
758 if (composite_nomem(req, c)) return c;
760 req->state = RPC_REQUEST_PENDING;
761 req->call_id = pkt.call_id;
762 req->async.private_data = c;
763 req->async.callback = dcerpc_composite_fail;
764 req->p = p;
765 req->recv_handler = dcerpc_bind_recv_handler;
766 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
767 talloc_set_destructor(req, dcerpc_req_dequeue);
769 c->status = p->conn->transport.send_request(p->conn, &blob,
770 true);
771 if (!composite_is_ok(c)) return c;
773 event_add_timed(c->event_ctx, req,
774 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
775 dcerpc_timeout_handler, req);
777 return c;
781 recv side of async dcerpc bind request
783 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
785 NTSTATUS result = composite_wait(ctx);
786 talloc_free(ctx);
787 return result;
791 perform a continued bind (and auth3)
793 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
794 TALLOC_CTX *mem_ctx)
796 struct ncacn_packet pkt;
797 NTSTATUS status;
798 DATA_BLOB blob;
800 init_ncacn_hdr(c, &pkt);
802 pkt.ptype = DCERPC_PKT_AUTH3;
803 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
804 pkt.call_id = next_call_id(c);
805 pkt.auth_length = 0;
806 pkt.u.auth3._pad = 0;
807 pkt.u.auth3.auth_info = data_blob(NULL, 0);
809 /* construct the NDR form of the packet */
810 status = ncacn_push_auth(&blob, mem_ctx, c->iconv_convenience, &pkt, c->security_state.auth_info);
811 if (!NT_STATUS_IS_OK(status)) {
812 return status;
815 /* send it on its way */
816 status = c->transport.send_request(c, &blob, false);
817 if (!NT_STATUS_IS_OK(status)) {
818 return status;
821 return NT_STATUS_OK;
826 process a fragment received from the transport layer during a
827 request
829 This function frees the data
831 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
832 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
834 struct rpc_request *req;
835 uint_t length;
836 NTSTATUS status = NT_STATUS_OK;
839 if this is an authenticated connection then parse and check
840 the auth info. We have to do this before finding the
841 matching packet, as the request structure might have been
842 removed due to a timeout, but if it has been we still need
843 to run the auth routines so that we don't get the sign/seal
844 info out of step with the server
846 if (c->security_state.auth_info && c->security_state.generic_state &&
847 pkt->ptype == DCERPC_PKT_RESPONSE) {
848 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
851 /* find the matching request */
852 for (req=c->pending;req;req=req->next) {
853 if (pkt->call_id == req->call_id) break;
856 #if 0
857 /* useful for testing certain vendors RPC servers */
858 if (req == NULL && c->pending && pkt->call_id == 0) {
859 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
860 req = c->pending;
862 #endif
864 if (req == NULL) {
865 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
866 data_blob_free(raw_packet);
867 return;
870 talloc_steal(req, raw_packet->data);
872 if (req->recv_handler != NULL) {
873 dcerpc_req_dequeue(req);
874 req->state = RPC_REQUEST_DONE;
875 req->recv_handler(req, raw_packet, pkt);
876 return;
879 if (pkt->ptype == DCERPC_PKT_FAULT) {
880 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
881 req->fault_code = pkt->u.fault.status;
882 req->status = NT_STATUS_NET_WRITE_FAULT;
883 goto req_done;
886 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
887 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
888 (int)pkt->ptype));
889 req->fault_code = DCERPC_FAULT_OTHER;
890 req->status = NT_STATUS_NET_WRITE_FAULT;
891 goto req_done;
894 /* now check the status from the auth routines, and if it failed then fail
895 this request accordingly */
896 if (!NT_STATUS_IS_OK(status)) {
897 req->status = status;
898 goto req_done;
901 length = pkt->u.response.stub_and_verifier.length;
903 if (length > 0) {
904 req->payload.data = talloc_realloc(req,
905 req->payload.data,
906 uint8_t,
907 req->payload.length + length);
908 if (!req->payload.data) {
909 req->status = NT_STATUS_NO_MEMORY;
910 goto req_done;
912 memcpy(req->payload.data+req->payload.length,
913 pkt->u.response.stub_and_verifier.data, length);
914 req->payload.length += length;
917 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
918 c->transport.send_read(c);
919 return;
922 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
923 req->flags |= DCERPC_PULL_BIGENDIAN;
924 } else {
925 req->flags &= ~DCERPC_PULL_BIGENDIAN;
929 req_done:
930 /* we've got the full payload */
931 req->state = RPC_REQUEST_DONE;
932 DLIST_REMOVE(c->pending, req);
934 if (c->request_queue != NULL) {
935 /* We have to look at shipping further requests before calling
936 * the async function, that one might close the pipe */
937 dcerpc_ship_next_request(c);
940 if (req->async.callback) {
941 req->async.callback(req);
946 perform the send side of a async dcerpc request
948 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
949 const struct GUID *object,
950 uint16_t opnum,
951 bool async,
952 DATA_BLOB *stub_data)
954 struct rpc_request *req;
956 p->conn->transport.recv_data = dcerpc_recv_data;
958 req = talloc(p, struct rpc_request);
959 if (req == NULL) {
960 return NULL;
963 req->p = p;
964 req->call_id = next_call_id(p->conn);
965 req->status = NT_STATUS_OK;
966 req->state = RPC_REQUEST_QUEUED;
967 req->payload = data_blob(NULL, 0);
968 req->flags = 0;
969 req->fault_code = 0;
970 req->async_call = async;
971 req->ignore_timeout = false;
972 req->async.callback = NULL;
973 req->async.private_data = NULL;
974 req->recv_handler = NULL;
976 if (object != NULL) {
977 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
978 if (req->object == NULL) {
979 talloc_free(req);
980 return NULL;
982 } else {
983 req->object = NULL;
986 req->opnum = opnum;
987 req->request_data.length = stub_data->length;
988 req->request_data.data = talloc_reference(req, stub_data->data);
989 if (req->request_data.length && req->request_data.data == NULL) {
990 return NULL;
993 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
994 talloc_set_destructor(req, dcerpc_req_dequeue);
996 dcerpc_ship_next_request(p->conn);
998 if (p->request_timeout) {
999 event_add_timed(dcerpc_event_context(p), req,
1000 timeval_current_ofs(p->request_timeout, 0),
1001 dcerpc_timeout_handler, req);
1004 return req;
1008 Send a request using the transport
1011 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
1013 struct rpc_request *req;
1014 struct dcerpc_pipe *p;
1015 DATA_BLOB *stub_data;
1016 struct ncacn_packet pkt;
1017 DATA_BLOB blob;
1018 uint32_t remaining, chunk_size;
1019 bool first_packet = true;
1021 req = c->request_queue;
1022 if (req == NULL) {
1023 return;
1026 p = req->p;
1027 stub_data = &req->request_data;
1029 if (!req->async_call && (c->pending != NULL)) {
1030 return;
1033 DLIST_REMOVE(c->request_queue, req);
1034 DLIST_ADD(c->pending, req);
1035 req->state = RPC_REQUEST_PENDING;
1037 init_ncacn_hdr(p->conn, &pkt);
1039 remaining = stub_data->length;
1041 /* we can write a full max_recv_frag size, minus the dcerpc
1042 request header size */
1043 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
1045 pkt.ptype = DCERPC_PKT_REQUEST;
1046 pkt.call_id = req->call_id;
1047 pkt.auth_length = 0;
1048 pkt.pfc_flags = 0;
1049 pkt.u.request.alloc_hint = remaining;
1050 pkt.u.request.context_id = p->context_id;
1051 pkt.u.request.opnum = req->opnum;
1053 if (req->object) {
1054 pkt.u.request.object.object = *req->object;
1055 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1056 chunk_size -= ndr_size_GUID(req->object,0);
1059 /* we send a series of pdus without waiting for a reply */
1060 while (remaining > 0 || first_packet) {
1061 uint32_t chunk = MIN(chunk_size, remaining);
1062 bool last_frag = false;
1064 first_packet = false;
1065 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1067 if (remaining == stub_data->length) {
1068 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1070 if (chunk == remaining) {
1071 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1072 last_frag = true;
1075 pkt.u.request.stub_and_verifier.data = stub_data->data +
1076 (stub_data->length - remaining);
1077 pkt.u.request.stub_and_verifier.length = chunk;
1079 req->status = ncacn_push_request_sign(p->conn, &blob, req, &pkt);
1080 if (!NT_STATUS_IS_OK(req->status)) {
1081 req->state = RPC_REQUEST_DONE;
1082 DLIST_REMOVE(p->conn->pending, req);
1083 return;
1086 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
1087 if (!NT_STATUS_IS_OK(req->status)) {
1088 req->state = RPC_REQUEST_DONE;
1089 DLIST_REMOVE(p->conn->pending, req);
1090 return;
1093 remaining -= chunk;
1098 return the event context for a dcerpc pipe
1099 used by callers who wish to operate asynchronously
1101 _PUBLIC_ struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
1103 return p->conn->event_ctx;
1109 perform the receive side of a async dcerpc request
1111 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1112 TALLOC_CTX *mem_ctx,
1113 DATA_BLOB *stub_data)
1115 NTSTATUS status;
1117 while (req->state != RPC_REQUEST_DONE) {
1118 struct event_context *ctx = dcerpc_event_context(req->p);
1119 if (event_loop_once(ctx) != 0) {
1120 return NT_STATUS_CONNECTION_DISCONNECTED;
1123 *stub_data = req->payload;
1124 status = req->status;
1125 if (stub_data->data) {
1126 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1128 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1129 req->p->last_fault_code = req->fault_code;
1131 talloc_free(req);
1132 return status;
1136 perform a full request/response pair on a dcerpc pipe
1138 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1139 struct GUID *object,
1140 uint16_t opnum,
1141 bool async,
1142 TALLOC_CTX *mem_ctx,
1143 DATA_BLOB *stub_data_in,
1144 DATA_BLOB *stub_data_out)
1146 struct rpc_request *req;
1148 req = dcerpc_request_send(p, object, opnum, async, stub_data_in);
1149 if (req == NULL) {
1150 return NT_STATUS_NO_MEMORY;
1153 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1158 this is a paranoid NDR validator. For every packet we push onto the wire
1159 we pull it back again, then push it again. Then we compare the raw NDR data
1160 for that to the NDR we initially generated. If they don't match then we know
1161 we must have a bug in either the pull or push side of our code
1163 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1164 TALLOC_CTX *mem_ctx,
1165 DATA_BLOB blob,
1166 size_t struct_size,
1167 ndr_push_flags_fn_t ndr_push,
1168 ndr_pull_flags_fn_t ndr_pull)
1170 void *st;
1171 struct ndr_pull *pull;
1172 struct ndr_push *push;
1173 DATA_BLOB blob2;
1174 enum ndr_err_code ndr_err;
1176 st = talloc_size(mem_ctx, struct_size);
1177 if (!st) {
1178 return NT_STATUS_NO_MEMORY;
1181 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1182 if (!pull) {
1183 return NT_STATUS_NO_MEMORY;
1185 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1187 ndr_err = ndr_pull(pull, NDR_IN, st);
1188 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1189 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1190 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1191 "failed input validation pull - %s",
1192 nt_errstr(status));
1193 return ndr_map_error2ntstatus(ndr_err);
1196 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1197 if (!push) {
1198 return NT_STATUS_NO_MEMORY;
1201 ndr_err = ndr_push(push, NDR_IN, st);
1202 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1203 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1204 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1205 "failed input validation push - %s",
1206 nt_errstr(status));
1207 return ndr_map_error2ntstatus(ndr_err);
1210 blob2 = ndr_push_blob(push);
1212 if (data_blob_cmp(&blob, &blob2) != 0) {
1213 DEBUG(3,("original:\n"));
1214 dump_data(3, blob.data, blob.length);
1215 DEBUG(3,("secondary:\n"));
1216 dump_data(3, blob2.data, blob2.length);
1217 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1218 "failed input validation blobs doesn't match");
1219 return ndr_map_error2ntstatus(ndr_err);
1222 return NT_STATUS_OK;
1226 this is a paranoid NDR input validator. For every packet we pull
1227 from the wire we push it back again then pull and push it
1228 again. Then we compare the raw NDR data for that to the NDR we
1229 initially generated. If they don't match then we know we must have a
1230 bug in either the pull or push side of our code
1232 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1233 struct ndr_pull *pull_in,
1234 void *struct_ptr,
1235 size_t struct_size,
1236 ndr_push_flags_fn_t ndr_push,
1237 ndr_pull_flags_fn_t ndr_pull,
1238 ndr_print_function_t ndr_print)
1240 void *st;
1241 struct ndr_pull *pull;
1242 struct ndr_push *push;
1243 DATA_BLOB blob, blob2;
1244 TALLOC_CTX *mem_ctx = pull_in;
1245 char *s1, *s2;
1246 enum ndr_err_code ndr_err;
1248 st = talloc_size(mem_ctx, struct_size);
1249 if (!st) {
1250 return NT_STATUS_NO_MEMORY;
1252 memcpy(st, struct_ptr, struct_size);
1254 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1255 if (!push) {
1256 return NT_STATUS_NO_MEMORY;
1259 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1260 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1261 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1262 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1263 "failed output validation push - %s",
1264 nt_errstr(status));
1265 return ndr_map_error2ntstatus(ndr_err);
1268 blob = ndr_push_blob(push);
1270 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1271 if (!pull) {
1272 return NT_STATUS_NO_MEMORY;
1275 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1276 ndr_err = ndr_pull(pull, NDR_OUT, st);
1277 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1278 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1279 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1280 "failed output validation pull - %s",
1281 nt_errstr(status));
1282 return ndr_map_error2ntstatus(ndr_err);
1285 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1286 if (!push) {
1287 return NT_STATUS_NO_MEMORY;
1290 ndr_err = ndr_push(push, NDR_OUT, st);
1291 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1292 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1293 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1294 "failed output validation push2 - %s",
1295 nt_errstr(status));
1296 return ndr_map_error2ntstatus(ndr_err);
1299 blob2 = ndr_push_blob(push);
1301 if (data_blob_cmp(&blob, &blob2) != 0) {
1302 DEBUG(3,("original:\n"));
1303 dump_data(3, blob.data, blob.length);
1304 DEBUG(3,("secondary:\n"));
1305 dump_data(3, blob2.data, blob2.length);
1306 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1307 "failed output validation blobs doesn't match");
1308 return ndr_map_error2ntstatus(ndr_err);
1311 /* this checks the printed forms of the two structures, which effectively
1312 tests all of the value() attributes */
1313 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1314 NDR_OUT, struct_ptr);
1315 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1316 NDR_OUT, st);
1317 if (strcmp(s1, s2) != 0) {
1318 #if 1
1319 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1320 #else
1321 /* this is sometimes useful */
1322 printf("VALIDATE ERROR\n");
1323 file_save("wire.dat", s1, strlen(s1));
1324 file_save("gen.dat", s2, strlen(s2));
1325 system("diff -u wire.dat gen.dat");
1326 #endif
1327 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1328 "failed output validation strings doesn't match");
1329 return ndr_map_error2ntstatus(ndr_err);
1332 return NT_STATUS_OK;
1337 send a rpc request given a dcerpc_call structure
1339 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1340 const struct GUID *object,
1341 const struct ndr_interface_table *table,
1342 uint32_t opnum,
1343 TALLOC_CTX *mem_ctx,
1344 void *r)
1346 const struct ndr_interface_call *call;
1347 struct ndr_push *push;
1348 NTSTATUS status;
1349 DATA_BLOB request;
1350 struct rpc_request *req;
1351 enum ndr_err_code ndr_err;
1353 call = &table->calls[opnum];
1355 /* setup for a ndr_push_* call */
1356 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1357 if (!push) {
1358 return NULL;
1361 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1362 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1365 /* push the structure into a blob */
1366 ndr_err = call->ndr_push(push, NDR_IN, r);
1367 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1368 status = ndr_map_error2ntstatus(ndr_err);
1369 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1370 nt_errstr(status)));
1371 talloc_free(push);
1372 return NULL;
1375 /* retrieve the blob */
1376 request = ndr_push_blob(push);
1378 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1379 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1380 call->ndr_push, call->ndr_pull);
1381 if (!NT_STATUS_IS_OK(status)) {
1382 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1383 nt_errstr(status)));
1384 talloc_free(push);
1385 return NULL;
1389 DEBUG(10,("rpc request data:\n"));
1390 dump_data(10, request.data, request.length);
1392 /* make the actual dcerpc request */
1393 req = dcerpc_request_send(p, object, opnum, table->calls[opnum].async,
1394 &request);
1396 if (req != NULL) {
1397 req->ndr.table = table;
1398 req->ndr.opnum = opnum;
1399 req->ndr.struct_ptr = r;
1400 req->ndr.mem_ctx = mem_ctx;
1403 talloc_free(push);
1405 return req;
1409 receive the answer from a dcerpc_ndr_request_send()
1411 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1413 struct dcerpc_pipe *p = req->p;
1414 NTSTATUS status;
1415 DATA_BLOB response;
1416 struct ndr_pull *pull;
1417 uint_t flags;
1418 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1419 void *r = req->ndr.struct_ptr;
1420 uint32_t opnum = req->ndr.opnum;
1421 const struct ndr_interface_table *table = req->ndr.table;
1422 const struct ndr_interface_call *call = &table->calls[opnum];
1423 enum ndr_err_code ndr_err;
1425 /* make sure the recv code doesn't free the request, as we
1426 need to grab the flags element before it is freed */
1427 if (talloc_reference(p, req) == NULL) {
1428 return NT_STATUS_NO_MEMORY;
1431 status = dcerpc_request_recv(req, mem_ctx, &response);
1432 if (!NT_STATUS_IS_OK(status)) {
1433 talloc_unlink(p, req);
1434 return status;
1437 flags = req->flags;
1439 /* prepare for ndr_pull_* */
1440 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1441 if (!pull) {
1442 talloc_unlink(p, req);
1443 return NT_STATUS_NO_MEMORY;
1446 if (pull->data) {
1447 pull->data = talloc_steal(pull, pull->data);
1449 talloc_unlink(p, req);
1451 if (flags & DCERPC_PULL_BIGENDIAN) {
1452 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1455 DEBUG(10,("rpc reply data:\n"));
1456 dump_data(10, pull->data, pull->data_size);
1458 /* pull the structure from the blob */
1459 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1460 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1461 status = ndr_map_error2ntstatus(ndr_err);
1462 dcerpc_log_packet(table, opnum, NDR_OUT,
1463 &response);
1464 return status;
1467 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1468 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1469 call->ndr_push, call->ndr_pull,
1470 call->ndr_print);
1471 if (!NT_STATUS_IS_OK(status)) {
1472 dcerpc_log_packet(table, opnum, NDR_OUT,
1473 &response);
1474 return status;
1478 if (pull->offset != pull->data_size) {
1479 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1480 pull->data_size - pull->offset));
1481 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1482 but it turns out that early versions of NT
1483 (specifically NT3.1) add junk onto the end of rpc
1484 packets, so if we want to interoperate at all with
1485 those versions then we need to ignore this error */
1488 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1490 return NT_STATUS_OK;
1495 a useful helper function for synchronous rpc requests
1497 this can be used when you have ndr push/pull functions in the
1498 standard format
1500 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1501 const struct GUID *object,
1502 const struct ndr_interface_table *table,
1503 uint32_t opnum,
1504 TALLOC_CTX *mem_ctx,
1505 void *r)
1507 struct rpc_request *req;
1509 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1510 if (req == NULL) {
1511 return NT_STATUS_NO_MEMORY;
1514 return dcerpc_ndr_request_recv(req);
1519 a useful function for retrieving the server name we connected to
1521 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1523 if (!p->conn->transport.target_hostname) {
1524 if (!p->conn->transport.peer_name) {
1525 return "";
1527 return p->conn->transport.peer_name(p->conn);
1529 return p->conn->transport.target_hostname(p->conn);
1534 get the dcerpc auth_level for a open connection
1536 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1538 uint8_t auth_level;
1540 if (c->flags & DCERPC_SEAL) {
1541 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1542 } else if (c->flags & DCERPC_SIGN) {
1543 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1544 } else if (c->flags & DCERPC_CONNECT) {
1545 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1546 } else {
1547 auth_level = DCERPC_AUTH_LEVEL_NONE;
1549 return auth_level;
1553 Receive an alter reply from the transport
1555 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1556 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1558 struct composite_context *c;
1559 struct dcerpc_pipe *recv_pipe;
1561 c = talloc_get_type(req->async.private_data, struct composite_context);
1562 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1564 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1565 pkt->u.alter_resp.num_results == 1 &&
1566 pkt->u.alter_resp.ctx_list[0].result != 0) {
1567 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1568 pkt->u.alter_resp.ctx_list[0].reason));
1569 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1570 return;
1573 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1574 pkt->u.alter_resp.num_results == 0 ||
1575 pkt->u.alter_resp.ctx_list[0].result != 0) {
1576 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1577 return;
1580 /* the alter_resp might contain a reply set of credentials */
1581 if (recv_pipe->conn->security_state.auth_info &&
1582 pkt->u.alter_resp.auth_info.length) {
1583 enum ndr_err_code ndr_err;
1584 ndr_err = ndr_pull_struct_blob(
1585 &pkt->u.alter_resp.auth_info, recv_pipe,
1586 NULL,
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, p->conn->iconv_convenience, &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 _PUBLIC_ 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);