s4:librpc/rpc: use the correct ndr flags in dcerpc_ndr_validate_in()
[Samba/gebeck_regimport.git] / source4 / librpc / rpc / dcerpc.c
bloba04dbb1ea9e05ce607a4e6e1f5e8c62822875f01
1 /*
2 Unix SMB/CIFS implementation.
3 raw dcerpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
34 _PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
36 return gensec_init(lp_ctx);
39 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
45 if (conn->dead) {
46 conn->free_skipped = true;
47 return -1;
49 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
50 return 0;
54 /* initialise a dcerpc connection.
55 the event context is optional
57 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
58 struct tevent_context *ev)
60 struct dcerpc_connection *c;
62 c = talloc_zero(mem_ctx, struct dcerpc_connection);
63 if (!c) {
64 return NULL;
67 c->event_ctx = ev;
69 if (c->event_ctx == NULL) {
70 talloc_free(c);
71 return NULL;
74 c->call_id = 1;
75 c->security_state.auth_info = NULL;
76 c->security_state.session_key = dcerpc_generic_session_key;
77 c->security_state.generic_state = NULL;
78 c->binding_string = NULL;
79 c->flags = 0;
80 c->srv_max_xmit_frag = 0;
81 c->srv_max_recv_frag = 0;
82 c->pending = NULL;
84 talloc_set_destructor(c, dcerpc_connection_destructor);
86 return c;
89 /* initialise a dcerpc pipe. */
90 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev)
92 struct dcerpc_pipe *p;
94 p = talloc(mem_ctx, struct dcerpc_pipe);
95 if (!p) {
96 return NULL;
99 p->conn = dcerpc_connection_init(p, ev);
100 if (p->conn == NULL) {
101 talloc_free(p);
102 return NULL;
105 p->last_fault_code = 0;
106 p->context_id = 0;
107 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
108 p->binding = NULL;
110 ZERO_STRUCT(p->syntax);
111 ZERO_STRUCT(p->transfer_syntax);
113 if (DEBUGLVL(100)) {
114 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
117 p->binding_handle = talloc(p, struct dcerpc_binding_handle);
118 if (p->binding_handle == NULL) {
119 talloc_free(p);
120 return NULL;
122 p->binding_handle->private_data = p;
124 return p;
129 choose the next call id to use
131 static uint32_t next_call_id(struct dcerpc_connection *c)
133 c->call_id++;
134 if (c->call_id == 0) {
135 c->call_id++;
137 return c->call_id;
141 setup for a ndr pull, also setting up any flags from the binding string
143 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
144 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
146 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
148 if (ndr == NULL) return ndr;
150 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
151 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
154 if (c->flags & DCERPC_NDR_REF_ALLOC) {
155 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
158 if (c->flags & DCERPC_NDR64) {
159 ndr->flags |= LIBNDR_FLAG_NDR64;
162 return ndr;
166 parse a data blob into a ncacn_packet structure. This handles both
167 input and output packets
169 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
170 struct ncacn_packet *pkt)
172 struct ndr_pull *ndr;
173 enum ndr_err_code ndr_err;
175 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
176 if (!ndr) {
177 return NT_STATUS_NO_MEMORY;
180 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
181 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
184 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
185 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
186 return ndr_map_error2ntstatus(ndr_err);
189 return NT_STATUS_OK;
193 parse the authentication information on a dcerpc response packet
195 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
196 DATA_BLOB *raw_packet,
197 struct ncacn_packet *pkt)
199 NTSTATUS status;
200 struct dcerpc_auth auth;
201 uint32_t auth_length;
203 if (!c->security_state.auth_info ||
204 !c->security_state.generic_state) {
205 return NT_STATUS_OK;
208 switch (c->security_state.auth_info->auth_level) {
209 case DCERPC_AUTH_LEVEL_PRIVACY:
210 case DCERPC_AUTH_LEVEL_INTEGRITY:
211 break;
213 case DCERPC_AUTH_LEVEL_CONNECT:
214 if (pkt->auth_length != 0) {
215 break;
217 return NT_STATUS_OK;
218 case DCERPC_AUTH_LEVEL_NONE:
219 if (pkt->auth_length != 0) {
220 return NT_STATUS_INVALID_NETWORK_RESPONSE;
222 return NT_STATUS_OK;
224 default:
225 return NT_STATUS_INVALID_LEVEL;
228 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
229 &pkt->u.response.stub_and_verifier,
230 &auth, &auth_length, false);
231 NT_STATUS_NOT_OK_RETURN(status);
233 pkt->u.response.stub_and_verifier.length -= auth_length;
235 /* check signature or unseal the packet */
236 switch (c->security_state.auth_info->auth_level) {
237 case DCERPC_AUTH_LEVEL_PRIVACY:
238 status = gensec_unseal_packet(c->security_state.generic_state,
239 mem_ctx,
240 raw_packet->data + DCERPC_REQUEST_LENGTH,
241 pkt->u.response.stub_and_verifier.length,
242 raw_packet->data,
243 raw_packet->length - auth.credentials.length,
244 &auth.credentials);
245 memcpy(pkt->u.response.stub_and_verifier.data,
246 raw_packet->data + DCERPC_REQUEST_LENGTH,
247 pkt->u.response.stub_and_verifier.length);
248 break;
250 case DCERPC_AUTH_LEVEL_INTEGRITY:
251 status = gensec_check_packet(c->security_state.generic_state,
252 mem_ctx,
253 pkt->u.response.stub_and_verifier.data,
254 pkt->u.response.stub_and_verifier.length,
255 raw_packet->data,
256 raw_packet->length - auth.credentials.length,
257 &auth.credentials);
258 break;
260 case DCERPC_AUTH_LEVEL_CONNECT:
261 /* for now we ignore possible signatures here */
262 status = NT_STATUS_OK;
263 break;
265 default:
266 status = NT_STATUS_INVALID_LEVEL;
267 break;
270 /* remove the indicated amount of padding */
271 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
272 return NT_STATUS_INFO_LENGTH_MISMATCH;
274 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
276 return status;
281 push a dcerpc request packet into a blob, possibly signing it.
283 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
284 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
285 size_t sig_size,
286 struct ncacn_packet *pkt)
288 NTSTATUS status;
289 struct ndr_push *ndr;
290 DATA_BLOB creds2;
291 size_t payload_length;
292 enum ndr_err_code ndr_err;
293 size_t hdr_size = DCERPC_REQUEST_LENGTH;
295 /* non-signed packets are simpler */
296 if (sig_size == 0) {
297 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
300 switch (c->security_state.auth_info->auth_level) {
301 case DCERPC_AUTH_LEVEL_PRIVACY:
302 case DCERPC_AUTH_LEVEL_INTEGRITY:
303 break;
305 case DCERPC_AUTH_LEVEL_CONNECT:
306 /* TODO: let the gensec mech decide if it wants to generate a signature */
307 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
309 case DCERPC_AUTH_LEVEL_NONE:
310 return ncacn_push_auth(blob, mem_ctx, pkt, NULL);
312 default:
313 return NT_STATUS_INVALID_LEVEL;
316 ndr = ndr_push_init_ctx(mem_ctx);
317 if (!ndr) {
318 return NT_STATUS_NO_MEMORY;
321 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
322 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
325 if (c->flags & DCERPC_NDR64) {
326 ndr->flags |= LIBNDR_FLAG_NDR64;
329 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
330 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
331 hdr_size += 16;
334 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
335 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
336 return ndr_map_error2ntstatus(ndr_err);
339 /* pad to 16 byte multiple in the payload portion of the
340 packet. This matches what w2k3 does. Note that we can't use
341 ndr_push_align() as that is relative to the start of the
342 whole packet, whereas w2k8 wants it relative to the start
343 of the stub */
344 c->security_state.auth_info->auth_pad_length =
345 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
346 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
347 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
348 return ndr_map_error2ntstatus(ndr_err);
351 payload_length = pkt->u.request.stub_and_verifier.length +
352 c->security_state.auth_info->auth_pad_length;
354 /* we start without signature, it will appended later */
355 c->security_state.auth_info->credentials = data_blob(NULL,0);
357 /* add the auth verifier */
358 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
359 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
360 return ndr_map_error2ntstatus(ndr_err);
363 /* extract the whole packet as a blob */
364 *blob = ndr_push_blob(ndr);
367 * Setup the frag and auth length in the packet buffer.
368 * This is needed if the GENSEC mech does AEAD signing
369 * of the packet headers. The signature itself will be
370 * appended later.
372 dcerpc_set_frag_length(blob, blob->length + sig_size);
373 dcerpc_set_auth_length(blob, sig_size);
375 /* sign or seal the packet */
376 switch (c->security_state.auth_info->auth_level) {
377 case DCERPC_AUTH_LEVEL_PRIVACY:
378 status = gensec_seal_packet(c->security_state.generic_state,
379 mem_ctx,
380 blob->data + hdr_size,
381 payload_length,
382 blob->data,
383 blob->length,
384 &creds2);
385 if (!NT_STATUS_IS_OK(status)) {
386 return status;
388 break;
390 case DCERPC_AUTH_LEVEL_INTEGRITY:
391 status = gensec_sign_packet(c->security_state.generic_state,
392 mem_ctx,
393 blob->data + hdr_size,
394 payload_length,
395 blob->data,
396 blob->length,
397 &creds2);
398 if (!NT_STATUS_IS_OK(status)) {
399 return status;
401 break;
403 default:
404 status = NT_STATUS_INVALID_LEVEL;
405 break;
408 if (creds2.length != sig_size) {
409 /* this means the sig_size estimate for the signature
410 was incorrect. We have to correct the packet
411 sizes. That means we could go over the max fragment
412 length */
413 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
414 (unsigned) creds2.length,
415 (unsigned) sig_size,
416 (unsigned) c->security_state.auth_info->auth_pad_length,
417 (unsigned) pkt->u.request.stub_and_verifier.length));
418 dcerpc_set_frag_length(blob, blob->length + creds2.length);
419 dcerpc_set_auth_length(blob, creds2.length);
422 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
423 return NT_STATUS_NO_MEMORY;
426 return NT_STATUS_OK;
431 fill in the fixed values in a dcerpc header
433 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
435 pkt->rpc_vers = 5;
436 pkt->rpc_vers_minor = 0;
437 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
438 pkt->drep[0] = 0;
439 } else {
440 pkt->drep[0] = DCERPC_DREP_LE;
442 pkt->drep[1] = 0;
443 pkt->drep[2] = 0;
444 pkt->drep[3] = 0;
448 map a bind nak reason to a NTSTATUS
450 static NTSTATUS dcerpc_map_reason(uint16_t reason)
452 switch (reason) {
453 case DCERPC_BIND_REASON_ASYNTAX:
454 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
455 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
456 return NT_STATUS_INVALID_PARAMETER;
458 return NT_STATUS_UNSUCCESSFUL;
462 a bind or alter context has failed
464 static void dcerpc_composite_fail(struct rpc_request *req)
466 struct composite_context *c = talloc_get_type(req->async.private_data,
467 struct composite_context);
468 composite_error(c, req->status);
472 remove requests from the pending or queued queues
474 static int dcerpc_req_dequeue(struct rpc_request *req)
476 switch (req->state) {
477 case RPC_REQUEST_QUEUED:
478 DLIST_REMOVE(req->p->conn->request_queue, req);
479 break;
480 case RPC_REQUEST_PENDING:
481 DLIST_REMOVE(req->p->conn->pending, req);
482 break;
483 case RPC_REQUEST_DONE:
484 break;
486 return 0;
491 mark the dcerpc connection dead. All outstanding requests get an error
493 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
495 if (conn->dead) return;
497 conn->dead = true;
499 if (conn->transport.shutdown_pipe) {
500 conn->transport.shutdown_pipe(conn, status);
503 /* all pending requests get the error */
504 while (conn->pending) {
505 struct rpc_request *req = conn->pending;
506 dcerpc_req_dequeue(req);
507 req->state = RPC_REQUEST_DONE;
508 req->status = status;
509 if (req->async.callback) {
510 req->async.callback(req);
514 talloc_set_destructor(conn, NULL);
515 if (conn->free_skipped) {
516 talloc_free(conn);
521 forward declarations of the recv_data handlers for the types of
522 packets we need to handle
524 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
525 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
528 receive a dcerpc reply from the transport. Here we work out what
529 type of reply it is (normal request, bind or alter context) and
530 dispatch to the appropriate handler
532 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
534 struct ncacn_packet pkt;
536 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
537 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
540 /* the transport may be telling us of a severe error, such as
541 a dropped socket */
542 if (!NT_STATUS_IS_OK(status)) {
543 data_blob_free(blob);
544 dcerpc_connection_dead(conn, status);
545 return;
548 /* parse the basic packet to work out what type of response this is */
549 status = ncacn_pull(conn, blob, blob->data, &pkt);
550 if (!NT_STATUS_IS_OK(status)) {
551 data_blob_free(blob);
552 dcerpc_connection_dead(conn, status);
555 dcerpc_request_recv_data(conn, blob, &pkt);
559 Receive a bind reply from the transport
561 static void dcerpc_bind_recv_handler(struct rpc_request *req,
562 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
564 struct composite_context *c;
565 struct dcerpc_connection *conn;
567 c = talloc_get_type(req->async.private_data, struct composite_context);
569 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
570 DEBUG(2,("dcerpc: bind_nak reason %d\n",
571 pkt->u.bind_nak.reject_reason));
572 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
573 reject_reason));
574 return;
577 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
578 (pkt->u.bind_ack.num_results == 0) ||
579 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
580 req->p->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
581 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
582 return;
585 conn = req->p->conn;
587 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
588 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
590 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
591 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
592 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
595 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
596 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
597 conn->flags |= DCERPC_HEADER_SIGNING;
600 /* the bind_ack might contain a reply set of credentials */
601 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
602 NTSTATUS status;
603 uint32_t auth_length;
604 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
605 conn->security_state.auth_info, &auth_length, true);
606 if (!NT_STATUS_IS_OK(status)) {
607 composite_error(c, status);
608 return;
612 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
614 composite_done(c);
618 handle timeouts of individual dcerpc requests
620 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
621 struct timeval t, void *private_data)
623 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
625 if (req->ignore_timeout) {
626 dcerpc_req_dequeue(req);
627 req->state = RPC_REQUEST_DONE;
628 req->status = NT_STATUS_IO_TIMEOUT;
629 if (req->async.callback) {
630 req->async.callback(req);
632 return;
635 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
639 send a async dcerpc bind request
641 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
642 TALLOC_CTX *mem_ctx,
643 const struct ndr_syntax_id *syntax,
644 const struct ndr_syntax_id *transfer_syntax)
646 struct composite_context *c;
647 struct ncacn_packet pkt;
648 DATA_BLOB blob;
649 struct rpc_request *req;
651 c = composite_create(mem_ctx,p->conn->event_ctx);
652 if (c == NULL) return NULL;
654 c->private_data = p;
656 p->syntax = *syntax;
657 p->transfer_syntax = *transfer_syntax;
659 init_ncacn_hdr(p->conn, &pkt);
661 pkt.ptype = DCERPC_PKT_BIND;
662 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
663 pkt.call_id = p->conn->call_id;
664 pkt.auth_length = 0;
666 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
667 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
670 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
671 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
674 pkt.u.bind.max_xmit_frag = 5840;
675 pkt.u.bind.max_recv_frag = 5840;
676 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
677 pkt.u.bind.num_contexts = 1;
678 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
679 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
680 pkt.u.bind.ctx_list[0].context_id = p->context_id;
681 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
682 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
683 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
684 pkt.u.bind.auth_info = data_blob(NULL, 0);
686 /* construct the NDR form of the packet */
687 c->status = ncacn_push_auth(&blob, c, &pkt,
688 p->conn->security_state.auth_info);
689 if (!composite_is_ok(c)) return c;
691 p->conn->transport.recv_data = dcerpc_recv_data;
694 * we allocate a dcerpc_request so we can be in the same
695 * request queue as normal requests
697 req = talloc_zero(c, struct rpc_request);
698 if (composite_nomem(req, c)) return c;
700 req->state = RPC_REQUEST_PENDING;
701 req->call_id = pkt.call_id;
702 req->async.private_data = c;
703 req->async.callback = dcerpc_composite_fail;
704 req->p = p;
705 req->recv_handler = dcerpc_bind_recv_handler;
706 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
707 talloc_set_destructor(req, dcerpc_req_dequeue);
709 c->status = p->conn->transport.send_request(p->conn, &blob,
710 true);
711 if (!composite_is_ok(c)) return c;
713 event_add_timed(c->event_ctx, req,
714 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
715 dcerpc_timeout_handler, req);
717 return c;
721 recv side of async dcerpc bind request
723 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
725 NTSTATUS result = composite_wait(ctx);
726 talloc_free(ctx);
727 return result;
731 perform a continued bind (and auth3)
733 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
734 TALLOC_CTX *mem_ctx)
736 struct ncacn_packet pkt;
737 NTSTATUS status;
738 DATA_BLOB blob;
740 init_ncacn_hdr(p->conn, &pkt);
742 pkt.ptype = DCERPC_PKT_AUTH3;
743 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
744 pkt.call_id = next_call_id(p->conn);
745 pkt.auth_length = 0;
746 pkt.u.auth3.auth_info = data_blob(NULL, 0);
748 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
749 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
752 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
753 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
756 /* construct the NDR form of the packet */
757 status = ncacn_push_auth(&blob, mem_ctx,
758 &pkt,
759 p->conn->security_state.auth_info);
760 if (!NT_STATUS_IS_OK(status)) {
761 return status;
764 /* send it on its way */
765 status = p->conn->transport.send_request(p->conn, &blob, false);
766 if (!NT_STATUS_IS_OK(status)) {
767 return status;
770 return NT_STATUS_OK;
775 process a fragment received from the transport layer during a
776 request
778 This function frees the data
780 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
781 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
783 struct rpc_request *req;
784 unsigned int length;
785 NTSTATUS status = NT_STATUS_OK;
788 if this is an authenticated connection then parse and check
789 the auth info. We have to do this before finding the
790 matching packet, as the request structure might have been
791 removed due to a timeout, but if it has been we still need
792 to run the auth routines so that we don't get the sign/seal
793 info out of step with the server
795 if (c->security_state.auth_info && c->security_state.generic_state &&
796 pkt->ptype == DCERPC_PKT_RESPONSE) {
797 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
800 /* find the matching request */
801 for (req=c->pending;req;req=req->next) {
802 if (pkt->call_id == req->call_id) break;
805 #if 0
806 /* useful for testing certain vendors RPC servers */
807 if (req == NULL && c->pending && pkt->call_id == 0) {
808 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
809 req = c->pending;
811 #endif
813 if (req == NULL) {
814 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
815 data_blob_free(raw_packet);
816 return;
819 talloc_steal(req, raw_packet->data);
821 if (req->recv_handler != NULL) {
822 dcerpc_req_dequeue(req);
823 req->state = RPC_REQUEST_DONE;
824 req->recv_handler(req, raw_packet, pkt);
825 return;
828 if (pkt->ptype == DCERPC_PKT_FAULT) {
829 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
830 req->fault_code = pkt->u.fault.status;
831 req->status = NT_STATUS_NET_WRITE_FAULT;
832 goto req_done;
835 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
836 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
837 (int)pkt->ptype));
838 req->fault_code = DCERPC_FAULT_OTHER;
839 req->status = NT_STATUS_NET_WRITE_FAULT;
840 goto req_done;
843 /* now check the status from the auth routines, and if it failed then fail
844 this request accordingly */
845 if (!NT_STATUS_IS_OK(status)) {
846 req->status = status;
847 goto req_done;
850 length = pkt->u.response.stub_and_verifier.length;
852 if (length > 0) {
853 req->payload.data = talloc_realloc(req,
854 req->payload.data,
855 uint8_t,
856 req->payload.length + length);
857 if (!req->payload.data) {
858 req->status = NT_STATUS_NO_MEMORY;
859 goto req_done;
861 memcpy(req->payload.data+req->payload.length,
862 pkt->u.response.stub_and_verifier.data, length);
863 req->payload.length += length;
866 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
867 c->transport.send_read(c);
868 return;
871 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
872 req->flags |= DCERPC_PULL_BIGENDIAN;
873 } else {
874 req->flags &= ~DCERPC_PULL_BIGENDIAN;
878 req_done:
879 /* we've got the full payload */
880 req->state = RPC_REQUEST_DONE;
881 DLIST_REMOVE(c->pending, req);
883 if (c->request_queue != NULL) {
884 /* We have to look at shipping further requests before calling
885 * the async function, that one might close the pipe */
886 dcerpc_ship_next_request(c);
889 if (req->async.callback) {
890 req->async.callback(req);
895 perform the send side of a async dcerpc request
897 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
898 const struct GUID *object,
899 uint16_t opnum,
900 bool async,
901 DATA_BLOB *stub_data)
903 struct rpc_request *req;
905 p->conn->transport.recv_data = dcerpc_recv_data;
907 req = talloc(p, struct rpc_request);
908 if (req == NULL) {
909 return NULL;
912 req->p = p;
913 req->call_id = next_call_id(p->conn);
914 req->status = NT_STATUS_OK;
915 req->state = RPC_REQUEST_QUEUED;
916 req->payload = data_blob(NULL, 0);
917 req->flags = 0;
918 req->fault_code = 0;
919 req->async_call = async;
920 req->ignore_timeout = false;
921 req->async.callback = NULL;
922 req->async.private_data = NULL;
923 req->recv_handler = NULL;
925 if (object != NULL) {
926 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
927 if (req->object == NULL) {
928 talloc_free(req);
929 return NULL;
931 } else {
932 req->object = NULL;
935 req->opnum = opnum;
936 req->request_data.length = stub_data->length;
937 req->request_data.data = talloc_reference(req, stub_data->data);
938 if (req->request_data.length && req->request_data.data == NULL) {
939 return NULL;
942 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
943 talloc_set_destructor(req, dcerpc_req_dequeue);
945 dcerpc_ship_next_request(p->conn);
947 if (p->request_timeout) {
948 event_add_timed(dcerpc_event_context(p), req,
949 timeval_current_ofs(p->request_timeout, 0),
950 dcerpc_timeout_handler, req);
953 return req;
957 Send a request using the transport
960 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
962 struct rpc_request *req;
963 struct dcerpc_pipe *p;
964 DATA_BLOB *stub_data;
965 struct ncacn_packet pkt;
966 DATA_BLOB blob;
967 uint32_t remaining, chunk_size;
968 bool first_packet = true;
969 size_t sig_size = 0;
971 req = c->request_queue;
972 if (req == NULL) {
973 return;
976 p = req->p;
977 stub_data = &req->request_data;
979 if (!req->async_call && (c->pending != NULL)) {
980 return;
983 DLIST_REMOVE(c->request_queue, req);
984 DLIST_ADD(c->pending, req);
985 req->state = RPC_REQUEST_PENDING;
987 init_ncacn_hdr(p->conn, &pkt);
989 remaining = stub_data->length;
991 /* we can write a full max_recv_frag size, minus the dcerpc
992 request header size */
993 chunk_size = p->conn->srv_max_recv_frag;
994 chunk_size -= DCERPC_REQUEST_LENGTH;
995 if (c->security_state.auth_info &&
996 c->security_state.generic_state) {
997 sig_size = gensec_sig_size(c->security_state.generic_state,
998 p->conn->srv_max_recv_frag);
999 if (sig_size) {
1000 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1001 chunk_size -= sig_size;
1004 chunk_size -= (chunk_size % 16);
1006 pkt.ptype = DCERPC_PKT_REQUEST;
1007 pkt.call_id = req->call_id;
1008 pkt.auth_length = 0;
1009 pkt.pfc_flags = 0;
1010 pkt.u.request.alloc_hint = remaining;
1011 pkt.u.request.context_id = p->context_id;
1012 pkt.u.request.opnum = req->opnum;
1014 if (req->object) {
1015 pkt.u.request.object.object = *req->object;
1016 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1017 chunk_size -= ndr_size_GUID(req->object,0);
1020 /* we send a series of pdus without waiting for a reply */
1021 while (remaining > 0 || first_packet) {
1022 uint32_t chunk = MIN(chunk_size, remaining);
1023 bool last_frag = false;
1024 bool do_trans = false;
1026 first_packet = false;
1027 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1029 if (remaining == stub_data->length) {
1030 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1032 if (chunk == remaining) {
1033 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1034 last_frag = true;
1037 pkt.u.request.stub_and_verifier.data = stub_data->data +
1038 (stub_data->length - remaining);
1039 pkt.u.request.stub_and_verifier.length = chunk;
1041 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1042 if (!NT_STATUS_IS_OK(req->status)) {
1043 req->state = RPC_REQUEST_DONE;
1044 DLIST_REMOVE(p->conn->pending, req);
1045 return;
1048 if (last_frag && !req->async_call) {
1049 do_trans = true;
1052 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1053 if (!NT_STATUS_IS_OK(req->status)) {
1054 req->state = RPC_REQUEST_DONE;
1055 DLIST_REMOVE(p->conn->pending, req);
1056 return;
1059 if (last_frag && !do_trans) {
1060 req->status = p->conn->transport.send_read(p->conn);
1061 if (!NT_STATUS_IS_OK(req->status)) {
1062 req->state = RPC_REQUEST_DONE;
1063 DLIST_REMOVE(p->conn->pending, req);
1064 return;
1068 remaining -= chunk;
1073 return the event context for a dcerpc pipe
1074 used by callers who wish to operate asynchronously
1076 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1078 return p->conn->event_ctx;
1084 perform the receive side of a async dcerpc request
1086 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1087 TALLOC_CTX *mem_ctx,
1088 DATA_BLOB *stub_data)
1090 NTSTATUS status;
1092 while (req->state != RPC_REQUEST_DONE) {
1093 struct tevent_context *ctx = dcerpc_event_context(req->p);
1094 if (event_loop_once(ctx) != 0) {
1095 return NT_STATUS_CONNECTION_DISCONNECTED;
1098 *stub_data = req->payload;
1099 status = req->status;
1100 if (stub_data->data) {
1101 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1103 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1104 req->p->last_fault_code = req->fault_code;
1106 talloc_unlink(talloc_parent(req), req);
1107 return status;
1111 perform a full request/response pair on a dcerpc pipe
1113 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1114 struct GUID *object,
1115 uint16_t opnum,
1116 TALLOC_CTX *mem_ctx,
1117 DATA_BLOB *stub_data_in,
1118 DATA_BLOB *stub_data_out)
1120 struct rpc_request *req;
1122 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1123 if (req == NULL) {
1124 return NT_STATUS_NO_MEMORY;
1127 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1132 this is a paranoid NDR validator. For every packet we push onto the wire
1133 we pull it back again, then push it again. Then we compare the raw NDR data
1134 for that to the NDR we initially generated. If they don't match then we know
1135 we must have a bug in either the pull or push side of our code
1137 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1138 TALLOC_CTX *mem_ctx,
1139 DATA_BLOB blob,
1140 size_t struct_size,
1141 ndr_push_flags_fn_t ndr_push,
1142 ndr_pull_flags_fn_t ndr_pull)
1144 void *st;
1145 struct ndr_pull *pull;
1146 struct ndr_push *push;
1147 DATA_BLOB blob2;
1148 enum ndr_err_code ndr_err;
1150 st = talloc_size(mem_ctx, struct_size);
1151 if (!st) {
1152 return NT_STATUS_NO_MEMORY;
1155 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1156 if (!pull) {
1157 return NT_STATUS_NO_MEMORY;
1159 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1161 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1162 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1165 if (c->flags & DCERPC_NDR64) {
1166 pull->flags |= LIBNDR_FLAG_NDR64;
1169 ndr_err = ndr_pull(pull, NDR_IN, st);
1170 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1171 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1172 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1173 "failed input validation pull - %s",
1174 nt_errstr(status));
1175 return ndr_map_error2ntstatus(ndr_err);
1178 push = ndr_push_init_ctx(mem_ctx);
1179 if (!push) {
1180 return NT_STATUS_NO_MEMORY;
1183 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
1184 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1187 if (c->flags & DCERPC_NDR64) {
1188 push->flags |= LIBNDR_FLAG_NDR64;
1191 ndr_err = ndr_push(push, NDR_IN, st);
1192 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1193 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1194 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1195 "failed input validation push - %s",
1196 nt_errstr(status));
1197 return ndr_map_error2ntstatus(ndr_err);
1200 blob2 = ndr_push_blob(push);
1202 if (data_blob_cmp(&blob, &blob2) != 0) {
1203 DEBUG(3,("original:\n"));
1204 dump_data(3, blob.data, blob.length);
1205 DEBUG(3,("secondary:\n"));
1206 dump_data(3, blob2.data, blob2.length);
1207 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1208 "failed input validation blobs doesn't match");
1209 return ndr_map_error2ntstatus(ndr_err);
1212 return NT_STATUS_OK;
1216 this is a paranoid NDR input validator. For every packet we pull
1217 from the wire we push it back again then pull and push it
1218 again. Then we compare the raw NDR data for that to the NDR we
1219 initially generated. If they don't match then we know we must have a
1220 bug in either the pull or push side of our code
1222 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1223 struct ndr_pull *pull_in,
1224 void *struct_ptr,
1225 size_t struct_size,
1226 ndr_push_flags_fn_t ndr_push,
1227 ndr_pull_flags_fn_t ndr_pull,
1228 ndr_print_function_t ndr_print)
1230 void *st;
1231 struct ndr_pull *pull;
1232 struct ndr_push *push;
1233 DATA_BLOB blob, blob2;
1234 TALLOC_CTX *mem_ctx = pull_in;
1235 char *s1, *s2;
1236 enum ndr_err_code ndr_err;
1238 st = talloc_size(mem_ctx, struct_size);
1239 if (!st) {
1240 return NT_STATUS_NO_MEMORY;
1242 memcpy(st, struct_ptr, struct_size);
1244 push = ndr_push_init_ctx(mem_ctx);
1245 if (!push) {
1246 return NT_STATUS_NO_MEMORY;
1249 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1250 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1251 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1252 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1253 "failed output validation push - %s",
1254 nt_errstr(status));
1255 return ndr_map_error2ntstatus(ndr_err);
1258 blob = ndr_push_blob(push);
1260 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1261 if (!pull) {
1262 return NT_STATUS_NO_MEMORY;
1265 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1266 ndr_err = ndr_pull(pull, NDR_OUT, st);
1267 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1268 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1269 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1270 "failed output validation pull - %s",
1271 nt_errstr(status));
1272 return ndr_map_error2ntstatus(ndr_err);
1275 push = ndr_push_init_ctx(mem_ctx);
1276 if (!push) {
1277 return NT_STATUS_NO_MEMORY;
1280 ndr_err = ndr_push(push, NDR_OUT, st);
1281 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1282 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1283 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1284 "failed output validation push2 - %s",
1285 nt_errstr(status));
1286 return ndr_map_error2ntstatus(ndr_err);
1289 blob2 = ndr_push_blob(push);
1291 if (data_blob_cmp(&blob, &blob2) != 0) {
1292 DEBUG(3,("original:\n"));
1293 dump_data(3, blob.data, blob.length);
1294 DEBUG(3,("secondary:\n"));
1295 dump_data(3, blob2.data, blob2.length);
1296 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1297 "failed output validation blobs doesn't match");
1298 return ndr_map_error2ntstatus(ndr_err);
1301 /* this checks the printed forms of the two structures, which effectively
1302 tests all of the value() attributes */
1303 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1304 NDR_OUT, struct_ptr);
1305 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1306 NDR_OUT, st);
1307 if (strcmp(s1, s2) != 0) {
1308 #if 1
1309 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1310 #else
1311 /* this is sometimes useful */
1312 printf("VALIDATE ERROR\n");
1313 file_save("wire.dat", s1, strlen(s1));
1314 file_save("gen.dat", s2, strlen(s2));
1315 system("diff -u wire.dat gen.dat");
1316 #endif
1317 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1318 "failed output validation strings doesn't match");
1319 return ndr_map_error2ntstatus(ndr_err);
1322 return NT_STATUS_OK;
1327 send a rpc request given a dcerpc_call structure
1329 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1330 const struct GUID *object,
1331 const struct ndr_interface_table *table,
1332 uint32_t opnum,
1333 bool async,
1334 TALLOC_CTX *mem_ctx,
1335 void *r)
1337 const struct ndr_interface_call *call;
1338 struct ndr_push *push;
1339 NTSTATUS status;
1340 DATA_BLOB request;
1341 struct rpc_request *req;
1342 enum ndr_err_code ndr_err;
1344 call = &table->calls[opnum];
1346 /* setup for a ndr_push_* call */
1347 push = ndr_push_init_ctx(mem_ctx);
1348 if (!push) {
1349 return NULL;
1352 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1353 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1356 if (p->conn->flags & DCERPC_NDR64) {
1357 push->flags |= LIBNDR_FLAG_NDR64;
1360 /* push the structure into a blob */
1361 ndr_err = call->ndr_push(push, NDR_IN, r);
1362 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1363 status = ndr_map_error2ntstatus(ndr_err);
1364 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1365 nt_errstr(status)));
1366 talloc_free(push);
1367 return NULL;
1370 /* retrieve the blob */
1371 request = ndr_push_blob(push);
1373 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1374 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1375 call->ndr_push, call->ndr_pull);
1376 if (!NT_STATUS_IS_OK(status)) {
1377 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1378 nt_errstr(status)));
1379 talloc_free(push);
1380 return NULL;
1384 DEBUG(10,("rpc request data:\n"));
1385 dump_data(10, request.data, request.length);
1387 /* make the actual dcerpc request */
1388 req = dcerpc_request_send(p, object, opnum, async, &request);
1390 if (req != NULL) {
1391 req->ndr.table = table;
1392 req->ndr.opnum = opnum;
1393 req->ndr.struct_ptr = r;
1394 req->ndr.mem_ctx = mem_ctx;
1397 talloc_free(push);
1399 return req;
1403 receive the answer from a dcerpc_ndr_request_send()
1405 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1407 struct dcerpc_pipe *p = req->p;
1408 NTSTATUS status;
1409 DATA_BLOB response;
1410 struct ndr_pull *pull;
1411 unsigned int flags;
1412 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1413 void *r = req->ndr.struct_ptr;
1414 uint32_t opnum = req->ndr.opnum;
1415 const struct ndr_interface_table *table = req->ndr.table;
1416 const struct ndr_interface_call *call = &table->calls[opnum];
1417 enum ndr_err_code ndr_err;
1419 /* make sure the recv code doesn't free the request, as we
1420 need to grab the flags element before it is freed */
1421 if (talloc_reference(p, req) == NULL) {
1422 return NT_STATUS_NO_MEMORY;
1425 status = dcerpc_request_recv(req, mem_ctx, &response);
1426 if (!NT_STATUS_IS_OK(status)) {
1427 talloc_unlink(p, req);
1428 return status;
1431 flags = req->flags;
1433 /* prepare for ndr_pull_* */
1434 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1435 if (!pull) {
1436 talloc_unlink(p, req);
1437 return NT_STATUS_NO_MEMORY;
1440 if (pull->data) {
1441 pull->data = talloc_steal(pull, pull->data);
1443 talloc_unlink(p, req);
1445 if (flags & DCERPC_PULL_BIGENDIAN) {
1446 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1449 DEBUG(10,("rpc reply data:\n"));
1450 dump_data(10, pull->data, pull->data_size);
1452 /* pull the structure from the blob */
1453 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1454 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1455 status = ndr_map_error2ntstatus(ndr_err);
1456 dcerpc_log_packet(p->conn->packet_log_dir,
1457 table, opnum, NDR_OUT,
1458 &response);
1459 return status;
1462 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1463 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1464 call->ndr_push, call->ndr_pull,
1465 call->ndr_print);
1466 if (!NT_STATUS_IS_OK(status)) {
1467 dcerpc_log_packet(p->conn->packet_log_dir,
1468 table, opnum, NDR_OUT,
1469 &response);
1470 return status;
1474 if (pull->offset != pull->data_size) {
1475 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1476 pull->data_size - pull->offset));
1477 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1478 but it turns out that early versions of NT
1479 (specifically NT3.1) add junk onto the end of rpc
1480 packets, so if we want to interoperate at all with
1481 those versions then we need to ignore this error */
1484 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1486 return NT_STATUS_OK;
1491 a useful helper function for synchronous rpc requests
1493 this can be used when you have ndr push/pull functions in the
1494 standard format
1496 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1497 const struct GUID *object,
1498 const struct ndr_interface_table *table,
1499 uint32_t opnum,
1500 TALLOC_CTX *mem_ctx,
1501 void *r)
1503 struct rpc_request *req;
1505 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1506 if (req == NULL) {
1507 return NT_STATUS_NO_MEMORY;
1510 return dcerpc_ndr_request_recv(req);
1515 a useful function for retrieving the server name we connected to
1517 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1519 if (!p->conn->transport.target_hostname) {
1520 if (!p->conn->transport.peer_name) {
1521 return "";
1523 return p->conn->transport.peer_name(p->conn);
1525 return p->conn->transport.target_hostname(p->conn);
1530 get the dcerpc auth_level for a open connection
1532 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1534 uint8_t auth_level;
1536 if (c->flags & DCERPC_SEAL) {
1537 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1538 } else if (c->flags & DCERPC_SIGN) {
1539 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1540 } else if (c->flags & DCERPC_CONNECT) {
1541 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1542 } else {
1543 auth_level = DCERPC_AUTH_LEVEL_NONE;
1545 return auth_level;
1549 Receive an alter reply from the transport
1551 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1552 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1554 struct composite_context *c;
1555 struct dcerpc_pipe *recv_pipe;
1557 c = talloc_get_type(req->async.private_data, struct composite_context);
1558 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1560 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1561 pkt->u.alter_resp.num_results == 1 &&
1562 pkt->u.alter_resp.ctx_list[0].result != 0) {
1563 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1564 pkt->u.alter_resp.ctx_list[0].reason));
1565 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1566 return;
1569 if (pkt->ptype == DCERPC_PKT_FAULT) {
1570 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
1571 recv_pipe->last_fault_code = pkt->u.fault.status;
1572 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1573 return;
1576 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1577 pkt->u.alter_resp.num_results == 0 ||
1578 pkt->u.alter_resp.ctx_list[0].result != 0) {
1579 recv_pipe->last_fault_code = DCERPC_NCA_S_PROTO_ERROR;
1580 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1581 return;
1584 /* the alter_resp might contain a reply set of credentials */
1585 if (recv_pipe->conn->security_state.auth_info &&
1586 pkt->u.alter_resp.auth_info.length) {
1587 struct dcerpc_connection *conn = recv_pipe->conn;
1588 NTSTATUS status;
1589 uint32_t auth_length;
1590 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1591 conn->security_state.auth_info, &auth_length, true);
1592 if (!NT_STATUS_IS_OK(status)) {
1593 composite_error(c, status);
1594 return;
1598 composite_done(c);
1602 send a dcerpc alter_context request
1604 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1605 TALLOC_CTX *mem_ctx,
1606 const struct ndr_syntax_id *syntax,
1607 const struct ndr_syntax_id *transfer_syntax)
1609 struct composite_context *c;
1610 struct ncacn_packet pkt;
1611 DATA_BLOB blob;
1612 struct rpc_request *req;
1614 c = composite_create(mem_ctx, p->conn->event_ctx);
1615 if (c == NULL) return NULL;
1617 c->private_data = p;
1619 p->syntax = *syntax;
1620 p->transfer_syntax = *transfer_syntax;
1622 init_ncacn_hdr(p->conn, &pkt);
1624 pkt.ptype = DCERPC_PKT_ALTER;
1625 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1626 pkt.call_id = p->conn->call_id;
1627 pkt.auth_length = 0;
1629 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1630 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1633 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1634 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1637 pkt.u.alter.max_xmit_frag = 5840;
1638 pkt.u.alter.max_recv_frag = 5840;
1639 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1640 pkt.u.alter.num_contexts = 1;
1641 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1642 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1643 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1644 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1645 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1646 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1647 pkt.u.alter.auth_info = data_blob(NULL, 0);
1649 /* construct the NDR form of the packet */
1650 c->status = ncacn_push_auth(&blob, mem_ctx, &pkt,
1651 p->conn->security_state.auth_info);
1652 if (!composite_is_ok(c)) return c;
1654 p->conn->transport.recv_data = dcerpc_recv_data;
1657 * we allocate a dcerpc_request so we can be in the same
1658 * request queue as normal requests
1660 req = talloc_zero(c, struct rpc_request);
1661 if (composite_nomem(req, c)) return c;
1663 req->state = RPC_REQUEST_PENDING;
1664 req->call_id = pkt.call_id;
1665 req->async.private_data = c;
1666 req->async.callback = dcerpc_composite_fail;
1667 req->p = p;
1668 req->recv_handler = dcerpc_alter_recv_handler;
1669 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1670 talloc_set_destructor(req, dcerpc_req_dequeue);
1672 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1673 if (!composite_is_ok(c)) return c;
1675 event_add_timed(c->event_ctx, req,
1676 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1677 dcerpc_timeout_handler, req);
1679 return c;
1682 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1684 NTSTATUS result = composite_wait(ctx);
1685 talloc_free(ctx);
1686 return result;
1690 send a dcerpc alter_context request
1692 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1693 TALLOC_CTX *mem_ctx,
1694 const struct ndr_syntax_id *syntax,
1695 const struct ndr_syntax_id *transfer_syntax)
1697 struct composite_context *creq;
1698 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1699 return dcerpc_alter_context_recv(creq);