r5197: moved events code to lib/events/ (suggestion from metze)
[Samba.git] / source / librpc / rpc / dcerpc.c
blob420c7acf7c4db929358e5a765438770c6edf78fb
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
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 2 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, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "includes.h"
25 #include "dlinklist.h"
26 #include "lib/events/events.h"
27 #include "librpc/gen_ndr/ndr_epmapper.h"
28 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 static struct dcerpc_interface_list *dcerpc_pipes = NULL;
33 register a dcerpc client interface
35 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
37 struct dcerpc_interface_list *l = talloc(talloc_autofree_context(),
38 struct dcerpc_interface_list);
40 if (idl_iface_by_name (interface->name) != NULL) {
41 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
42 return NT_STATUS_OBJECT_NAME_COLLISION;
44 l->table = interface;
46 DLIST_ADD(dcerpc_pipes, l);
48 return NT_STATUS_OK;
52 return the list of registered dcerpc_pipes
54 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
56 return dcerpc_pipes;
59 /* destroy a dcerpc connection */
60 static int dcerpc_connection_destructor(void *ptr)
62 struct dcerpc_connection *c = ptr;
63 if (c->transport.shutdown_pipe) {
64 c->transport.shutdown_pipe(c);
66 return 0;
70 /* initialise a dcerpc connection. */
71 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx)
73 struct dcerpc_connection *c;
75 c = talloc_zero(mem_ctx, struct dcerpc_connection);
76 if (!c) {
77 return NULL;
80 c->call_id = 1;
81 c->security_state.auth_info = NULL;
82 c->security_state.session_key = dcerpc_generic_session_key;
83 c->security_state.generic_state = NULL;
84 c->binding_string = NULL;
85 c->flags = 0;
86 c->srv_max_xmit_frag = 0;
87 c->srv_max_recv_frag = 0;
88 c->pending = NULL;
90 talloc_set_destructor(c, dcerpc_connection_destructor);
92 return c;
95 /* initialise a dcerpc pipe. */
96 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx)
98 struct dcerpc_pipe *p;
100 p = talloc(mem_ctx, struct dcerpc_pipe);
101 if (!p) {
102 return NULL;
105 p->conn = dcerpc_connection_init(p);
106 if (p->conn == NULL) {
107 talloc_free(p);
108 return NULL;
111 p->last_fault_code = 0;
112 p->context_id = 0;
114 ZERO_STRUCT(p->syntax);
115 ZERO_STRUCT(p->transfer_syntax);
117 return p;
122 choose the next call id to use
124 static uint32_t next_call_id(struct dcerpc_connection *c)
126 c->call_id++;
127 if (c->call_id == 0) {
128 c->call_id++;
130 return c->call_id;
133 /* close down a dcerpc over SMB pipe */
134 void dcerpc_pipe_close(struct dcerpc_pipe *p)
136 talloc_free(p);
139 /* we need to be able to get/set the fragment length without doing a full
140 decode */
141 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
143 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
144 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
145 } else {
146 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
150 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
152 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
153 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
154 } else {
155 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
159 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
161 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
162 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
163 } else {
164 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
170 setup for a ndr pull, also setting up any flags from the binding string
172 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
173 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
175 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
177 if (ndr == NULL) return ndr;
179 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
180 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
183 if (c->flags & DCERPC_NDR_REF_ALLOC) {
184 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
187 return ndr;
191 parse a data blob into a dcerpc_packet structure. This handles both
192 input and output packets
194 static NTSTATUS dcerpc_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
195 struct dcerpc_packet *pkt)
197 struct ndr_pull *ndr;
199 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
200 if (!ndr) {
201 return NT_STATUS_NO_MEMORY;
204 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
205 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
208 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
212 generate a CONNECT level verifier
214 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
216 *blob = data_blob_talloc(mem_ctx, NULL, 16);
217 if (blob->data == NULL) {
218 return NT_STATUS_NO_MEMORY;
220 SIVAL(blob->data, 0, 1);
221 memset(blob->data+4, 0, 12);
222 return NT_STATUS_OK;
226 check a CONNECT level verifier
228 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
230 if (blob->length != 16 ||
231 IVAL(blob->data, 0) != 1) {
232 return NT_STATUS_ACCESS_DENIED;
234 return NT_STATUS_OK;
238 parse a possibly signed blob into a dcerpc request packet structure
240 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_connection *c,
241 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
242 struct dcerpc_packet *pkt)
244 struct ndr_pull *ndr;
245 NTSTATUS status;
246 struct dcerpc_auth auth;
247 DATA_BLOB auth_blob;
249 /* non-signed packets are simpler */
250 if (!c->security_state.auth_info ||
251 !c->security_state.generic_state) {
252 return dcerpc_pull(c, blob, mem_ctx, pkt);
255 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
256 if (!ndr) {
257 return NT_STATUS_NO_MEMORY;
260 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
261 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
264 /* pull the basic packet */
265 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
266 if (!NT_STATUS_IS_OK(status)) {
267 return status;
270 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
271 return status;
274 if (pkt->auth_length == 0 &&
275 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
276 return NT_STATUS_OK;
279 auth_blob.length = 8 + pkt->auth_length;
281 /* check for a valid length */
282 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
283 return NT_STATUS_INFO_LENGTH_MISMATCH;
286 auth_blob.data =
287 pkt->u.response.stub_and_verifier.data +
288 pkt->u.response.stub_and_verifier.length - auth_blob.length;
289 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
291 /* pull the auth structure */
292 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
293 if (!ndr) {
294 return NT_STATUS_NO_MEMORY;
297 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
298 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
301 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
302 if (!NT_STATUS_IS_OK(status)) {
303 return status;
307 /* check signature or unseal the packet */
308 switch (c->security_state.auth_info->auth_level) {
309 case DCERPC_AUTH_LEVEL_PRIVACY:
310 status = gensec_unseal_packet(c->security_state.generic_state,
311 mem_ctx,
312 blob->data + DCERPC_REQUEST_LENGTH,
313 pkt->u.response.stub_and_verifier.length,
314 blob->data,
315 blob->length - auth.credentials.length,
316 &auth.credentials);
317 memcpy(pkt->u.response.stub_and_verifier.data,
318 blob->data + DCERPC_REQUEST_LENGTH,
319 pkt->u.response.stub_and_verifier.length);
320 break;
322 case DCERPC_AUTH_LEVEL_INTEGRITY:
323 status = gensec_check_packet(c->security_state.generic_state,
324 mem_ctx,
325 pkt->u.response.stub_and_verifier.data,
326 pkt->u.response.stub_and_verifier.length,
327 blob->data,
328 blob->length - auth.credentials.length,
329 &auth.credentials);
330 break;
332 case DCERPC_AUTH_LEVEL_CONNECT:
333 status = dcerpc_check_connect_verifier(&auth.credentials);
334 break;
336 case DCERPC_AUTH_LEVEL_NONE:
337 break;
339 default:
340 status = NT_STATUS_INVALID_LEVEL;
341 break;
344 /* remove the indicated amount of paddiing */
345 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
346 return NT_STATUS_INFO_LENGTH_MISMATCH;
348 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
350 return status;
355 push a dcerpc request packet into a blob, possibly signing it.
357 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_connection *c,
358 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
359 struct dcerpc_packet *pkt)
361 NTSTATUS status;
362 struct ndr_push *ndr;
363 DATA_BLOB creds2;
365 /* non-signed packets are simpler */
366 if (!c->security_state.auth_info ||
367 !c->security_state.generic_state) {
368 return dcerpc_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
371 ndr = ndr_push_init_ctx(mem_ctx);
372 if (!ndr) {
373 return NT_STATUS_NO_MEMORY;
376 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
377 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
380 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
381 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
384 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
385 if (!NT_STATUS_IS_OK(status)) {
386 return status;
389 /* pad to 16 byte multiple in the payload portion of the
390 packet. This matches what w2k3 does */
391 c->security_state.auth_info->auth_pad_length =
392 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
393 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
395 /* sign or seal the packet */
396 switch (c->security_state.auth_info->auth_level) {
397 case DCERPC_AUTH_LEVEL_PRIVACY:
398 case DCERPC_AUTH_LEVEL_INTEGRITY:
399 c->security_state.auth_info->credentials
400 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state));
401 data_blob_clear(&c->security_state.auth_info->credentials);
402 break;
404 case DCERPC_AUTH_LEVEL_CONNECT:
405 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
406 break;
408 case DCERPC_AUTH_LEVEL_NONE:
409 c->security_state.auth_info->credentials = data_blob(NULL, 0);
410 break;
412 default:
413 status = NT_STATUS_INVALID_LEVEL;
414 break;
417 if (!NT_STATUS_IS_OK(status)) {
418 return status;
421 /* add the auth verifier */
422 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
423 if (!NT_STATUS_IS_OK(status)) {
424 return status;
427 /* extract the whole packet as a blob */
428 *blob = ndr_push_blob(ndr);
430 /* fill in the fragment length and auth_length, we can't fill
431 in these earlier as we don't know the signature length (it
432 could be variable length) */
433 dcerpc_set_frag_length(blob, blob->length);
434 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
436 /* sign or seal the packet */
437 switch (c->security_state.auth_info->auth_level) {
438 case DCERPC_AUTH_LEVEL_PRIVACY:
439 status = gensec_seal_packet(c->security_state.generic_state,
440 mem_ctx,
441 blob->data + DCERPC_REQUEST_LENGTH,
442 pkt->u.request.stub_and_verifier.length +
443 c->security_state.auth_info->auth_pad_length,
444 blob->data,
445 blob->length -
446 c->security_state.auth_info->credentials.length,
447 &creds2);
448 if (!NT_STATUS_IS_OK(status)) {
449 return status;
451 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
452 break;
454 case DCERPC_AUTH_LEVEL_INTEGRITY:
455 status = gensec_sign_packet(c->security_state.generic_state,
456 mem_ctx,
457 blob->data + DCERPC_REQUEST_LENGTH,
458 pkt->u.request.stub_and_verifier.length +
459 c->security_state.auth_info->auth_pad_length,
460 blob->data,
461 blob->length -
462 c->security_state.auth_info->credentials.length,
463 &creds2);
464 if (!NT_STATUS_IS_OK(status)) {
465 return status;
467 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
468 break;
470 case DCERPC_AUTH_LEVEL_CONNECT:
471 break;
473 case DCERPC_AUTH_LEVEL_NONE:
474 c->security_state.auth_info->credentials = data_blob(NULL, 0);
475 break;
477 default:
478 status = NT_STATUS_INVALID_LEVEL;
479 break;
482 data_blob_free(&c->security_state.auth_info->credentials);
484 return NT_STATUS_OK;
489 fill in the fixed values in a dcerpc header
491 static void init_dcerpc_hdr(struct dcerpc_connection *c, struct dcerpc_packet *pkt)
493 pkt->rpc_vers = 5;
494 pkt->rpc_vers_minor = 0;
495 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
496 pkt->drep[0] = 0;
497 } else {
498 pkt->drep[0] = DCERPC_DREP_LE;
500 pkt->drep[1] = 0;
501 pkt->drep[2] = 0;
502 pkt->drep[3] = 0;
506 hold the state of pending full requests
508 struct full_request_state {
509 DATA_BLOB *reply_blob;
510 NTSTATUS status;
514 receive a reply to a full request
516 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob,
517 NTSTATUS status)
519 struct full_request_state *state = c->full_request_private;
521 if (!NT_STATUS_IS_OK(status)) {
522 state->status = status;
523 return;
525 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
526 state->reply_blob = NULL;
530 perform a single pdu synchronous request - used for the bind code
531 this cannot be mixed with normal async requests
533 static NTSTATUS full_request(struct dcerpc_connection *c,
534 TALLOC_CTX *mem_ctx,
535 DATA_BLOB *request_blob,
536 DATA_BLOB *reply_blob)
538 struct full_request_state *state = talloc(mem_ctx, struct full_request_state);
539 NTSTATUS status;
541 if (state == NULL) {
542 return NT_STATUS_NO_MEMORY;
545 state->reply_blob = reply_blob;
546 state->status = NT_STATUS_OK;
548 c->transport.recv_data = full_request_recv;
549 c->full_request_private = state;
551 status = c->transport.send_request(c, request_blob, True);
552 if (!NT_STATUS_IS_OK(status)) {
553 return status;
556 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
557 struct event_context *ctx = c->transport.event_context(c);
558 if (event_loop_once(ctx) != 0) {
559 return NT_STATUS_CONNECTION_DISCONNECTED;
563 return state->status;
567 map a bind nak reason to a NTSTATUS
569 static NTSTATUS dcerpc_map_reason(uint16_t reason)
571 switch (reason) {
572 case DCERPC_BIND_REASON_ASYNTAX:
573 return NT_STATUS_RPC_UNSUPPORTED_NAME_SYNTAX;
575 return NT_STATUS_UNSUCCESSFUL;
580 perform a bind using the given syntax
582 the auth_info structure is updated with the reply authentication info
583 on success
585 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
586 TALLOC_CTX *mem_ctx,
587 const struct dcerpc_syntax_id *syntax,
588 const struct dcerpc_syntax_id *transfer_syntax)
590 struct dcerpc_packet pkt;
591 NTSTATUS status;
592 DATA_BLOB blob;
594 p->syntax = *syntax;
595 p->transfer_syntax = *transfer_syntax;
597 init_dcerpc_hdr(p->conn, &pkt);
599 pkt.ptype = DCERPC_PKT_BIND;
600 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
601 pkt.call_id = p->conn->call_id;
602 pkt.auth_length = 0;
604 pkt.u.bind.max_xmit_frag = 5840;
605 pkt.u.bind.max_recv_frag = 5840;
606 pkt.u.bind.assoc_group_id = 0;
607 pkt.u.bind.num_contexts = 1;
608 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
609 if (!pkt.u.bind.ctx_list) {
610 return NT_STATUS_NO_MEMORY;
612 pkt.u.bind.ctx_list[0].context_id = p->context_id;
613 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
614 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
615 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
616 pkt.u.bind.auth_info = data_blob(NULL, 0);
618 /* construct the NDR form of the packet */
619 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
620 if (!NT_STATUS_IS_OK(status)) {
621 return status;
624 /* send it on its way */
625 status = full_request(p->conn, mem_ctx, &blob, &blob);
626 if (!NT_STATUS_IS_OK(status)) {
627 return status;
630 /* unmarshall the NDR */
631 status = dcerpc_pull(p->conn, &blob, mem_ctx, &pkt);
632 if (!NT_STATUS_IS_OK(status)) {
633 return status;
636 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
637 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
638 return dcerpc_map_reason(pkt.u.bind_nak.reject_reason);
641 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
642 pkt.u.bind_ack.num_results == 0 ||
643 pkt.u.bind_ack.ctx_list[0].result != 0) {
644 return NT_STATUS_UNSUCCESSFUL;
647 p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
648 p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
650 /* the bind_ack might contain a reply set of credentials */
651 if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
652 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
653 mem_ctx,
654 p->conn->security_state.auth_info,
655 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
658 return status;
663 perform a continued bind (and auth3)
665 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
666 TALLOC_CTX *mem_ctx)
668 struct dcerpc_packet pkt;
669 NTSTATUS status;
670 DATA_BLOB blob;
672 init_dcerpc_hdr(c, &pkt);
674 pkt.ptype = DCERPC_PKT_AUTH3;
675 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
676 pkt.call_id = next_call_id(c);
677 pkt.auth_length = 0;
678 pkt.u.auth3._pad = 0;
679 pkt.u.auth3.auth_info = data_blob(NULL, 0);
681 /* construct the NDR form of the packet */
682 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
683 if (!NT_STATUS_IS_OK(status)) {
684 return status;
687 /* send it on its way */
688 status = c->transport.send_request(c, &blob, False);
689 if (!NT_STATUS_IS_OK(status)) {
690 return status;
693 return status;
697 /* perform a dcerpc bind, using the uuid as the key */
698 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
699 TALLOC_CTX *mem_ctx,
700 const char *uuid, uint_t version)
702 struct dcerpc_syntax_id syntax;
703 struct dcerpc_syntax_id transfer_syntax;
704 NTSTATUS status;
706 status = GUID_from_string(uuid, &syntax.uuid);
707 if (!NT_STATUS_IS_OK(status)) {
708 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
709 return status;
711 syntax.if_version = version;
713 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
714 if (!NT_STATUS_IS_OK(status)) {
715 return status;
717 transfer_syntax.if_version = NDR_GUID_VERSION;
719 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
723 process a fragment received from the transport layer during a
724 request
726 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
727 DATA_BLOB *data,
728 NTSTATUS status)
730 struct dcerpc_packet pkt;
731 struct rpc_request *req;
732 uint_t length;
734 if (!NT_STATUS_IS_OK(status)) {
735 /* all pending requests get the error */
736 while (c->pending) {
737 req = c->pending;
738 req->state = RPC_REQUEST_DONE;
739 req->status = status;
740 DLIST_REMOVE(c->pending, req);
741 if (req->async.callback) {
742 req->async.callback(req);
745 return;
748 pkt.call_id = 0;
750 status = dcerpc_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
752 /* find the matching request. Notice we match before we check
753 the status. this is ok as a pending call_id can never be
754 zero */
755 for (req=c->pending;req;req=req->next) {
756 if (pkt.call_id == req->call_id) break;
759 if (req == NULL) {
760 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
761 return;
764 if (!NT_STATUS_IS_OK(status)) {
765 req->status = status;
766 req->state = RPC_REQUEST_DONE;
767 DLIST_REMOVE(c->pending, req);
768 if (req->async.callback) {
769 req->async.callback(req);
771 return;
774 if (pkt.ptype == DCERPC_PKT_FAULT) {
775 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
776 req->fault_code = pkt.u.fault.status;
777 req->status = NT_STATUS_NET_WRITE_FAULT;
778 req->state = RPC_REQUEST_DONE;
779 DLIST_REMOVE(c->pending, req);
780 if (req->async.callback) {
781 req->async.callback(req);
783 return;
786 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
787 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
788 (int)pkt.ptype));
789 req->fault_code = DCERPC_FAULT_OTHER;
790 req->status = NT_STATUS_NET_WRITE_FAULT;
791 req->state = RPC_REQUEST_DONE;
792 DLIST_REMOVE(c->pending, req);
793 if (req->async.callback) {
794 req->async.callback(req);
796 return;
799 length = pkt.u.response.stub_and_verifier.length;
801 if (length > 0) {
802 req->payload.data = talloc_realloc(req,
803 req->payload.data,
804 uint8_t,
805 req->payload.length + length);
806 if (!req->payload.data) {
807 req->status = NT_STATUS_NO_MEMORY;
808 req->state = RPC_REQUEST_DONE;
809 DLIST_REMOVE(c->pending, req);
810 if (req->async.callback) {
811 req->async.callback(req);
813 return;
815 memcpy(req->payload.data+req->payload.length,
816 pkt.u.response.stub_and_verifier.data, length);
817 req->payload.length += length;
820 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
821 c->transport.send_read(c);
822 return;
825 /* we've got the full payload */
826 req->state = RPC_REQUEST_DONE;
827 DLIST_REMOVE(c->pending, req);
829 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
830 req->flags |= DCERPC_PULL_BIGENDIAN;
831 } else {
832 req->flags &= ~DCERPC_PULL_BIGENDIAN;
835 if (req->async.callback) {
836 req->async.callback(req);
842 make sure requests are cleaned up
844 static int dcerpc_req_destructor(void *ptr)
846 struct rpc_request *req = ptr;
847 DLIST_REMOVE(req->p->conn->pending, req);
848 return 0;
852 perform the send side of a async dcerpc request
854 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
855 const struct GUID *object,
856 uint16_t opnum,
857 TALLOC_CTX *mem_ctx,
858 DATA_BLOB *stub_data)
860 struct rpc_request *req;
861 struct dcerpc_packet pkt;
862 DATA_BLOB blob;
863 uint32_t remaining, chunk_size;
864 BOOL first_packet = True;
866 p->conn->transport.recv_data = dcerpc_request_recv_data;
868 req = talloc(mem_ctx, struct rpc_request);
869 if (req == NULL) {
870 return NULL;
873 req->p = p;
874 req->call_id = next_call_id(p->conn);
875 req->status = NT_STATUS_OK;
876 req->state = RPC_REQUEST_PENDING;
877 req->payload = data_blob(NULL, 0);
878 req->flags = 0;
879 req->fault_code = 0;
880 req->async.callback = NULL;
882 init_dcerpc_hdr(p->conn, &pkt);
884 remaining = stub_data->length;
886 /* we can write a full max_recv_frag size, minus the dcerpc
887 request header size */
888 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
890 pkt.ptype = DCERPC_PKT_REQUEST;
891 pkt.call_id = req->call_id;
892 pkt.auth_length = 0;
893 pkt.pfc_flags = 0;
894 pkt.u.request.alloc_hint = remaining;
895 pkt.u.request.context_id = p->context_id;
896 pkt.u.request.opnum = opnum;
898 if (object) {
899 pkt.u.request.object.object = *object;
900 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
901 chunk_size -= ndr_size_GUID(object,0);
904 DLIST_ADD(p->conn->pending, req);
906 /* we send a series of pdus without waiting for a reply */
907 while (remaining > 0 || first_packet) {
908 uint32_t chunk = MIN(chunk_size, remaining);
909 BOOL last_frag = False;
911 first_packet = False;
912 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
914 if (remaining == stub_data->length) {
915 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
917 if (chunk == remaining) {
918 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
919 last_frag = True;
922 pkt.u.request.stub_and_verifier.data = stub_data->data +
923 (stub_data->length - remaining);
924 pkt.u.request.stub_and_verifier.length = chunk;
926 req->status = dcerpc_push_request_sign(p->conn, &blob, mem_ctx, &pkt);
927 if (!NT_STATUS_IS_OK(req->status)) {
928 req->state = RPC_REQUEST_DONE;
929 DLIST_REMOVE(p->conn->pending, req);
930 return req;
933 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
934 if (!NT_STATUS_IS_OK(req->status)) {
935 req->state = RPC_REQUEST_DONE;
936 DLIST_REMOVE(p->conn->pending, req);
937 return req;
940 remaining -= chunk;
943 talloc_set_destructor(req, dcerpc_req_destructor);
945 return req;
949 return the event context for a dcerpc pipe
950 used by callers who wish to operate asynchronously
952 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
954 return p->conn->transport.event_context(p->conn);
960 perform the receive side of a async dcerpc request
962 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
963 TALLOC_CTX *mem_ctx,
964 DATA_BLOB *stub_data)
966 NTSTATUS status;
968 while (req->state == RPC_REQUEST_PENDING) {
969 struct event_context *ctx = dcerpc_event_context(req->p);
970 if (event_loop_once(ctx) != 0) {
971 return NT_STATUS_CONNECTION_DISCONNECTED;
974 *stub_data = req->payload;
975 status = req->status;
976 if (stub_data->data) {
977 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
979 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
980 req->p->last_fault_code = req->fault_code;
982 talloc_free(req);
983 return status;
987 perform a full request/response pair on a dcerpc pipe
989 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
990 struct GUID *object,
991 uint16_t opnum,
992 TALLOC_CTX *mem_ctx,
993 DATA_BLOB *stub_data_in,
994 DATA_BLOB *stub_data_out)
996 struct rpc_request *req;
998 req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
999 if (req == NULL) {
1000 return NT_STATUS_NO_MEMORY;
1003 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1008 this is a paranoid NDR validator. For every packet we push onto the wire
1009 we pull it back again, then push it again. Then we compare the raw NDR data
1010 for that to the NDR we initially generated. If they don't match then we know
1011 we must have a bug in either the pull or push side of our code
1013 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1014 TALLOC_CTX *mem_ctx,
1015 DATA_BLOB blob,
1016 size_t struct_size,
1017 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1018 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1020 void *st;
1021 struct ndr_pull *pull;
1022 struct ndr_push *push;
1023 NTSTATUS status;
1024 DATA_BLOB blob2;
1026 st = talloc_size(mem_ctx, struct_size);
1027 if (!st) {
1028 return NT_STATUS_NO_MEMORY;
1031 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1032 if (!pull) {
1033 return NT_STATUS_NO_MEMORY;
1036 status = ndr_pull(pull, NDR_IN, st);
1037 if (!NT_STATUS_IS_OK(status)) {
1038 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1039 "failed input validation pull - %s",
1040 nt_errstr(status));
1043 push = ndr_push_init_ctx(mem_ctx);
1044 if (!push) {
1045 return NT_STATUS_NO_MEMORY;
1048 status = ndr_push(push, NDR_IN, st);
1049 if (!NT_STATUS_IS_OK(status)) {
1050 return ndr_push_error(push, NDR_ERR_VALIDATE,
1051 "failed input validation push - %s",
1052 nt_errstr(status));
1055 blob2 = ndr_push_blob(push);
1057 if (!data_blob_equal(&blob, &blob2)) {
1058 DEBUG(3,("original:\n"));
1059 dump_data(3, blob.data, blob.length);
1060 DEBUG(3,("secondary:\n"));
1061 dump_data(3, blob2.data, blob2.length);
1062 return ndr_push_error(push, NDR_ERR_VALIDATE,
1063 "failed input validation data - %s",
1064 nt_errstr(status));
1067 return NT_STATUS_OK;
1071 this is a paranoid NDR input validator. For every packet we pull
1072 from the wire we push it back again then pull and push it
1073 again. Then we compare the raw NDR data for that to the NDR we
1074 initially generated. If they don't match then we know we must have a
1075 bug in either the pull or push side of our code
1077 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1078 TALLOC_CTX *mem_ctx,
1079 void *struct_ptr,
1080 size_t struct_size,
1081 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1082 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1084 void *st;
1085 struct ndr_pull *pull;
1086 struct ndr_push *push;
1087 NTSTATUS status;
1088 DATA_BLOB blob, blob2;
1090 st = talloc_size(mem_ctx, struct_size);
1091 if (!st) {
1092 return NT_STATUS_NO_MEMORY;
1094 memcpy(st, struct_ptr, struct_size);
1096 push = ndr_push_init_ctx(mem_ctx);
1097 if (!push) {
1098 return NT_STATUS_NO_MEMORY;
1101 status = ndr_push(push, NDR_OUT, struct_ptr);
1102 if (!NT_STATUS_IS_OK(status)) {
1103 return ndr_push_error(push, NDR_ERR_VALIDATE,
1104 "failed output validation push - %s",
1105 nt_errstr(status));
1108 blob = ndr_push_blob(push);
1110 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1111 if (!pull) {
1112 return NT_STATUS_NO_MEMORY;
1115 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1116 status = ndr_pull(pull, NDR_OUT, st);
1117 if (!NT_STATUS_IS_OK(status)) {
1118 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1119 "failed output validation pull - %s",
1120 nt_errstr(status));
1123 push = ndr_push_init_ctx(mem_ctx);
1124 if (!push) {
1125 return NT_STATUS_NO_MEMORY;
1128 status = ndr_push(push, NDR_OUT, st);
1129 if (!NT_STATUS_IS_OK(status)) {
1130 return ndr_push_error(push, NDR_ERR_VALIDATE,
1131 "failed output validation push2 - %s",
1132 nt_errstr(status));
1135 blob2 = ndr_push_blob(push);
1137 if (!data_blob_equal(&blob, &blob2)) {
1138 DEBUG(3,("original:\n"));
1139 dump_data(3, blob.data, blob.length);
1140 DEBUG(3,("secondary:\n"));
1141 dump_data(3, blob2.data, blob2.length);
1142 return ndr_push_error(push, NDR_ERR_VALIDATE,
1143 "failed output validation data - %s",
1144 nt_errstr(status));
1147 return NT_STATUS_OK;
1152 send a rpc request given a dcerpc_call structure
1154 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1155 const struct GUID *object,
1156 const struct dcerpc_interface_table *table,
1157 uint32_t opnum,
1158 TALLOC_CTX *mem_ctx,
1159 void *r)
1161 const struct dcerpc_interface_call *call;
1162 struct ndr_push *push;
1163 NTSTATUS status;
1164 DATA_BLOB request;
1165 struct rpc_request *req;
1167 call = &table->calls[opnum];
1169 /* setup for a ndr_push_* call */
1170 push = ndr_push_init();
1171 if (!push) {
1172 return NULL;
1175 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1176 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1179 /* push the structure into a blob */
1180 status = call->ndr_push(push, NDR_IN, r);
1181 if (!NT_STATUS_IS_OK(status)) {
1182 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1183 nt_errstr(status)));
1184 ndr_push_free(push);
1185 return NULL;
1188 /* retrieve the blob */
1189 request = ndr_push_blob(push);
1191 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1192 status = dcerpc_ndr_validate_in(p->conn, mem_ctx, request, call->struct_size,
1193 call->ndr_push, call->ndr_pull);
1194 if (!NT_STATUS_IS_OK(status)) {
1195 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1196 nt_errstr(status)));
1197 ndr_push_free(push);
1198 return NULL;
1202 DEBUG(10,("rpc request data:\n"));
1203 dump_data(10, request.data, request.length);
1205 /* make the actual dcerpc request */
1206 req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1208 if (req != NULL) {
1209 req->ndr.table = table;
1210 req->ndr.opnum = opnum;
1211 req->ndr.struct_ptr = r;
1212 req->ndr.mem_ctx = mem_ctx;
1215 ndr_push_free(push);
1217 return req;
1221 receive the answer from a dcerpc_ndr_request_send()
1223 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1225 struct dcerpc_pipe *p = req->p;
1226 NTSTATUS status;
1227 DATA_BLOB response;
1228 struct ndr_pull *pull;
1229 uint_t flags;
1230 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1231 void *r = req->ndr.struct_ptr;
1232 uint32_t opnum = req->ndr.opnum;
1233 const struct dcerpc_interface_table *table = req->ndr.table;
1234 const struct dcerpc_interface_call *call = &table->calls[opnum];
1236 /* make sure the recv code doesn't free the request, as we
1237 need to grab the flags element before it is freed */
1238 talloc_increase_ref_count(req);
1240 status = dcerpc_request_recv(req, mem_ctx, &response);
1241 if (!NT_STATUS_IS_OK(status)) {
1242 return status;
1245 flags = req->flags;
1246 talloc_free(req);
1248 /* prepare for ndr_pull_* */
1249 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1250 if (!pull) {
1251 return NT_STATUS_NO_MEMORY;
1254 if (flags & DCERPC_PULL_BIGENDIAN) {
1255 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1258 DEBUG(10,("rpc reply data:\n"));
1259 dump_data(10, pull->data, pull->data_size);
1261 /* pull the structure from the blob */
1262 status = call->ndr_pull(pull, NDR_OUT, r);
1263 if (!NT_STATUS_IS_OK(status)) {
1264 dcerpc_log_packet(table, opnum, NDR_OUT,
1265 &response);
1266 return status;
1269 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1270 status = dcerpc_ndr_validate_out(p->conn, mem_ctx, r, call->struct_size,
1271 call->ndr_push, call->ndr_pull);
1272 if (!NT_STATUS_IS_OK(status)) {
1273 dcerpc_log_packet(table, opnum, NDR_OUT,
1274 &response);
1275 return status;
1279 if (pull->offset != pull->data_size) {
1280 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1281 pull->data_size - pull->offset));
1282 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1283 but it turns out that early versions of NT
1284 (specifically NT3.1) add junk onto the end of rpc
1285 packets, so if we want to interoperate at all with
1286 those versions then we need to ignore this error */
1289 return NT_STATUS_OK;
1294 a useful helper function for synchronous rpc requests
1296 this can be used when you have ndr push/pull functions in the
1297 standard format
1299 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1300 const struct GUID *object,
1301 const struct dcerpc_interface_table *table,
1302 uint32_t opnum,
1303 TALLOC_CTX *mem_ctx,
1304 void *r)
1306 struct rpc_request *req;
1308 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1309 if (req == NULL) {
1310 return NT_STATUS_NO_MEMORY;
1313 return dcerpc_ndr_request_recv(req);
1318 a useful function for retrieving the server name we connected to
1320 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1322 if (!p->conn->transport.peer_name) {
1323 return "";
1325 return p->conn->transport.peer_name(p->conn);
1330 get the dcerpc auth_level for a open connection
1332 uint32_t dcerpc_auth_level(struct dcerpc_connection *c)
1334 uint8_t auth_level;
1336 if (c->flags & DCERPC_SEAL) {
1337 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1338 } else if (c->flags & DCERPC_SIGN) {
1339 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1340 } else if (c->flags & DCERPC_CONNECT) {
1341 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1342 } else {
1343 auth_level = DCERPC_AUTH_LEVEL_NONE;
1345 return auth_level;
1350 send a dcerpc alter_context request
1352 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1353 TALLOC_CTX *mem_ctx,
1354 const struct dcerpc_syntax_id *syntax,
1355 const struct dcerpc_syntax_id *transfer_syntax)
1357 struct dcerpc_packet pkt;
1358 NTSTATUS status;
1359 DATA_BLOB blob;
1361 p->syntax = *syntax;
1362 p->transfer_syntax = *transfer_syntax;
1364 init_dcerpc_hdr(p->conn, &pkt);
1366 pkt.ptype = DCERPC_PKT_ALTER;
1367 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1368 pkt.call_id = p->conn->call_id;
1369 pkt.auth_length = 0;
1371 pkt.u.alter.max_xmit_frag = 5840;
1372 pkt.u.alter.max_recv_frag = 5840;
1373 pkt.u.alter.assoc_group_id = 0;
1374 pkt.u.alter.num_contexts = 1;
1375 pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1376 if (!pkt.u.alter.ctx_list) {
1377 return NT_STATUS_NO_MEMORY;
1379 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1380 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1381 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1382 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1383 pkt.u.alter.auth_info = data_blob(NULL, 0);
1385 /* construct the NDR form of the packet */
1386 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1387 if (!NT_STATUS_IS_OK(status)) {
1388 return status;
1391 /* send it on its way */
1392 status = full_request(p->conn, mem_ctx, &blob, &blob);
1393 if (!NT_STATUS_IS_OK(status)) {
1394 return status;
1397 /* unmarshall the NDR */
1398 status = dcerpc_pull(p->conn, &blob, mem_ctx, &pkt);
1399 if (!NT_STATUS_IS_OK(status)) {
1400 return status;
1403 if (pkt.ptype == DCERPC_PKT_ALTER_RESP &&
1404 pkt.u.alter_resp.num_results == 1 &&
1405 pkt.u.alter_resp.ctx_list[0].result != 0) {
1406 DEBUG(2,("dcerpc: alter_resp failed - reason %d\n",
1407 pkt.u.alter_resp.ctx_list[0].reason));
1408 return dcerpc_map_reason(pkt.u.alter_resp.ctx_list[0].reason);
1411 if (pkt.ptype != DCERPC_PKT_ALTER_RESP ||
1412 pkt.u.alter_resp.num_results == 0 ||
1413 pkt.u.alter_resp.ctx_list[0].result != 0) {
1414 return NT_STATUS_UNSUCCESSFUL;
1417 /* the alter_resp might contain a reply set of credentials */
1418 if (p->conn->security_state.auth_info && pkt.u.alter_resp.auth_info.length) {
1419 status = ndr_pull_struct_blob(&pkt.u.alter_resp.auth_info,
1420 mem_ctx,
1421 p->conn->security_state.auth_info,
1422 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
1425 return status;