2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003
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.
25 #include "dlinklist.h"
26 #include "librpc/gen_ndr/ndr_epmapper.h"
28 struct dcerpc_interface_list *dcerpc_pipes = NULL;
30 NTSTATUS librpc_register_interface (const struct dcerpc_interface_table *interface)
32 struct dcerpc_interface_list *l = talloc_p(NULL, struct dcerpc_interface_list);
34 if (idl_iface_by_name (interface->name) != NULL) {
35 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
36 return NT_STATUS_OBJECT_NAME_COLLISION;
40 DLIST_ADD(dcerpc_pipes, l);
45 /* initialise a dcerpc pipe. */
46 struct dcerpc_pipe *dcerpc_pipe_init(void)
48 struct dcerpc_pipe *p;
50 p = talloc_p(NULL, struct dcerpc_pipe);
55 p->reference_count = 0;
57 p->security_state.auth_info = NULL;
58 p->security_state.session_key = dcerpc_generic_session_key;
59 p->security_state.generic_state = NULL;
60 p->binding_string = NULL;
62 p->srv_max_xmit_frag = 0;
63 p->srv_max_recv_frag = 0;
64 p->last_fault_code = 0;
71 choose the next call id to use
73 static uint32_t next_call_id(struct dcerpc_pipe *p)
76 if (p->call_id == 0) {
82 /* close down a dcerpc over SMB pipe */
83 void dcerpc_pipe_close(struct dcerpc_pipe *p)
87 if (p->reference_count <= 0) {
88 p->transport.shutdown_pipe(p);
93 /* we need to be able to get/set the fragment length without doing a full
95 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
97 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
98 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
100 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
104 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
106 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
107 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
109 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
113 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
115 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
116 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
118 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
124 setup for a ndr pull, also setting up any flags from the binding string
126 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
128 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
130 if (ndr == NULL) return ndr;
132 if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
133 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
136 if (p->flags & DCERPC_NDR_REF_ALLOC) {
137 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
144 parse a data blob into a dcerpc_packet structure. This handles both
145 input and output packets
147 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
148 struct dcerpc_packet *pkt)
150 struct ndr_pull *ndr;
152 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
154 return NT_STATUS_NO_MEMORY;
157 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
158 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
161 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
165 generate a CONNECT level verifier
167 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
169 *blob = data_blob_talloc(mem_ctx, NULL, 16);
170 if (blob->data == NULL) {
171 return NT_STATUS_NO_MEMORY;
173 SIVAL(blob->data, 0, 1);
174 memset(blob->data+4, 0, 12);
179 generate a CONNECT level verifier
181 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
183 if (blob->length != 16 ||
184 IVAL(blob->data, 0) != 1) {
185 return NT_STATUS_ACCESS_DENIED;
191 parse a possibly signed blob into a dcerpc request packet structure
193 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
194 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
195 struct dcerpc_packet *pkt)
197 struct ndr_pull *ndr;
199 struct dcerpc_auth auth;
202 /* non-signed packets are simpler */
203 if (!p->security_state.auth_info ||
204 !p->security_state.generic_state) {
205 return dcerpc_pull(p, blob, mem_ctx, pkt);
208 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
210 return NT_STATUS_NO_MEMORY;
213 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
214 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
217 /* pull the basic packet */
218 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
219 if (!NT_STATUS_IS_OK(status)) {
223 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
227 if (pkt->auth_length == 0 &&
228 p->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
232 auth_blob.length = 8 + pkt->auth_length;
234 /* check for a valid length */
235 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
236 return NT_STATUS_INFO_LENGTH_MISMATCH;
240 pkt->u.response.stub_and_verifier.data +
241 pkt->u.response.stub_and_verifier.length - auth_blob.length;
242 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
244 /* pull the auth structure */
245 ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
247 return NT_STATUS_NO_MEMORY;
250 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
251 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
254 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
255 if (!NT_STATUS_IS_OK(status)) {
260 /* check signature or unseal the packet */
261 switch (p->security_state.auth_info->auth_level) {
262 case DCERPC_AUTH_LEVEL_PRIVACY:
263 status = gensec_unseal_packet(p->security_state.generic_state,
265 blob->data + DCERPC_REQUEST_LENGTH,
266 pkt->u.response.stub_and_verifier.length,
268 blob->length - auth.credentials.length,
270 memcpy(pkt->u.response.stub_and_verifier.data,
271 blob->data + DCERPC_REQUEST_LENGTH,
272 pkt->u.response.stub_and_verifier.length);
275 case DCERPC_AUTH_LEVEL_INTEGRITY:
276 status = gensec_check_packet(p->security_state.generic_state,
278 pkt->u.response.stub_and_verifier.data,
279 pkt->u.response.stub_and_verifier.length,
281 blob->length - auth.credentials.length,
285 case DCERPC_AUTH_LEVEL_CONNECT:
286 status = dcerpc_check_connect_verifier(&auth.credentials);
289 case DCERPC_AUTH_LEVEL_NONE:
293 status = NT_STATUS_INVALID_LEVEL;
297 /* remove the indicated amount of paddiing */
298 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
299 return NT_STATUS_INFO_LENGTH_MISMATCH;
301 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
308 push a dcerpc request packet into a blob, possibly signing it.
310 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
311 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
312 struct dcerpc_packet *pkt)
315 struct ndr_push *ndr;
318 /* non-signed packets are simpler */
319 if (!p->security_state.auth_info ||
320 !p->security_state.generic_state) {
321 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
324 ndr = ndr_push_init_ctx(mem_ctx);
326 return NT_STATUS_NO_MEMORY;
329 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
330 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
333 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
334 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
337 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
338 if (!NT_STATUS_IS_OK(status)) {
342 /* pad to 16 byte multiple in the payload portion of the
343 packet. This matches what w2k3 does */
344 p->security_state.auth_info->auth_pad_length =
345 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
346 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
348 /* sign or seal the packet */
349 switch (p->security_state.auth_info->auth_level) {
350 case DCERPC_AUTH_LEVEL_PRIVACY:
351 case DCERPC_AUTH_LEVEL_INTEGRITY:
352 p->security_state.auth_info->credentials
353 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
354 data_blob_clear(&p->security_state.auth_info->credentials);
357 case DCERPC_AUTH_LEVEL_CONNECT:
358 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
361 case DCERPC_AUTH_LEVEL_NONE:
362 p->security_state.auth_info->credentials = data_blob(NULL, 0);
366 status = NT_STATUS_INVALID_LEVEL;
370 if (!NT_STATUS_IS_OK(status)) {
374 /* add the auth verifier */
375 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
376 if (!NT_STATUS_IS_OK(status)) {
380 /* extract the whole packet as a blob */
381 *blob = ndr_push_blob(ndr);
383 /* fill in the fragment length and auth_length, we can't fill
384 in these earlier as we don't know the signature length (it
385 could be variable length) */
386 dcerpc_set_frag_length(blob, blob->length);
387 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
389 /* sign or seal the packet */
390 switch (p->security_state.auth_info->auth_level) {
391 case DCERPC_AUTH_LEVEL_PRIVACY:
392 status = gensec_seal_packet(p->security_state.generic_state,
394 blob->data + DCERPC_REQUEST_LENGTH,
395 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
398 p->security_state.auth_info->credentials.length,
400 if (!NT_STATUS_IS_OK(status)) {
403 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
406 case DCERPC_AUTH_LEVEL_INTEGRITY:
407 status = gensec_sign_packet(p->security_state.generic_state,
409 blob->data + DCERPC_REQUEST_LENGTH,
410 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
413 p->security_state.auth_info->credentials.length,
415 if (!NT_STATUS_IS_OK(status)) {
418 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
421 case DCERPC_AUTH_LEVEL_CONNECT:
424 case DCERPC_AUTH_LEVEL_NONE:
425 p->security_state.auth_info->credentials = data_blob(NULL, 0);
429 status = NT_STATUS_INVALID_LEVEL;
433 data_blob_free(&p->security_state.auth_info->credentials);
440 fill in the fixed values in a dcerpc header
442 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
445 pkt->rpc_vers_minor = 0;
446 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
449 pkt->drep[0] = DCERPC_DREP_LE;
457 hold the state of pending full requests
459 struct full_request_state {
460 DATA_BLOB *reply_blob;
465 receive a reply to a full request
467 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
470 struct full_request_state *state = p->full_request_private;
472 if (!NT_STATUS_IS_OK(status)) {
473 state->status = status;
476 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
477 state->reply_blob = NULL;
481 perform a single pdu synchronous request - used for the bind code
482 this cannot be mixed with normal async requests
484 static NTSTATUS full_request(struct dcerpc_pipe *p,
486 DATA_BLOB *request_blob,
487 DATA_BLOB *reply_blob)
489 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
493 return NT_STATUS_NO_MEMORY;
496 state->reply_blob = reply_blob;
497 state->status = NT_STATUS_OK;
499 p->transport.recv_data = full_request_recv;
500 p->full_request_private = state;
502 status = p->transport.send_request(p, request_blob, True);
503 if (!NT_STATUS_IS_OK(status)) {
507 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
508 struct event_context *ctx = p->transport.event_context(p);
509 if (event_loop_once(ctx) != 0) {
510 return NT_STATUS_CONNECTION_DISCONNECTED;
514 return state->status;
519 perform a bind using the given syntax
521 the auth_info structure is updated with the reply authentication info
524 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
526 const struct dcerpc_syntax_id *syntax,
527 const struct dcerpc_syntax_id *transfer_syntax)
529 struct dcerpc_packet pkt;
534 p->transfer_syntax = *transfer_syntax;
536 init_dcerpc_hdr(p, &pkt);
538 pkt.ptype = DCERPC_PKT_BIND;
539 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
540 pkt.call_id = p->call_id;
543 pkt.u.bind.max_xmit_frag = 5840;
544 pkt.u.bind.max_recv_frag = 5840;
545 pkt.u.bind.assoc_group_id = 0;
546 pkt.u.bind.num_contexts = 1;
547 pkt.u.bind.ctx_list = talloc_p(mem_ctx, struct dcerpc_ctx_list);
548 if (!pkt.u.bind.ctx_list) {
549 return NT_STATUS_NO_MEMORY;
551 pkt.u.bind.ctx_list[0].context_id = 0;
552 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
553 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
554 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
555 pkt.u.bind.auth_info = data_blob(NULL, 0);
557 /* construct the NDR form of the packet */
558 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
559 if (!NT_STATUS_IS_OK(status)) {
563 /* send it on its way */
564 status = full_request(p, mem_ctx, &blob, &blob);
565 if (!NT_STATUS_IS_OK(status)) {
569 /* unmarshall the NDR */
570 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
571 if (!NT_STATUS_IS_OK(status)) {
575 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
576 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
577 return NT_STATUS_ACCESS_DENIED;
580 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
581 pkt.u.bind_ack.num_results == 0 ||
582 pkt.u.bind_ack.ctx_list[0].result != 0) {
583 return NT_STATUS_UNSUCCESSFUL;
586 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
587 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
588 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
591 /* the bind_ack might contain a reply set of credentials */
592 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
593 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
595 p->security_state.auth_info,
596 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
603 perform a alter context using the given syntax
605 the auth_info structure is updated with the reply authentication info
608 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
611 struct dcerpc_packet pkt;
615 init_dcerpc_hdr(p, &pkt);
617 pkt.ptype = DCERPC_PKT_ALTER;
618 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
619 pkt.call_id = p->call_id;
622 pkt.u.alter.max_xmit_frag = 0x2000;
623 pkt.u.alter.max_recv_frag = 0x2000;
624 pkt.u.alter.assoc_group_id = 0;
625 pkt.u.alter.num_contexts = 1;
626 pkt.u.alter.ctx_list = talloc_p(mem_ctx, struct dcerpc_ctx_list);
627 if (!pkt.u.alter.ctx_list) {
628 return NT_STATUS_NO_MEMORY;
630 pkt.u.alter.ctx_list[0].context_id = 0;
631 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
632 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
633 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
634 pkt.u.alter.auth_info = data_blob(NULL, 0);
636 /* construct the NDR form of the packet */
637 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
638 if (!NT_STATUS_IS_OK(status)) {
642 /* send it on its way */
643 status = full_request(p, mem_ctx, &blob, &blob);
644 if (!NT_STATUS_IS_OK(status)) {
648 /* unmarshall the NDR */
649 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
650 if (!NT_STATUS_IS_OK(status)) {
654 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
655 pkt.u.alter_ack.num_results == 0 ||
656 pkt.u.alter_ack.ctx_list[0].result != 0) {
657 status = NT_STATUS_UNSUCCESSFUL;
660 /* the bind_ack might contain a reply set of credentials */
661 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
662 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
664 p->security_state.auth_info,
665 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
672 perform a continued bind (and auth3)
674 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
677 struct dcerpc_packet pkt;
681 init_dcerpc_hdr(p, &pkt);
683 pkt.ptype = DCERPC_PKT_AUTH3;
684 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
685 pkt.call_id = next_call_id(p);
687 pkt.u.auth3._pad = 0;
688 pkt.u.auth3.auth_info = data_blob(NULL, 0);
690 /* construct the NDR form of the packet */
691 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
692 if (!NT_STATUS_IS_OK(status)) {
696 /* send it on its way */
697 status = p->transport.send_request(p, &blob, False);
698 if (!NT_STATUS_IS_OK(status)) {
706 /* perform a dcerpc bind, using the uuid as the key */
707 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
709 const char *uuid, uint_t version)
711 struct dcerpc_syntax_id syntax;
712 struct dcerpc_syntax_id transfer_syntax;
715 status = GUID_from_string(uuid, &syntax.uuid);
716 if (!NT_STATUS_IS_OK(status)) {
717 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
720 syntax.if_version = version;
722 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
723 if (!NT_STATUS_IS_OK(status)) {
726 transfer_syntax.if_version = NDR_GUID_VERSION;
728 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
732 process a fragment received from the transport layer during a
735 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
739 struct dcerpc_packet pkt;
740 struct rpc_request *req;
743 if (!NT_STATUS_IS_OK(status)) {
744 /* all pending requests get the error */
747 req->state = RPC_REQUEST_DONE;
748 req->status = status;
749 DLIST_REMOVE(p->pending, req);
750 if (req->async.callback) {
751 req->async.callback(req);
759 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
761 /* find the matching request. Notice we match before we check
762 the status. this is ok as a pending call_id can never be
764 for (req=p->pending;req;req=req->next) {
765 if (pkt.call_id == req->call_id) break;
769 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
773 if (!NT_STATUS_IS_OK(status)) {
774 req->status = status;
775 req->state = RPC_REQUEST_DONE;
776 DLIST_REMOVE(p->pending, req);
777 if (req->async.callback) {
778 req->async.callback(req);
783 if (pkt.ptype == DCERPC_PKT_FAULT) {
784 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
785 req->fault_code = pkt.u.fault.status;
786 req->status = NT_STATUS_NET_WRITE_FAULT;
787 req->state = RPC_REQUEST_DONE;
788 DLIST_REMOVE(p->pending, req);
789 if (req->async.callback) {
790 req->async.callback(req);
795 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
796 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
798 req->fault_code = DCERPC_FAULT_OTHER;
799 req->status = NT_STATUS_NET_WRITE_FAULT;
800 req->state = RPC_REQUEST_DONE;
801 DLIST_REMOVE(p->pending, req);
802 if (req->async.callback) {
803 req->async.callback(req);
808 length = pkt.u.response.stub_and_verifier.length;
811 req->payload.data = talloc_realloc(req,
813 req->payload.length + length);
814 if (!req->payload.data) {
815 req->status = NT_STATUS_NO_MEMORY;
816 req->state = RPC_REQUEST_DONE;
817 DLIST_REMOVE(p->pending, req);
818 if (req->async.callback) {
819 req->async.callback(req);
823 memcpy(req->payload.data+req->payload.length,
824 pkt.u.response.stub_and_verifier.data, length);
825 req->payload.length += length;
828 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
829 p->transport.send_read(p);
833 /* we've got the full payload */
834 req->state = RPC_REQUEST_DONE;
835 DLIST_REMOVE(p->pending, req);
837 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
838 req->flags |= DCERPC_PULL_BIGENDIAN;
840 req->flags &= ~DCERPC_PULL_BIGENDIAN;
843 if (req->async.callback) {
844 req->async.callback(req);
850 make sure requests are cleaned up
852 static int dcerpc_req_destructor(void *ptr)
854 struct rpc_request *req = ptr;
855 DLIST_REMOVE(req->p->pending, req);
860 perform the send size of a async dcerpc request
862 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
863 const struct GUID *object,
866 DATA_BLOB *stub_data)
868 struct rpc_request *req;
869 struct dcerpc_packet pkt;
871 uint32_t remaining, chunk_size;
872 BOOL first_packet = True;
874 p->transport.recv_data = dcerpc_request_recv_data;
876 req = talloc_p(mem_ctx, struct rpc_request);
882 req->call_id = next_call_id(p);
883 req->status = NT_STATUS_OK;
884 req->state = RPC_REQUEST_PENDING;
885 req->payload = data_blob(NULL, 0);
888 req->async.callback = NULL;
890 init_dcerpc_hdr(p, &pkt);
892 remaining = stub_data->length;
894 /* we can write a full max_recv_frag size, minus the dcerpc
895 request header size */
896 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
898 pkt.ptype = DCERPC_PKT_REQUEST;
899 pkt.call_id = req->call_id;
902 pkt.u.request.alloc_hint = remaining;
903 pkt.u.request.context_id = 0;
904 pkt.u.request.opnum = opnum;
907 pkt.u.request.object.object = *object;
908 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
909 chunk_size -= ndr_size_GUID(0,object,0);
912 DLIST_ADD(p->pending, req);
914 /* we send a series of pdus without waiting for a reply */
915 while (remaining > 0 || first_packet) {
916 uint32_t chunk = MIN(chunk_size, remaining);
917 BOOL last_frag = False;
919 first_packet = False;
920 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
922 if (remaining == stub_data->length) {
923 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
925 if (chunk == remaining) {
926 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
930 pkt.u.request.stub_and_verifier.data = stub_data->data +
931 (stub_data->length - remaining);
932 pkt.u.request.stub_and_verifier.length = chunk;
934 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
935 if (!NT_STATUS_IS_OK(req->status)) {
936 req->state = RPC_REQUEST_DONE;
937 DLIST_REMOVE(p->pending, req);
941 req->status = p->transport.send_request(p, &blob, last_frag);
942 if (!NT_STATUS_IS_OK(req->status)) {
943 req->state = RPC_REQUEST_DONE;
944 DLIST_REMOVE(p->pending, req);
951 talloc_set_destructor(req, dcerpc_req_destructor);
957 return the event context for a dcerpc pipe
958 used by callers who wish to operate asynchronously
960 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
962 return p->transport.event_context(p);
968 perform the receive side of a async dcerpc request
970 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
972 DATA_BLOB *stub_data)
976 while (req->state == RPC_REQUEST_PENDING) {
977 struct event_context *ctx = dcerpc_event_context(req->p);
978 if (event_loop_once(ctx) != 0) {
979 return NT_STATUS_CONNECTION_DISCONNECTED;
982 *stub_data = req->payload;
983 status = req->status;
984 if (stub_data->data) {
985 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
987 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
988 req->p->last_fault_code = req->fault_code;
995 perform a full request/response pair on a dcerpc pipe
997 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1000 TALLOC_CTX *mem_ctx,
1001 DATA_BLOB *stub_data_in,
1002 DATA_BLOB *stub_data_out)
1004 struct rpc_request *req;
1006 req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
1008 return NT_STATUS_NO_MEMORY;
1011 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1016 this is a paranoid NDR validator. For every packet we push onto the wire
1017 we pull it back again, then push it again. Then we compare the raw NDR data
1018 for that to the NDR we initially generated. If they don't match then we know
1019 we must have a bug in either the pull or push side of our code
1021 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
1022 TALLOC_CTX *mem_ctx,
1025 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1026 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1029 struct ndr_pull *pull;
1030 struct ndr_push *push;
1034 st = talloc(mem_ctx, struct_size);
1036 return NT_STATUS_NO_MEMORY;
1039 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1041 return NT_STATUS_NO_MEMORY;
1044 status = ndr_pull(pull, NDR_IN, st);
1045 if (!NT_STATUS_IS_OK(status)) {
1046 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1047 "failed input validation pull - %s",
1051 push = ndr_push_init_ctx(mem_ctx);
1053 return NT_STATUS_NO_MEMORY;
1056 status = ndr_push(push, NDR_IN, st);
1057 if (!NT_STATUS_IS_OK(status)) {
1058 return ndr_push_error(push, NDR_ERR_VALIDATE,
1059 "failed input validation push - %s",
1063 blob2 = ndr_push_blob(push);
1065 if (!data_blob_equal(&blob, &blob2)) {
1066 DEBUG(3,("original:\n"));
1067 dump_data(3, blob.data, blob.length);
1068 DEBUG(3,("secondary:\n"));
1069 dump_data(3, blob2.data, blob2.length);
1070 return ndr_push_error(push, NDR_ERR_VALIDATE,
1071 "failed input validation data - %s",
1075 return NT_STATUS_OK;
1079 this is a paranoid NDR input validator. For every packet we pull
1080 from the wire we push it back again then pull and push it
1081 again. Then we compare the raw NDR data for that to the NDR we
1082 initially generated. If they don't match then we know we must have a
1083 bug in either the pull or push side of our code
1085 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1086 TALLOC_CTX *mem_ctx,
1089 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1090 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1093 struct ndr_pull *pull;
1094 struct ndr_push *push;
1096 DATA_BLOB blob, blob2;
1098 st = talloc(mem_ctx, struct_size);
1100 return NT_STATUS_NO_MEMORY;
1102 memcpy(st, struct_ptr, struct_size);
1104 push = ndr_push_init_ctx(mem_ctx);
1106 return NT_STATUS_NO_MEMORY;
1109 status = ndr_push(push, NDR_OUT, struct_ptr);
1110 if (!NT_STATUS_IS_OK(status)) {
1111 return ndr_push_error(push, NDR_ERR_VALIDATE,
1112 "failed output validation push - %s",
1116 blob = ndr_push_blob(push);
1118 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1120 return NT_STATUS_NO_MEMORY;
1123 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1124 status = ndr_pull(pull, NDR_OUT, st);
1125 if (!NT_STATUS_IS_OK(status)) {
1126 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1127 "failed output validation pull - %s",
1131 push = ndr_push_init_ctx(mem_ctx);
1133 return NT_STATUS_NO_MEMORY;
1136 status = ndr_push(push, NDR_OUT, st);
1137 if (!NT_STATUS_IS_OK(status)) {
1138 return ndr_push_error(push, NDR_ERR_VALIDATE,
1139 "failed output validation push2 - %s",
1143 blob2 = ndr_push_blob(push);
1145 if (!data_blob_equal(&blob, &blob2)) {
1146 DEBUG(3,("original:\n"));
1147 dump_data(3, blob.data, blob.length);
1148 DEBUG(3,("secondary:\n"));
1149 dump_data(3, blob2.data, blob2.length);
1150 return ndr_push_error(push, NDR_ERR_VALIDATE,
1151 "failed output validation data - %s",
1155 return NT_STATUS_OK;
1160 send a rpc request given a dcerpc_call structure
1162 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1163 const struct GUID *object,
1164 const struct dcerpc_interface_table *table,
1166 TALLOC_CTX *mem_ctx,
1169 const struct dcerpc_interface_call *call;
1170 struct ndr_push *push;
1173 struct rpc_request *req;
1175 call = &table->calls[opnum];
1177 /* setup for a ndr_push_* call */
1178 push = ndr_push_init();
1183 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1184 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1187 /* push the structure into a blob */
1188 status = call->ndr_push(push, NDR_IN, r);
1189 if (!NT_STATUS_IS_OK(status)) {
1190 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1191 nt_errstr(status)));
1192 ndr_push_free(push);
1196 /* retrieve the blob */
1197 request = ndr_push_blob(push);
1199 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1200 status = dcerpc_ndr_validate_in(p, mem_ctx, request, call->struct_size,
1201 call->ndr_push, call->ndr_pull);
1202 if (!NT_STATUS_IS_OK(status)) {
1203 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1204 nt_errstr(status)));
1205 ndr_push_free(push);
1210 DEBUG(10,("rpc request data:\n"));
1211 dump_data(10, request.data, request.length);
1213 /* make the actual dcerpc request */
1214 req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1217 req->ndr.table = table;
1218 req->ndr.opnum = opnum;
1219 req->ndr.struct_ptr = r;
1220 req->ndr.mem_ctx = mem_ctx;
1223 ndr_push_free(push);
1229 receive the answer from a dcerpc_ndr_request_send()
1231 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1233 struct dcerpc_pipe *p = req->p;
1236 struct ndr_pull *pull;
1238 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1239 void *r = req->ndr.struct_ptr;
1240 uint32_t opnum = req->ndr.opnum;
1241 const struct dcerpc_interface_table *table = req->ndr.table;
1242 const struct dcerpc_interface_call *call = &table->calls[opnum];
1244 /* make sure the recv code doesn't free the request, as we
1245 need to grab the flags element before it is freed */
1246 talloc_increase_ref_count(req);
1248 status = dcerpc_request_recv(req, mem_ctx, &response);
1249 if (!NT_STATUS_IS_OK(status)) {
1256 /* prepare for ndr_pull_* */
1257 pull = ndr_pull_init_flags(p, &response, mem_ctx);
1259 return NT_STATUS_NO_MEMORY;
1262 if (flags & DCERPC_PULL_BIGENDIAN) {
1263 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1266 DEBUG(10,("rpc reply data:\n"));
1267 dump_data(10, pull->data, pull->data_size);
1269 /* pull the structure from the blob */
1270 status = call->ndr_pull(pull, NDR_OUT, r);
1271 if (!NT_STATUS_IS_OK(status)) {
1272 dcerpc_log_packet(table, opnum, NDR_OUT,
1277 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1278 status = dcerpc_ndr_validate_out(p, mem_ctx, r, call->struct_size,
1279 call->ndr_push, call->ndr_pull);
1280 if (!NT_STATUS_IS_OK(status)) {
1281 dcerpc_log_packet(table, opnum, NDR_OUT,
1287 if (pull->offset != pull->data_size) {
1288 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1289 pull->data_size - pull->offset));
1290 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1291 but it turns out that early versions of NT
1292 (specifically NT3.1) add junk onto the end of rpc
1293 packets, so if we want to interoperate at all with
1294 those versions then we need to ignore this error */
1297 return NT_STATUS_OK;
1302 a useful helper function for synchronous rpc requests
1304 this can be used when you have ndr push/pull functions in the
1307 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1308 const struct GUID *object,
1309 const struct dcerpc_interface_table *table,
1311 TALLOC_CTX *mem_ctx,
1314 struct rpc_request *req;
1316 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1318 return NT_STATUS_NO_MEMORY;
1321 return dcerpc_ndr_request_recv(req);
1326 a useful function for retrieving the server name we connected to
1328 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1330 if (!p->transport.peer_name) {
1333 return p->transport.peer_name(p);
1337 a useful function to get the auth_level
1340 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1344 if (p->flags & DCERPC_SEAL) {
1345 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1346 } else if (p->flags & DCERPC_SIGN) {
1347 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1348 } else if (p->flags & DCERPC_CONNECT) {
1349 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1351 auth_level = DCERPC_AUTH_LEVEL_NONE;