Fetch the SID of the user we are running as and send with the common
[Samba/nascimento.git] / source4 / librpc / rpc / dcerpc.c
blob064159f3547925e8edb94d1fe7944a0110821579
1 /*
2 Unix SMB/CIFS implementation.
3 raw dcerpc operations
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003-2005
7 Copyright (C) Jelmer Vernooij 2004-2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "../lib/util/dlinklist.h"
25 #include "lib/events/events.h"
26 #include "librpc/rpc/dcerpc.h"
27 #include "librpc/rpc/dcerpc_proto.h"
28 #include "librpc/gen_ndr/ndr_misc.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "libcli/composite/composite.h"
31 #include "auth/gensec/gensec.h"
32 #include "param/param.h"
34 _PUBLIC_ NTSTATUS dcerpc_init(struct loadparm_context *lp_ctx)
36 return gensec_init(lp_ctx);
39 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status);
40 static void dcerpc_ship_next_request(struct dcerpc_connection *c);
42 /* destroy a dcerpc connection */
43 static int dcerpc_connection_destructor(struct dcerpc_connection *conn)
45 if (conn->dead) {
46 conn->free_skipped = true;
47 return -1;
49 dcerpc_connection_dead(conn, NT_STATUS_LOCAL_DISCONNECT);
50 return 0;
54 /* initialise a dcerpc connection.
55 the event context is optional
57 static struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx,
58 struct tevent_context *ev,
59 struct smb_iconv_convenience *ic)
61 struct dcerpc_connection *c;
63 c = talloc_zero(mem_ctx, struct dcerpc_connection);
64 if (!c) {
65 return NULL;
68 c->iconv_convenience = talloc_reference(c, ic);
70 c->event_ctx = ev;
72 if (c->event_ctx == NULL) {
73 talloc_free(c);
74 return NULL;
77 c->call_id = 1;
78 c->security_state.auth_info = NULL;
79 c->security_state.session_key = dcerpc_generic_session_key;
80 c->security_state.generic_state = NULL;
81 c->binding_string = NULL;
82 c->flags = 0;
83 c->srv_max_xmit_frag = 0;
84 c->srv_max_recv_frag = 0;
85 c->pending = NULL;
87 talloc_set_destructor(c, dcerpc_connection_destructor);
89 return c;
92 /* initialise a dcerpc pipe. */
93 _PUBLIC_ struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
94 struct smb_iconv_convenience *ic)
96 struct dcerpc_pipe *p;
98 p = talloc(mem_ctx, struct dcerpc_pipe);
99 if (!p) {
100 return NULL;
103 p->conn = dcerpc_connection_init(p, ev, ic);
104 if (p->conn == NULL) {
105 talloc_free(p);
106 return NULL;
109 p->last_fault_code = 0;
110 p->context_id = 0;
111 p->request_timeout = DCERPC_REQUEST_TIMEOUT;
112 p->binding = NULL;
114 ZERO_STRUCT(p->syntax);
115 ZERO_STRUCT(p->transfer_syntax);
117 if (DEBUGLVL(100)) {
118 p->conn->flags |= DCERPC_DEBUG_PRINT_BOTH;
121 p->binding_handle = talloc(p, struct dcerpc_binding_handle);
122 if (p->binding_handle == NULL) {
123 talloc_free(p);
124 return NULL;
126 p->binding_handle->private_data = p;
128 return p;
133 choose the next call id to use
135 static uint32_t next_call_id(struct dcerpc_connection *c)
137 c->call_id++;
138 if (c->call_id == 0) {
139 c->call_id++;
141 return c->call_id;
144 /* we need to be able to get/set the fragment length without doing a full
145 decode */
146 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
148 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
149 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
150 } else {
151 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
155 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
157 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
158 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
159 } else {
160 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
164 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
166 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
167 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
168 } else {
169 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
175 setup for a ndr pull, also setting up any flags from the binding string
177 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
178 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
180 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx, c->iconv_convenience);
182 if (ndr == NULL) return ndr;
184 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
185 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
188 if (c->flags & DCERPC_NDR_REF_ALLOC) {
189 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
192 if (c->flags & DCERPC_NDR64) {
193 ndr->flags |= LIBNDR_FLAG_NDR64;
196 return ndr;
200 parse a data blob into a ncacn_packet structure. This handles both
201 input and output packets
203 static NTSTATUS ncacn_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
204 struct ncacn_packet *pkt)
206 struct ndr_pull *ndr;
207 enum ndr_err_code ndr_err;
209 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
210 if (!ndr) {
211 return NT_STATUS_NO_MEMORY;
214 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
215 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
218 ndr_err = ndr_pull_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
219 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
220 return ndr_map_error2ntstatus(ndr_err);
223 return NT_STATUS_OK;
227 parse the authentication information on a dcerpc response packet
229 static NTSTATUS ncacn_pull_request_auth(struct dcerpc_connection *c, TALLOC_CTX *mem_ctx,
230 DATA_BLOB *raw_packet,
231 struct ncacn_packet *pkt)
233 NTSTATUS status;
234 struct dcerpc_auth auth;
235 uint32_t auth_length;
237 if (!c->security_state.auth_info ||
238 !c->security_state.generic_state) {
239 return NT_STATUS_OK;
242 switch (c->security_state.auth_info->auth_level) {
243 case DCERPC_AUTH_LEVEL_PRIVACY:
244 case DCERPC_AUTH_LEVEL_INTEGRITY:
245 break;
247 case DCERPC_AUTH_LEVEL_CONNECT:
248 if (pkt->auth_length != 0) {
249 break;
251 return NT_STATUS_OK;
252 case DCERPC_AUTH_LEVEL_NONE:
253 if (pkt->auth_length != 0) {
254 return NT_STATUS_INVALID_NETWORK_RESPONSE;
256 return NT_STATUS_OK;
258 default:
259 return NT_STATUS_INVALID_LEVEL;
262 status = dcerpc_pull_auth_trailer(pkt, mem_ctx,
263 &pkt->u.response.stub_and_verifier,
264 &auth, &auth_length, false);
265 NT_STATUS_NOT_OK_RETURN(status);
267 pkt->u.response.stub_and_verifier.length -= auth_length;
269 /* check signature or unseal the packet */
270 switch (c->security_state.auth_info->auth_level) {
271 case DCERPC_AUTH_LEVEL_PRIVACY:
272 status = gensec_unseal_packet(c->security_state.generic_state,
273 mem_ctx,
274 raw_packet->data + DCERPC_REQUEST_LENGTH,
275 pkt->u.response.stub_and_verifier.length,
276 raw_packet->data,
277 raw_packet->length - auth.credentials.length,
278 &auth.credentials);
279 memcpy(pkt->u.response.stub_and_verifier.data,
280 raw_packet->data + DCERPC_REQUEST_LENGTH,
281 pkt->u.response.stub_and_verifier.length);
282 break;
284 case DCERPC_AUTH_LEVEL_INTEGRITY:
285 status = gensec_check_packet(c->security_state.generic_state,
286 mem_ctx,
287 pkt->u.response.stub_and_verifier.data,
288 pkt->u.response.stub_and_verifier.length,
289 raw_packet->data,
290 raw_packet->length - auth.credentials.length,
291 &auth.credentials);
292 break;
294 case DCERPC_AUTH_LEVEL_CONNECT:
295 /* for now we ignore possible signatures here */
296 status = NT_STATUS_OK;
297 break;
299 default:
300 status = NT_STATUS_INVALID_LEVEL;
301 break;
304 /* remove the indicated amount of padding */
305 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
306 return NT_STATUS_INFO_LENGTH_MISMATCH;
308 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
310 return status;
315 push a dcerpc request packet into a blob, possibly signing it.
317 static NTSTATUS ncacn_push_request_sign(struct dcerpc_connection *c,
318 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
319 size_t sig_size,
320 struct ncacn_packet *pkt)
322 NTSTATUS status;
323 struct ndr_push *ndr;
324 DATA_BLOB creds2;
325 size_t payload_length;
326 enum ndr_err_code ndr_err;
327 size_t hdr_size = DCERPC_REQUEST_LENGTH;
329 /* non-signed packets are simpler */
330 if (sig_size == 0) {
331 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
334 switch (c->security_state.auth_info->auth_level) {
335 case DCERPC_AUTH_LEVEL_PRIVACY:
336 case DCERPC_AUTH_LEVEL_INTEGRITY:
337 break;
339 case DCERPC_AUTH_LEVEL_CONNECT:
340 /* TODO: let the gensec mech decide if it wants to generate a signature */
341 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
343 case DCERPC_AUTH_LEVEL_NONE:
344 return ncacn_push_auth(blob, mem_ctx, c->iconv_convenience, pkt, NULL);
346 default:
347 return NT_STATUS_INVALID_LEVEL;
350 ndr = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
351 if (!ndr) {
352 return NT_STATUS_NO_MEMORY;
355 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
356 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
359 if (c->flags & DCERPC_NDR64) {
360 ndr->flags |= LIBNDR_FLAG_NDR64;
363 if (pkt->pfc_flags & DCERPC_PFC_FLAG_OBJECT_UUID) {
364 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
365 hdr_size += 16;
368 ndr_err = ndr_push_ncacn_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
369 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
370 return ndr_map_error2ntstatus(ndr_err);
373 /* pad to 16 byte multiple in the payload portion of the
374 packet. This matches what w2k3 does. Note that we can't use
375 ndr_push_align() as that is relative to the start of the
376 whole packet, whereas w2k8 wants it relative to the start
377 of the stub */
378 c->security_state.auth_info->auth_pad_length =
379 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
380 ndr_err = ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
381 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
382 return ndr_map_error2ntstatus(ndr_err);
385 payload_length = pkt->u.request.stub_and_verifier.length +
386 c->security_state.auth_info->auth_pad_length;
388 /* we start without signature, it will appended later */
389 c->security_state.auth_info->credentials = data_blob(NULL,0);
391 /* add the auth verifier */
392 ndr_err = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
393 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
394 return ndr_map_error2ntstatus(ndr_err);
397 /* extract the whole packet as a blob */
398 *blob = ndr_push_blob(ndr);
401 * Setup the frag and auth length in the packet buffer.
402 * This is needed if the GENSEC mech does AEAD signing
403 * of the packet headers. The signature itself will be
404 * appended later.
406 dcerpc_set_frag_length(blob, blob->length + sig_size);
407 dcerpc_set_auth_length(blob, sig_size);
409 /* sign or seal the packet */
410 switch (c->security_state.auth_info->auth_level) {
411 case DCERPC_AUTH_LEVEL_PRIVACY:
412 status = gensec_seal_packet(c->security_state.generic_state,
413 mem_ctx,
414 blob->data + hdr_size,
415 payload_length,
416 blob->data,
417 blob->length,
418 &creds2);
419 if (!NT_STATUS_IS_OK(status)) {
420 return status;
422 break;
424 case DCERPC_AUTH_LEVEL_INTEGRITY:
425 status = gensec_sign_packet(c->security_state.generic_state,
426 mem_ctx,
427 blob->data + hdr_size,
428 payload_length,
429 blob->data,
430 blob->length,
431 &creds2);
432 if (!NT_STATUS_IS_OK(status)) {
433 return status;
435 break;
437 default:
438 status = NT_STATUS_INVALID_LEVEL;
439 break;
442 if (creds2.length != sig_size) {
443 /* this means the sig_size estimate for the signature
444 was incorrect. We have to correct the packet
445 sizes. That means we could go over the max fragment
446 length */
447 DEBUG(3,("ncacn_push_request_sign: creds2.length[%u] != sig_size[%u] pad[%u] stub[%u]\n",
448 (unsigned) creds2.length,
449 (unsigned) sig_size,
450 (unsigned) c->security_state.auth_info->auth_pad_length,
451 (unsigned) pkt->u.request.stub_and_verifier.length));
452 dcerpc_set_frag_length(blob, blob->length + creds2.length);
453 dcerpc_set_auth_length(blob, creds2.length);
456 if (!data_blob_append(mem_ctx, blob, creds2.data, creds2.length)) {
457 return NT_STATUS_NO_MEMORY;
460 return NT_STATUS_OK;
465 fill in the fixed values in a dcerpc header
467 static void init_ncacn_hdr(struct dcerpc_connection *c, struct ncacn_packet *pkt)
469 pkt->rpc_vers = 5;
470 pkt->rpc_vers_minor = 0;
471 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
472 pkt->drep[0] = 0;
473 } else {
474 pkt->drep[0] = DCERPC_DREP_LE;
476 pkt->drep[1] = 0;
477 pkt->drep[2] = 0;
478 pkt->drep[3] = 0;
482 map a bind nak reason to a NTSTATUS
484 static NTSTATUS dcerpc_map_reason(uint16_t reason)
486 switch (reason) {
487 case DCERPC_BIND_REASON_ASYNTAX:
488 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
489 case DCERPC_BIND_REASON_INVALID_AUTH_TYPE:
490 return NT_STATUS_INVALID_PARAMETER;
492 return NT_STATUS_UNSUCCESSFUL;
496 a bind or alter context has failed
498 static void dcerpc_composite_fail(struct rpc_request *req)
500 struct composite_context *c = talloc_get_type(req->async.private_data,
501 struct composite_context);
502 composite_error(c, req->status);
506 remove requests from the pending or queued queues
508 static int dcerpc_req_dequeue(struct rpc_request *req)
510 switch (req->state) {
511 case RPC_REQUEST_QUEUED:
512 DLIST_REMOVE(req->p->conn->request_queue, req);
513 break;
514 case RPC_REQUEST_PENDING:
515 DLIST_REMOVE(req->p->conn->pending, req);
516 break;
517 case RPC_REQUEST_DONE:
518 break;
520 return 0;
525 mark the dcerpc connection dead. All outstanding requests get an error
527 static void dcerpc_connection_dead(struct dcerpc_connection *conn, NTSTATUS status)
529 if (conn->dead) return;
531 conn->dead = true;
533 if (conn->transport.shutdown_pipe) {
534 conn->transport.shutdown_pipe(conn, status);
537 /* all pending requests get the error */
538 while (conn->pending) {
539 struct rpc_request *req = conn->pending;
540 dcerpc_req_dequeue(req);
541 req->state = RPC_REQUEST_DONE;
542 req->status = status;
543 if (req->async.callback) {
544 req->async.callback(req);
548 talloc_set_destructor(conn, NULL);
549 if (conn->free_skipped) {
550 talloc_free(conn);
555 forward declarations of the recv_data handlers for the types of
556 packets we need to handle
558 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
559 DATA_BLOB *raw_packet, struct ncacn_packet *pkt);
562 receive a dcerpc reply from the transport. Here we work out what
563 type of reply it is (normal request, bind or alter context) and
564 dispatch to the appropriate handler
566 static void dcerpc_recv_data(struct dcerpc_connection *conn, DATA_BLOB *blob, NTSTATUS status)
568 struct ncacn_packet pkt;
570 if (NT_STATUS_IS_OK(status) && blob->length == 0) {
571 status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
574 /* the transport may be telling us of a severe error, such as
575 a dropped socket */
576 if (!NT_STATUS_IS_OK(status)) {
577 data_blob_free(blob);
578 dcerpc_connection_dead(conn, status);
579 return;
582 /* parse the basic packet to work out what type of response this is */
583 status = ncacn_pull(conn, blob, blob->data, &pkt);
584 if (!NT_STATUS_IS_OK(status)) {
585 data_blob_free(blob);
586 dcerpc_connection_dead(conn, status);
589 dcerpc_request_recv_data(conn, blob, &pkt);
593 Receive a bind reply from the transport
595 static void dcerpc_bind_recv_handler(struct rpc_request *req,
596 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
598 struct composite_context *c;
599 struct dcerpc_connection *conn;
601 c = talloc_get_type(req->async.private_data, struct composite_context);
603 if (pkt->ptype == DCERPC_PKT_BIND_NAK) {
604 DEBUG(2,("dcerpc: bind_nak reason %d\n",
605 pkt->u.bind_nak.reject_reason));
606 composite_error(c, dcerpc_map_reason(pkt->u.bind_nak.
607 reject_reason));
608 return;
611 if ((pkt->ptype != DCERPC_PKT_BIND_ACK) ||
612 (pkt->u.bind_ack.num_results == 0) ||
613 (pkt->u.bind_ack.ctx_list[0].result != 0)) {
614 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
615 return;
618 conn = req->p->conn;
620 conn->srv_max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
621 conn->srv_max_recv_frag = pkt->u.bind_ack.max_recv_frag;
623 if ((req->p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) &&
624 (pkt->pfc_flags & DCERPC_PFC_FLAG_CONC_MPX)) {
625 conn->flags |= DCERPC_CONCURRENT_MULTIPLEX;
628 if ((req->p->binding->flags & DCERPC_HEADER_SIGNING) &&
629 (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN)) {
630 conn->flags |= DCERPC_HEADER_SIGNING;
633 /* the bind_ack might contain a reply set of credentials */
634 if (conn->security_state.auth_info && pkt->u.bind_ack.auth_info.length) {
635 NTSTATUS status;
636 uint32_t auth_length;
637 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.bind_ack.auth_info,
638 conn->security_state.auth_info, &auth_length, true);
639 if (!NT_STATUS_IS_OK(status)) {
640 composite_error(c, status);
641 return;
645 req->p->assoc_group_id = pkt->u.bind_ack.assoc_group_id;
647 composite_done(c);
651 handle timeouts of individual dcerpc requests
653 static void dcerpc_timeout_handler(struct tevent_context *ev, struct tevent_timer *te,
654 struct timeval t, void *private_data)
656 struct rpc_request *req = talloc_get_type(private_data, struct rpc_request);
658 if (req->ignore_timeout) {
659 dcerpc_req_dequeue(req);
660 req->state = RPC_REQUEST_DONE;
661 req->status = NT_STATUS_IO_TIMEOUT;
662 if (req->async.callback) {
663 req->async.callback(req);
665 return;
668 dcerpc_connection_dead(req->p->conn, NT_STATUS_IO_TIMEOUT);
672 send a async dcerpc bind request
674 struct composite_context *dcerpc_bind_send(struct dcerpc_pipe *p,
675 TALLOC_CTX *mem_ctx,
676 const struct ndr_syntax_id *syntax,
677 const struct ndr_syntax_id *transfer_syntax)
679 struct composite_context *c;
680 struct ncacn_packet pkt;
681 DATA_BLOB blob;
682 struct rpc_request *req;
684 c = composite_create(mem_ctx,p->conn->event_ctx);
685 if (c == NULL) return NULL;
687 c->private_data = p;
689 p->syntax = *syntax;
690 p->transfer_syntax = *transfer_syntax;
692 init_ncacn_hdr(p->conn, &pkt);
694 pkt.ptype = DCERPC_PKT_BIND;
695 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
696 pkt.call_id = p->conn->call_id;
697 pkt.auth_length = 0;
699 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
700 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
703 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
704 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
707 pkt.u.bind.max_xmit_frag = 5840;
708 pkt.u.bind.max_recv_frag = 5840;
709 pkt.u.bind.assoc_group_id = p->binding->assoc_group_id;
710 pkt.u.bind.num_contexts = 1;
711 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
712 if (composite_nomem(pkt.u.bind.ctx_list, c)) return c;
713 pkt.u.bind.ctx_list[0].context_id = p->context_id;
714 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
715 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
716 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
717 pkt.u.bind.auth_info = data_blob(NULL, 0);
719 /* construct the NDR form of the packet */
720 c->status = ncacn_push_auth(&blob, c, p->conn->iconv_convenience, &pkt,
721 p->conn->security_state.auth_info);
722 if (!composite_is_ok(c)) return c;
724 p->conn->transport.recv_data = dcerpc_recv_data;
727 * we allocate a dcerpc_request so we can be in the same
728 * request queue as normal requests
730 req = talloc_zero(c, struct rpc_request);
731 if (composite_nomem(req, c)) return c;
733 req->state = RPC_REQUEST_PENDING;
734 req->call_id = pkt.call_id;
735 req->async.private_data = c;
736 req->async.callback = dcerpc_composite_fail;
737 req->p = p;
738 req->recv_handler = dcerpc_bind_recv_handler;
739 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
740 talloc_set_destructor(req, dcerpc_req_dequeue);
742 c->status = p->conn->transport.send_request(p->conn, &blob,
743 true);
744 if (!composite_is_ok(c)) return c;
746 event_add_timed(c->event_ctx, req,
747 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
748 dcerpc_timeout_handler, req);
750 return c;
754 recv side of async dcerpc bind request
756 NTSTATUS dcerpc_bind_recv(struct composite_context *ctx)
758 NTSTATUS result = composite_wait(ctx);
759 talloc_free(ctx);
760 return result;
764 perform a continued bind (and auth3)
766 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
767 TALLOC_CTX *mem_ctx)
769 struct ncacn_packet pkt;
770 NTSTATUS status;
771 DATA_BLOB blob;
773 init_ncacn_hdr(p->conn, &pkt);
775 pkt.ptype = DCERPC_PKT_AUTH3;
776 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
777 pkt.call_id = next_call_id(p->conn);
778 pkt.auth_length = 0;
779 pkt.u.auth3.auth_info = data_blob(NULL, 0);
781 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
782 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
785 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
786 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
789 /* construct the NDR form of the packet */
790 status = ncacn_push_auth(&blob, mem_ctx,
791 p->conn->iconv_convenience,
792 &pkt,
793 p->conn->security_state.auth_info);
794 if (!NT_STATUS_IS_OK(status)) {
795 return status;
798 /* send it on its way */
799 status = p->conn->transport.send_request(p->conn, &blob, false);
800 if (!NT_STATUS_IS_OK(status)) {
801 return status;
804 return NT_STATUS_OK;
809 process a fragment received from the transport layer during a
810 request
812 This function frees the data
814 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
815 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
817 struct rpc_request *req;
818 unsigned int length;
819 NTSTATUS status = NT_STATUS_OK;
822 if this is an authenticated connection then parse and check
823 the auth info. We have to do this before finding the
824 matching packet, as the request structure might have been
825 removed due to a timeout, but if it has been we still need
826 to run the auth routines so that we don't get the sign/seal
827 info out of step with the server
829 if (c->security_state.auth_info && c->security_state.generic_state &&
830 pkt->ptype == DCERPC_PKT_RESPONSE) {
831 status = ncacn_pull_request_auth(c, raw_packet->data, raw_packet, pkt);
834 /* find the matching request */
835 for (req=c->pending;req;req=req->next) {
836 if (pkt->call_id == req->call_id) break;
839 #if 0
840 /* useful for testing certain vendors RPC servers */
841 if (req == NULL && c->pending && pkt->call_id == 0) {
842 DEBUG(0,("HACK FOR INCORRECT CALL ID\n"));
843 req = c->pending;
845 #endif
847 if (req == NULL) {
848 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt->call_id));
849 data_blob_free(raw_packet);
850 return;
853 talloc_steal(req, raw_packet->data);
855 if (req->recv_handler != NULL) {
856 dcerpc_req_dequeue(req);
857 req->state = RPC_REQUEST_DONE;
858 req->recv_handler(req, raw_packet, pkt);
859 return;
862 if (pkt->ptype == DCERPC_PKT_FAULT) {
863 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt->u.fault.status)));
864 req->fault_code = pkt->u.fault.status;
865 req->status = NT_STATUS_NET_WRITE_FAULT;
866 goto req_done;
869 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
870 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
871 (int)pkt->ptype));
872 req->fault_code = DCERPC_FAULT_OTHER;
873 req->status = NT_STATUS_NET_WRITE_FAULT;
874 goto req_done;
877 /* now check the status from the auth routines, and if it failed then fail
878 this request accordingly */
879 if (!NT_STATUS_IS_OK(status)) {
880 req->status = status;
881 goto req_done;
884 length = pkt->u.response.stub_and_verifier.length;
886 if (length > 0) {
887 req->payload.data = talloc_realloc(req,
888 req->payload.data,
889 uint8_t,
890 req->payload.length + length);
891 if (!req->payload.data) {
892 req->status = NT_STATUS_NO_MEMORY;
893 goto req_done;
895 memcpy(req->payload.data+req->payload.length,
896 pkt->u.response.stub_and_verifier.data, length);
897 req->payload.length += length;
900 if (!(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
901 c->transport.send_read(c);
902 return;
905 if (!(pkt->drep[0] & DCERPC_DREP_LE)) {
906 req->flags |= DCERPC_PULL_BIGENDIAN;
907 } else {
908 req->flags &= ~DCERPC_PULL_BIGENDIAN;
912 req_done:
913 /* we've got the full payload */
914 req->state = RPC_REQUEST_DONE;
915 DLIST_REMOVE(c->pending, req);
917 if (c->request_queue != NULL) {
918 /* We have to look at shipping further requests before calling
919 * the async function, that one might close the pipe */
920 dcerpc_ship_next_request(c);
923 if (req->async.callback) {
924 req->async.callback(req);
929 perform the send side of a async dcerpc request
931 static struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
932 const struct GUID *object,
933 uint16_t opnum,
934 bool async,
935 DATA_BLOB *stub_data)
937 struct rpc_request *req;
939 p->conn->transport.recv_data = dcerpc_recv_data;
941 req = talloc(p, struct rpc_request);
942 if (req == NULL) {
943 return NULL;
946 req->p = p;
947 req->call_id = next_call_id(p->conn);
948 req->status = NT_STATUS_OK;
949 req->state = RPC_REQUEST_QUEUED;
950 req->payload = data_blob(NULL, 0);
951 req->flags = 0;
952 req->fault_code = 0;
953 req->async_call = async;
954 req->ignore_timeout = false;
955 req->async.callback = NULL;
956 req->async.private_data = NULL;
957 req->recv_handler = NULL;
959 if (object != NULL) {
960 req->object = (struct GUID *)talloc_memdup(req, (const void *)object, sizeof(*object));
961 if (req->object == NULL) {
962 talloc_free(req);
963 return NULL;
965 } else {
966 req->object = NULL;
969 req->opnum = opnum;
970 req->request_data.length = stub_data->length;
971 req->request_data.data = talloc_reference(req, stub_data->data);
972 if (req->request_data.length && req->request_data.data == NULL) {
973 return NULL;
976 DLIST_ADD_END(p->conn->request_queue, req, struct rpc_request *);
977 talloc_set_destructor(req, dcerpc_req_dequeue);
979 dcerpc_ship_next_request(p->conn);
981 if (p->request_timeout) {
982 event_add_timed(dcerpc_event_context(p), req,
983 timeval_current_ofs(p->request_timeout, 0),
984 dcerpc_timeout_handler, req);
987 return req;
991 Send a request using the transport
994 static void dcerpc_ship_next_request(struct dcerpc_connection *c)
996 struct rpc_request *req;
997 struct dcerpc_pipe *p;
998 DATA_BLOB *stub_data;
999 struct ncacn_packet pkt;
1000 DATA_BLOB blob;
1001 uint32_t remaining, chunk_size;
1002 bool first_packet = true;
1003 size_t sig_size = 0;
1005 req = c->request_queue;
1006 if (req == NULL) {
1007 return;
1010 p = req->p;
1011 stub_data = &req->request_data;
1013 if (!req->async_call && (c->pending != NULL)) {
1014 return;
1017 DLIST_REMOVE(c->request_queue, req);
1018 DLIST_ADD(c->pending, req);
1019 req->state = RPC_REQUEST_PENDING;
1021 init_ncacn_hdr(p->conn, &pkt);
1023 remaining = stub_data->length;
1025 /* we can write a full max_recv_frag size, minus the dcerpc
1026 request header size */
1027 chunk_size = p->conn->srv_max_recv_frag;
1028 chunk_size -= DCERPC_REQUEST_LENGTH;
1029 if (c->security_state.auth_info &&
1030 c->security_state.generic_state) {
1031 sig_size = gensec_sig_size(c->security_state.generic_state,
1032 p->conn->srv_max_recv_frag);
1033 if (sig_size) {
1034 chunk_size -= DCERPC_AUTH_TRAILER_LENGTH;
1035 chunk_size -= sig_size;
1038 chunk_size -= (chunk_size % 16);
1040 pkt.ptype = DCERPC_PKT_REQUEST;
1041 pkt.call_id = req->call_id;
1042 pkt.auth_length = 0;
1043 pkt.pfc_flags = 0;
1044 pkt.u.request.alloc_hint = remaining;
1045 pkt.u.request.context_id = p->context_id;
1046 pkt.u.request.opnum = req->opnum;
1048 if (req->object) {
1049 pkt.u.request.object.object = *req->object;
1050 pkt.pfc_flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1051 chunk_size -= ndr_size_GUID(req->object,NULL,0);
1054 /* we send a series of pdus without waiting for a reply */
1055 while (remaining > 0 || first_packet) {
1056 uint32_t chunk = MIN(chunk_size, remaining);
1057 bool last_frag = false;
1058 bool do_trans = false;
1060 first_packet = false;
1061 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
1063 if (remaining == stub_data->length) {
1064 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
1066 if (chunk == remaining) {
1067 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
1068 last_frag = true;
1071 pkt.u.request.stub_and_verifier.data = stub_data->data +
1072 (stub_data->length - remaining);
1073 pkt.u.request.stub_and_verifier.length = chunk;
1075 req->status = ncacn_push_request_sign(p->conn, &blob, req, sig_size, &pkt);
1076 if (!NT_STATUS_IS_OK(req->status)) {
1077 req->state = RPC_REQUEST_DONE;
1078 DLIST_REMOVE(p->conn->pending, req);
1079 return;
1082 if (last_frag && !req->async_call) {
1083 do_trans = true;
1086 req->status = p->conn->transport.send_request(p->conn, &blob, do_trans);
1087 if (!NT_STATUS_IS_OK(req->status)) {
1088 req->state = RPC_REQUEST_DONE;
1089 DLIST_REMOVE(p->conn->pending, req);
1090 return;
1093 if (last_frag && !do_trans) {
1094 req->status = p->conn->transport.send_read(p->conn);
1095 if (!NT_STATUS_IS_OK(req->status)) {
1096 req->state = RPC_REQUEST_DONE;
1097 DLIST_REMOVE(p->conn->pending, req);
1098 return;
1102 remaining -= chunk;
1107 return the event context for a dcerpc pipe
1108 used by callers who wish to operate asynchronously
1110 _PUBLIC_ struct tevent_context *dcerpc_event_context(struct dcerpc_pipe *p)
1112 return p->conn->event_ctx;
1118 perform the receive side of a async dcerpc request
1120 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
1121 TALLOC_CTX *mem_ctx,
1122 DATA_BLOB *stub_data)
1124 NTSTATUS status;
1126 while (req->state != RPC_REQUEST_DONE) {
1127 struct tevent_context *ctx = dcerpc_event_context(req->p);
1128 if (event_loop_once(ctx) != 0) {
1129 return NT_STATUS_CONNECTION_DISCONNECTED;
1132 *stub_data = req->payload;
1133 status = req->status;
1134 if (stub_data->data) {
1135 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
1137 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
1138 req->p->last_fault_code = req->fault_code;
1140 talloc_unlink(talloc_parent(req), req);
1141 return status;
1145 perform a full request/response pair on a dcerpc pipe
1147 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1148 struct GUID *object,
1149 uint16_t opnum,
1150 TALLOC_CTX *mem_ctx,
1151 DATA_BLOB *stub_data_in,
1152 DATA_BLOB *stub_data_out)
1154 struct rpc_request *req;
1156 req = dcerpc_request_send(p, object, opnum, false, stub_data_in);
1157 if (req == NULL) {
1158 return NT_STATUS_NO_MEMORY;
1161 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1166 this is a paranoid NDR validator. For every packet we push onto the wire
1167 we pull it back again, then push it again. Then we compare the raw NDR data
1168 for that to the NDR we initially generated. If they don't match then we know
1169 we must have a bug in either the pull or push side of our code
1171 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1172 TALLOC_CTX *mem_ctx,
1173 DATA_BLOB blob,
1174 size_t struct_size,
1175 ndr_push_flags_fn_t ndr_push,
1176 ndr_pull_flags_fn_t ndr_pull)
1178 void *st;
1179 struct ndr_pull *pull;
1180 struct ndr_push *push;
1181 DATA_BLOB blob2;
1182 enum ndr_err_code ndr_err;
1184 st = talloc_size(mem_ctx, struct_size);
1185 if (!st) {
1186 return NT_STATUS_NO_MEMORY;
1189 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1190 if (!pull) {
1191 return NT_STATUS_NO_MEMORY;
1193 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1195 ndr_err = ndr_pull(pull, NDR_IN, st);
1196 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1197 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1198 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1199 "failed input validation pull - %s",
1200 nt_errstr(status));
1201 return ndr_map_error2ntstatus(ndr_err);
1204 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1205 if (!push) {
1206 return NT_STATUS_NO_MEMORY;
1209 ndr_err = ndr_push(push, NDR_IN, st);
1210 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1211 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1212 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1213 "failed input validation push - %s",
1214 nt_errstr(status));
1215 return ndr_map_error2ntstatus(ndr_err);
1218 blob2 = ndr_push_blob(push);
1220 if (data_blob_cmp(&blob, &blob2) != 0) {
1221 DEBUG(3,("original:\n"));
1222 dump_data(3, blob.data, blob.length);
1223 DEBUG(3,("secondary:\n"));
1224 dump_data(3, blob2.data, blob2.length);
1225 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1226 "failed input validation blobs doesn't match");
1227 return ndr_map_error2ntstatus(ndr_err);
1230 return NT_STATUS_OK;
1234 this is a paranoid NDR input validator. For every packet we pull
1235 from the wire we push it back again then pull and push it
1236 again. Then we compare the raw NDR data for that to the NDR we
1237 initially generated. If they don't match then we know we must have a
1238 bug in either the pull or push side of our code
1240 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1241 struct ndr_pull *pull_in,
1242 void *struct_ptr,
1243 size_t struct_size,
1244 ndr_push_flags_fn_t ndr_push,
1245 ndr_pull_flags_fn_t ndr_pull,
1246 ndr_print_function_t ndr_print)
1248 void *st;
1249 struct ndr_pull *pull;
1250 struct ndr_push *push;
1251 DATA_BLOB blob, blob2;
1252 TALLOC_CTX *mem_ctx = pull_in;
1253 char *s1, *s2;
1254 enum ndr_err_code ndr_err;
1256 st = talloc_size(mem_ctx, struct_size);
1257 if (!st) {
1258 return NT_STATUS_NO_MEMORY;
1260 memcpy(st, struct_ptr, struct_size);
1262 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1263 if (!push) {
1264 return NT_STATUS_NO_MEMORY;
1267 ndr_err = ndr_push(push, NDR_OUT, struct_ptr);
1268 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1269 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1270 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1271 "failed output validation push - %s",
1272 nt_errstr(status));
1273 return ndr_map_error2ntstatus(ndr_err);
1276 blob = ndr_push_blob(push);
1278 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1279 if (!pull) {
1280 return NT_STATUS_NO_MEMORY;
1283 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1284 ndr_err = ndr_pull(pull, NDR_OUT, st);
1285 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1286 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1287 ndr_err = ndr_pull_error(pull, NDR_ERR_VALIDATE,
1288 "failed output validation pull - %s",
1289 nt_errstr(status));
1290 return ndr_map_error2ntstatus(ndr_err);
1293 push = ndr_push_init_ctx(mem_ctx, c->iconv_convenience);
1294 if (!push) {
1295 return NT_STATUS_NO_MEMORY;
1298 ndr_err = ndr_push(push, NDR_OUT, st);
1299 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1300 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1301 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1302 "failed output validation push2 - %s",
1303 nt_errstr(status));
1304 return ndr_map_error2ntstatus(ndr_err);
1307 blob2 = ndr_push_blob(push);
1309 if (data_blob_cmp(&blob, &blob2) != 0) {
1310 DEBUG(3,("original:\n"));
1311 dump_data(3, blob.data, blob.length);
1312 DEBUG(3,("secondary:\n"));
1313 dump_data(3, blob2.data, blob2.length);
1314 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1315 "failed output validation blobs doesn't match");
1316 return ndr_map_error2ntstatus(ndr_err);
1319 /* this checks the printed forms of the two structures, which effectively
1320 tests all of the value() attributes */
1321 s1 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1322 NDR_OUT, struct_ptr);
1323 s2 = ndr_print_function_string(mem_ctx, ndr_print, "VALIDATE",
1324 NDR_OUT, st);
1325 if (strcmp(s1, s2) != 0) {
1326 #if 1
1327 DEBUG(3,("VALIDATE ERROR:\nWIRE:\n%s\n GEN:\n%s\n", s1, s2));
1328 #else
1329 /* this is sometimes useful */
1330 printf("VALIDATE ERROR\n");
1331 file_save("wire.dat", s1, strlen(s1));
1332 file_save("gen.dat", s2, strlen(s2));
1333 system("diff -u wire.dat gen.dat");
1334 #endif
1335 ndr_err = ndr_push_error(push, NDR_ERR_VALIDATE,
1336 "failed output validation strings doesn't match");
1337 return ndr_map_error2ntstatus(ndr_err);
1340 return NT_STATUS_OK;
1345 send a rpc request given a dcerpc_call structure
1347 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1348 const struct GUID *object,
1349 const struct ndr_interface_table *table,
1350 uint32_t opnum,
1351 bool async,
1352 TALLOC_CTX *mem_ctx,
1353 void *r)
1355 const struct ndr_interface_call *call;
1356 struct ndr_push *push;
1357 NTSTATUS status;
1358 DATA_BLOB request;
1359 struct rpc_request *req;
1360 enum ndr_err_code ndr_err;
1362 call = &table->calls[opnum];
1364 /* setup for a ndr_push_* call */
1365 push = ndr_push_init_ctx(mem_ctx, p->conn->iconv_convenience);
1366 if (!push) {
1367 return NULL;
1370 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1371 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1374 if (p->conn->flags & DCERPC_NDR64) {
1375 push->flags |= LIBNDR_FLAG_NDR64;
1378 /* push the structure into a blob */
1379 ndr_err = call->ndr_push(push, NDR_IN, r);
1380 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1381 status = ndr_map_error2ntstatus(ndr_err);
1382 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1383 nt_errstr(status)));
1384 talloc_free(push);
1385 return NULL;
1388 /* retrieve the blob */
1389 request = ndr_push_blob(push);
1391 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1392 status = dcerpc_ndr_validate_in(p->conn, push, request, call->struct_size,
1393 call->ndr_push, call->ndr_pull);
1394 if (!NT_STATUS_IS_OK(status)) {
1395 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1396 nt_errstr(status)));
1397 talloc_free(push);
1398 return NULL;
1402 DEBUG(10,("rpc request data:\n"));
1403 dump_data(10, request.data, request.length);
1405 /* make the actual dcerpc request */
1406 req = dcerpc_request_send(p, object, opnum, async, &request);
1408 if (req != NULL) {
1409 req->ndr.table = table;
1410 req->ndr.opnum = opnum;
1411 req->ndr.struct_ptr = r;
1412 req->ndr.mem_ctx = mem_ctx;
1415 talloc_free(push);
1417 return req;
1421 receive the answer from a dcerpc_ndr_request_send()
1423 _PUBLIC_ NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1425 struct dcerpc_pipe *p = req->p;
1426 NTSTATUS status;
1427 DATA_BLOB response;
1428 struct ndr_pull *pull;
1429 unsigned int flags;
1430 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1431 void *r = req->ndr.struct_ptr;
1432 uint32_t opnum = req->ndr.opnum;
1433 const struct ndr_interface_table *table = req->ndr.table;
1434 const struct ndr_interface_call *call = &table->calls[opnum];
1435 enum ndr_err_code ndr_err;
1437 /* make sure the recv code doesn't free the request, as we
1438 need to grab the flags element before it is freed */
1439 if (talloc_reference(p, req) == NULL) {
1440 return NT_STATUS_NO_MEMORY;
1443 status = dcerpc_request_recv(req, mem_ctx, &response);
1444 if (!NT_STATUS_IS_OK(status)) {
1445 talloc_unlink(p, req);
1446 return status;
1449 flags = req->flags;
1451 /* prepare for ndr_pull_* */
1452 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1453 if (!pull) {
1454 talloc_unlink(p, req);
1455 return NT_STATUS_NO_MEMORY;
1458 if (pull->data) {
1459 pull->data = talloc_steal(pull, pull->data);
1461 talloc_unlink(p, req);
1463 if (flags & DCERPC_PULL_BIGENDIAN) {
1464 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1467 DEBUG(10,("rpc reply data:\n"));
1468 dump_data(10, pull->data, pull->data_size);
1470 /* pull the structure from the blob */
1471 ndr_err = call->ndr_pull(pull, NDR_OUT, r);
1472 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1473 status = ndr_map_error2ntstatus(ndr_err);
1474 dcerpc_log_packet(p->conn->packet_log_dir,
1475 table, opnum, NDR_OUT,
1476 &response);
1477 return status;
1480 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1481 status = dcerpc_ndr_validate_out(p->conn, pull, r, call->struct_size,
1482 call->ndr_push, call->ndr_pull,
1483 call->ndr_print);
1484 if (!NT_STATUS_IS_OK(status)) {
1485 dcerpc_log_packet(p->conn->packet_log_dir,
1486 table, opnum, NDR_OUT,
1487 &response);
1488 return status;
1492 if (pull->offset != pull->data_size) {
1493 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1494 pull->data_size - pull->offset));
1495 /* we used to return NT_STATUS_INFO_LENGTH_MISMATCH here,
1496 but it turns out that early versions of NT
1497 (specifically NT3.1) add junk onto the end of rpc
1498 packets, so if we want to interoperate at all with
1499 those versions then we need to ignore this error */
1502 /* TODO: make pull context independent from the output mem_ctx and free the pull context */
1504 return NT_STATUS_OK;
1509 a useful helper function for synchronous rpc requests
1511 this can be used when you have ndr push/pull functions in the
1512 standard format
1514 _PUBLIC_ NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1515 const struct GUID *object,
1516 const struct ndr_interface_table *table,
1517 uint32_t opnum,
1518 TALLOC_CTX *mem_ctx,
1519 void *r)
1521 struct rpc_request *req;
1523 req = dcerpc_ndr_request_send(p, object, table, opnum, false, mem_ctx, r);
1524 if (req == NULL) {
1525 return NT_STATUS_NO_MEMORY;
1528 return dcerpc_ndr_request_recv(req);
1533 a useful function for retrieving the server name we connected to
1535 _PUBLIC_ const char *dcerpc_server_name(struct dcerpc_pipe *p)
1537 if (!p->conn->transport.target_hostname) {
1538 if (!p->conn->transport.peer_name) {
1539 return "";
1541 return p->conn->transport.peer_name(p->conn);
1543 return p->conn->transport.target_hostname(p->conn);
1548 get the dcerpc auth_level for a open connection
1550 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1552 uint8_t auth_level;
1554 if (c->flags & DCERPC_SEAL) {
1555 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1556 } else if (c->flags & DCERPC_SIGN) {
1557 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1558 } else if (c->flags & DCERPC_CONNECT) {
1559 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1560 } else {
1561 auth_level = DCERPC_AUTH_LEVEL_NONE;
1563 return auth_level;
1567 Receive an alter reply from the transport
1569 static void dcerpc_alter_recv_handler(struct rpc_request *req,
1570 DATA_BLOB *raw_packet, struct ncacn_packet *pkt)
1572 struct composite_context *c;
1573 struct dcerpc_pipe *recv_pipe;
1575 c = talloc_get_type(req->async.private_data, struct composite_context);
1576 recv_pipe = talloc_get_type(c->private_data, struct dcerpc_pipe);
1578 if (pkt->ptype == DCERPC_PKT_ALTER_RESP &&
1579 pkt->u.alter_resp.num_results == 1 &&
1580 pkt->u.alter_resp.ctx_list[0].result != 0) {
1581 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1582 pkt->u.alter_resp.ctx_list[0].reason));
1583 composite_error(c, dcerpc_map_reason(pkt->u.alter_resp.ctx_list[0].reason));
1584 return;
1587 if (pkt->ptype != DCERPC_PKT_ALTER_RESP ||
1588 pkt->u.alter_resp.num_results == 0 ||
1589 pkt->u.alter_resp.ctx_list[0].result != 0) {
1590 composite_error(c, NT_STATUS_NET_WRITE_FAULT);
1591 return;
1594 /* the alter_resp might contain a reply set of credentials */
1595 if (recv_pipe->conn->security_state.auth_info &&
1596 pkt->u.alter_resp.auth_info.length) {
1597 struct dcerpc_connection *conn = recv_pipe->conn;
1598 NTSTATUS status;
1599 uint32_t auth_length;
1600 status = dcerpc_pull_auth_trailer(pkt, conn, &pkt->u.alter_resp.auth_info,
1601 conn->security_state.auth_info, &auth_length, true);
1602 if (!NT_STATUS_IS_OK(status)) {
1603 composite_error(c, status);
1604 return;
1608 composite_done(c);
1612 send a dcerpc alter_context request
1614 struct composite_context *dcerpc_alter_context_send(struct dcerpc_pipe *p,
1615 TALLOC_CTX *mem_ctx,
1616 const struct ndr_syntax_id *syntax,
1617 const struct ndr_syntax_id *transfer_syntax)
1619 struct composite_context *c;
1620 struct ncacn_packet pkt;
1621 DATA_BLOB blob;
1622 struct rpc_request *req;
1624 c = composite_create(mem_ctx, p->conn->event_ctx);
1625 if (c == NULL) return NULL;
1627 c->private_data = p;
1629 p->syntax = *syntax;
1630 p->transfer_syntax = *transfer_syntax;
1632 init_ncacn_hdr(p->conn, &pkt);
1634 pkt.ptype = DCERPC_PKT_ALTER;
1635 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1636 pkt.call_id = p->conn->call_id;
1637 pkt.auth_length = 0;
1639 if (p->binding->flags & DCERPC_CONCURRENT_MULTIPLEX) {
1640 pkt.pfc_flags |= DCERPC_PFC_FLAG_CONC_MPX;
1643 if (p->binding->flags & DCERPC_HEADER_SIGNING) {
1644 pkt.pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1647 pkt.u.alter.max_xmit_frag = 5840;
1648 pkt.u.alter.max_recv_frag = 5840;
1649 pkt.u.alter.assoc_group_id = p->binding->assoc_group_id;
1650 pkt.u.alter.num_contexts = 1;
1651 pkt.u.alter.ctx_list = talloc_array(c, struct dcerpc_ctx_list, 1);
1652 if (composite_nomem(pkt.u.alter.ctx_list, c)) return c;
1653 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1654 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1655 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1656 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1657 pkt.u.alter.auth_info = data_blob(NULL, 0);
1659 /* construct the NDR form of the packet */
1660 c->status = ncacn_push_auth(&blob, mem_ctx, p->conn->iconv_convenience, &pkt,
1661 p->conn->security_state.auth_info);
1662 if (!composite_is_ok(c)) return c;
1664 p->conn->transport.recv_data = dcerpc_recv_data;
1667 * we allocate a dcerpc_request so we can be in the same
1668 * request queue as normal requests
1670 req = talloc_zero(c, struct rpc_request);
1671 if (composite_nomem(req, c)) return c;
1673 req->state = RPC_REQUEST_PENDING;
1674 req->call_id = pkt.call_id;
1675 req->async.private_data = c;
1676 req->async.callback = dcerpc_composite_fail;
1677 req->p = p;
1678 req->recv_handler = dcerpc_alter_recv_handler;
1679 DLIST_ADD_END(p->conn->pending, req, struct rpc_request *);
1680 talloc_set_destructor(req, dcerpc_req_dequeue);
1682 c->status = p->conn->transport.send_request(p->conn, &blob, true);
1683 if (!composite_is_ok(c)) return c;
1685 event_add_timed(c->event_ctx, req,
1686 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
1687 dcerpc_timeout_handler, req);
1689 return c;
1692 NTSTATUS dcerpc_alter_context_recv(struct composite_context *ctx)
1694 NTSTATUS result = composite_wait(ctx);
1695 talloc_free(ctx);
1696 return result;
1700 send a dcerpc alter_context request
1702 _PUBLIC_ NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1703 TALLOC_CTX *mem_ctx,
1704 const struct ndr_syntax_id *syntax,
1705 const struct ndr_syntax_id *transfer_syntax)
1707 struct composite_context *creq;
1708 creq = dcerpc_alter_context_send(p, mem_ctx, syntax, transfer_syntax);
1709 return dcerpc_alter_context_recv(creq);