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(talloc_autofree_context(),
33 struct dcerpc_interface_list);
35 if (idl_iface_by_name (interface->name) != NULL) {
36 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
37 return NT_STATUS_OBJECT_NAME_COLLISION;
41 DLIST_ADD(dcerpc_pipes, l);
46 /* initialise a dcerpc pipe. */
47 struct dcerpc_pipe *dcerpc_pipe_init(void)
49 struct dcerpc_pipe *p;
51 p = talloc_p(NULL, struct dcerpc_pipe);
56 p->reference_count = 0;
58 p->security_state.auth_info = NULL;
59 p->security_state.session_key = dcerpc_generic_session_key;
60 p->security_state.generic_state = NULL;
61 p->binding_string = NULL;
63 p->srv_max_xmit_frag = 0;
64 p->srv_max_recv_frag = 0;
65 p->last_fault_code = 0;
72 choose the next call id to use
74 static uint32_t next_call_id(struct dcerpc_pipe *p)
77 if (p->call_id == 0) {
83 /* close down a dcerpc over SMB pipe */
84 void dcerpc_pipe_close(struct dcerpc_pipe *p)
88 if (p->reference_count <= 0) {
89 p->transport.shutdown_pipe(p);
94 /* we need to be able to get/set the fragment length without doing a full
96 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
98 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
99 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
101 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
105 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
107 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
108 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
110 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
114 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
116 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
117 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
119 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
125 setup for a ndr pull, also setting up any flags from the binding string
127 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
129 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
131 if (ndr == NULL) return ndr;
133 if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
134 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
137 if (p->flags & DCERPC_NDR_REF_ALLOC) {
138 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
145 parse a data blob into a dcerpc_packet structure. This handles both
146 input and output packets
148 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
149 struct dcerpc_packet *pkt)
151 struct ndr_pull *ndr;
153 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
155 return NT_STATUS_NO_MEMORY;
158 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
159 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
162 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
166 generate a CONNECT level verifier
168 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
170 *blob = data_blob_talloc(mem_ctx, NULL, 16);
171 if (blob->data == NULL) {
172 return NT_STATUS_NO_MEMORY;
174 SIVAL(blob->data, 0, 1);
175 memset(blob->data+4, 0, 12);
180 generate a CONNECT level verifier
182 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
184 if (blob->length != 16 ||
185 IVAL(blob->data, 0) != 1) {
186 return NT_STATUS_ACCESS_DENIED;
192 parse a possibly signed blob into a dcerpc request packet structure
194 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
195 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
196 struct dcerpc_packet *pkt)
198 struct ndr_pull *ndr;
200 struct dcerpc_auth auth;
203 /* non-signed packets are simpler */
204 if (!p->security_state.auth_info ||
205 !p->security_state.generic_state) {
206 return dcerpc_pull(p, blob, mem_ctx, pkt);
209 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
211 return NT_STATUS_NO_MEMORY;
214 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
215 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
218 /* pull the basic packet */
219 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
220 if (!NT_STATUS_IS_OK(status)) {
224 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
228 if (pkt->auth_length == 0 &&
229 p->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
233 auth_blob.length = 8 + pkt->auth_length;
235 /* check for a valid length */
236 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
237 return NT_STATUS_INFO_LENGTH_MISMATCH;
241 pkt->u.response.stub_and_verifier.data +
242 pkt->u.response.stub_and_verifier.length - auth_blob.length;
243 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
245 /* pull the auth structure */
246 ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
248 return NT_STATUS_NO_MEMORY;
251 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
252 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
255 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
256 if (!NT_STATUS_IS_OK(status)) {
261 /* check signature or unseal the packet */
262 switch (p->security_state.auth_info->auth_level) {
263 case DCERPC_AUTH_LEVEL_PRIVACY:
264 status = gensec_unseal_packet(p->security_state.generic_state,
266 blob->data + DCERPC_REQUEST_LENGTH,
267 pkt->u.response.stub_and_verifier.length,
269 blob->length - auth.credentials.length,
271 memcpy(pkt->u.response.stub_and_verifier.data,
272 blob->data + DCERPC_REQUEST_LENGTH,
273 pkt->u.response.stub_and_verifier.length);
276 case DCERPC_AUTH_LEVEL_INTEGRITY:
277 status = gensec_check_packet(p->security_state.generic_state,
279 pkt->u.response.stub_and_verifier.data,
280 pkt->u.response.stub_and_verifier.length,
282 blob->length - auth.credentials.length,
286 case DCERPC_AUTH_LEVEL_CONNECT:
287 status = dcerpc_check_connect_verifier(&auth.credentials);
290 case DCERPC_AUTH_LEVEL_NONE:
294 status = NT_STATUS_INVALID_LEVEL;
298 /* remove the indicated amount of paddiing */
299 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
300 return NT_STATUS_INFO_LENGTH_MISMATCH;
302 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
309 push a dcerpc request packet into a blob, possibly signing it.
311 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
312 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
313 struct dcerpc_packet *pkt)
316 struct ndr_push *ndr;
319 /* non-signed packets are simpler */
320 if (!p->security_state.auth_info ||
321 !p->security_state.generic_state) {
322 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
325 ndr = ndr_push_init_ctx(mem_ctx);
327 return NT_STATUS_NO_MEMORY;
330 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
331 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
334 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
335 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
338 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
339 if (!NT_STATUS_IS_OK(status)) {
343 /* pad to 16 byte multiple in the payload portion of the
344 packet. This matches what w2k3 does */
345 p->security_state.auth_info->auth_pad_length =
346 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
347 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
349 /* sign or seal the packet */
350 switch (p->security_state.auth_info->auth_level) {
351 case DCERPC_AUTH_LEVEL_PRIVACY:
352 case DCERPC_AUTH_LEVEL_INTEGRITY:
353 p->security_state.auth_info->credentials
354 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
355 data_blob_clear(&p->security_state.auth_info->credentials);
358 case DCERPC_AUTH_LEVEL_CONNECT:
359 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
362 case DCERPC_AUTH_LEVEL_NONE:
363 p->security_state.auth_info->credentials = data_blob(NULL, 0);
367 status = NT_STATUS_INVALID_LEVEL;
371 if (!NT_STATUS_IS_OK(status)) {
375 /* add the auth verifier */
376 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
377 if (!NT_STATUS_IS_OK(status)) {
381 /* extract the whole packet as a blob */
382 *blob = ndr_push_blob(ndr);
384 /* fill in the fragment length and auth_length, we can't fill
385 in these earlier as we don't know the signature length (it
386 could be variable length) */
387 dcerpc_set_frag_length(blob, blob->length);
388 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
390 /* sign or seal the packet */
391 switch (p->security_state.auth_info->auth_level) {
392 case DCERPC_AUTH_LEVEL_PRIVACY:
393 status = gensec_seal_packet(p->security_state.generic_state,
395 blob->data + DCERPC_REQUEST_LENGTH,
396 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
399 p->security_state.auth_info->credentials.length,
401 if (!NT_STATUS_IS_OK(status)) {
404 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
407 case DCERPC_AUTH_LEVEL_INTEGRITY:
408 status = gensec_sign_packet(p->security_state.generic_state,
410 blob->data + DCERPC_REQUEST_LENGTH,
411 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
414 p->security_state.auth_info->credentials.length,
416 if (!NT_STATUS_IS_OK(status)) {
419 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
422 case DCERPC_AUTH_LEVEL_CONNECT:
425 case DCERPC_AUTH_LEVEL_NONE:
426 p->security_state.auth_info->credentials = data_blob(NULL, 0);
430 status = NT_STATUS_INVALID_LEVEL;
434 data_blob_free(&p->security_state.auth_info->credentials);
441 fill in the fixed values in a dcerpc header
443 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
446 pkt->rpc_vers_minor = 0;
447 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
450 pkt->drep[0] = DCERPC_DREP_LE;
458 hold the state of pending full requests
460 struct full_request_state {
461 DATA_BLOB *reply_blob;
466 receive a reply to a full request
468 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
471 struct full_request_state *state = p->full_request_private;
473 if (!NT_STATUS_IS_OK(status)) {
474 state->status = status;
477 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
478 state->reply_blob = NULL;
482 perform a single pdu synchronous request - used for the bind code
483 this cannot be mixed with normal async requests
485 static NTSTATUS full_request(struct dcerpc_pipe *p,
487 DATA_BLOB *request_blob,
488 DATA_BLOB *reply_blob)
490 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
494 return NT_STATUS_NO_MEMORY;
497 state->reply_blob = reply_blob;
498 state->status = NT_STATUS_OK;
500 p->transport.recv_data = full_request_recv;
501 p->full_request_private = state;
503 status = p->transport.send_request(p, request_blob, True);
504 if (!NT_STATUS_IS_OK(status)) {
508 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
509 struct event_context *ctx = p->transport.event_context(p);
510 if (event_loop_once(ctx) != 0) {
511 return NT_STATUS_CONNECTION_DISCONNECTED;
515 return state->status;
520 perform a bind using the given syntax
522 the auth_info structure is updated with the reply authentication info
525 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
527 const struct dcerpc_syntax_id *syntax,
528 const struct dcerpc_syntax_id *transfer_syntax)
530 struct dcerpc_packet pkt;
535 p->transfer_syntax = *transfer_syntax;
537 init_dcerpc_hdr(p, &pkt);
539 pkt.ptype = DCERPC_PKT_BIND;
540 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
541 pkt.call_id = p->call_id;
544 pkt.u.bind.max_xmit_frag = 5840;
545 pkt.u.bind.max_recv_frag = 5840;
546 pkt.u.bind.assoc_group_id = 0;
547 pkt.u.bind.num_contexts = 1;
548 pkt.u.bind.ctx_list = talloc_p(mem_ctx, struct dcerpc_ctx_list);
549 if (!pkt.u.bind.ctx_list) {
550 return NT_STATUS_NO_MEMORY;
552 pkt.u.bind.ctx_list[0].context_id = 0;
553 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
554 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
555 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
556 pkt.u.bind.auth_info = data_blob(NULL, 0);
558 /* construct the NDR form of the packet */
559 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
560 if (!NT_STATUS_IS_OK(status)) {
564 /* send it on its way */
565 status = full_request(p, mem_ctx, &blob, &blob);
566 if (!NT_STATUS_IS_OK(status)) {
570 /* unmarshall the NDR */
571 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
572 if (!NT_STATUS_IS_OK(status)) {
576 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
577 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
578 return NT_STATUS_ACCESS_DENIED;
581 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
582 pkt.u.bind_ack.num_results == 0 ||
583 pkt.u.bind_ack.ctx_list[0].result != 0) {
584 return NT_STATUS_UNSUCCESSFUL;
587 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
588 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
589 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
592 /* the bind_ack might contain a reply set of credentials */
593 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
594 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
596 p->security_state.auth_info,
597 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
604 perform a alter context using the given syntax
606 the auth_info structure is updated with the reply authentication info
609 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
612 struct dcerpc_packet pkt;
616 init_dcerpc_hdr(p, &pkt);
618 pkt.ptype = DCERPC_PKT_ALTER;
619 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
620 pkt.call_id = p->call_id;
623 pkt.u.alter.max_xmit_frag = 0x2000;
624 pkt.u.alter.max_recv_frag = 0x2000;
625 pkt.u.alter.assoc_group_id = 0;
626 pkt.u.alter.num_contexts = 1;
627 pkt.u.alter.ctx_list = talloc_p(mem_ctx, struct dcerpc_ctx_list);
628 if (!pkt.u.alter.ctx_list) {
629 return NT_STATUS_NO_MEMORY;
631 pkt.u.alter.ctx_list[0].context_id = 0;
632 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
633 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
634 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
635 pkt.u.alter.auth_info = data_blob(NULL, 0);
637 /* construct the NDR form of the packet */
638 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
639 if (!NT_STATUS_IS_OK(status)) {
643 /* send it on its way */
644 status = full_request(p, mem_ctx, &blob, &blob);
645 if (!NT_STATUS_IS_OK(status)) {
649 /* unmarshall the NDR */
650 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
651 if (!NT_STATUS_IS_OK(status)) {
655 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
656 pkt.u.alter_ack.num_results == 0 ||
657 pkt.u.alter_ack.ctx_list[0].result != 0) {
658 status = NT_STATUS_UNSUCCESSFUL;
661 /* the bind_ack might contain a reply set of credentials */
662 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
663 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
665 p->security_state.auth_info,
666 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
673 perform a continued bind (and auth3)
675 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
678 struct dcerpc_packet pkt;
682 init_dcerpc_hdr(p, &pkt);
684 pkt.ptype = DCERPC_PKT_AUTH3;
685 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
686 pkt.call_id = next_call_id(p);
688 pkt.u.auth3._pad = 0;
689 pkt.u.auth3.auth_info = data_blob(NULL, 0);
691 /* construct the NDR form of the packet */
692 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
693 if (!NT_STATUS_IS_OK(status)) {
697 /* send it on its way */
698 status = p->transport.send_request(p, &blob, False);
699 if (!NT_STATUS_IS_OK(status)) {
707 /* perform a dcerpc bind, using the uuid as the key */
708 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
710 const char *uuid, uint_t version)
712 struct dcerpc_syntax_id syntax;
713 struct dcerpc_syntax_id transfer_syntax;
716 status = GUID_from_string(uuid, &syntax.uuid);
717 if (!NT_STATUS_IS_OK(status)) {
718 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
721 syntax.if_version = version;
723 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
724 if (!NT_STATUS_IS_OK(status)) {
727 transfer_syntax.if_version = NDR_GUID_VERSION;
729 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
733 process a fragment received from the transport layer during a
736 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
740 struct dcerpc_packet pkt;
741 struct rpc_request *req;
744 if (!NT_STATUS_IS_OK(status)) {
745 /* all pending requests get the error */
748 req->state = RPC_REQUEST_DONE;
749 req->status = status;
750 DLIST_REMOVE(p->pending, req);
751 if (req->async.callback) {
752 req->async.callback(req);
760 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
762 /* find the matching request. Notice we match before we check
763 the status. this is ok as a pending call_id can never be
765 for (req=p->pending;req;req=req->next) {
766 if (pkt.call_id == req->call_id) break;
770 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
774 if (!NT_STATUS_IS_OK(status)) {
775 req->status = status;
776 req->state = RPC_REQUEST_DONE;
777 DLIST_REMOVE(p->pending, req);
778 if (req->async.callback) {
779 req->async.callback(req);
784 if (pkt.ptype == DCERPC_PKT_FAULT) {
785 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
786 req->fault_code = pkt.u.fault.status;
787 req->status = NT_STATUS_NET_WRITE_FAULT;
788 req->state = RPC_REQUEST_DONE;
789 DLIST_REMOVE(p->pending, req);
790 if (req->async.callback) {
791 req->async.callback(req);
796 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
797 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
799 req->fault_code = DCERPC_FAULT_OTHER;
800 req->status = NT_STATUS_NET_WRITE_FAULT;
801 req->state = RPC_REQUEST_DONE;
802 DLIST_REMOVE(p->pending, req);
803 if (req->async.callback) {
804 req->async.callback(req);
809 length = pkt.u.response.stub_and_verifier.length;
812 req->payload.data = talloc_realloc(req,
814 req->payload.length + length);
815 if (!req->payload.data) {
816 req->status = NT_STATUS_NO_MEMORY;
817 req->state = RPC_REQUEST_DONE;
818 DLIST_REMOVE(p->pending, req);
819 if (req->async.callback) {
820 req->async.callback(req);
824 memcpy(req->payload.data+req->payload.length,
825 pkt.u.response.stub_and_verifier.data, length);
826 req->payload.length += length;
829 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
830 p->transport.send_read(p);
834 /* we've got the full payload */
835 req->state = RPC_REQUEST_DONE;
836 DLIST_REMOVE(p->pending, req);
838 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
839 req->flags |= DCERPC_PULL_BIGENDIAN;
841 req->flags &= ~DCERPC_PULL_BIGENDIAN;
844 if (req->async.callback) {
845 req->async.callback(req);
851 make sure requests are cleaned up
853 static int dcerpc_req_destructor(void *ptr)
855 struct rpc_request *req = ptr;
856 DLIST_REMOVE(req->p->pending, req);
861 perform the send size of a async dcerpc request
863 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
864 const struct GUID *object,
867 DATA_BLOB *stub_data)
869 struct rpc_request *req;
870 struct dcerpc_packet pkt;
872 uint32_t remaining, chunk_size;
873 BOOL first_packet = True;
875 p->transport.recv_data = dcerpc_request_recv_data;
877 req = talloc_p(mem_ctx, struct rpc_request);
883 req->call_id = next_call_id(p);
884 req->status = NT_STATUS_OK;
885 req->state = RPC_REQUEST_PENDING;
886 req->payload = data_blob(NULL, 0);
889 req->async.callback = NULL;
891 init_dcerpc_hdr(p, &pkt);
893 remaining = stub_data->length;
895 /* we can write a full max_recv_frag size, minus the dcerpc
896 request header size */
897 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
899 pkt.ptype = DCERPC_PKT_REQUEST;
900 pkt.call_id = req->call_id;
903 pkt.u.request.alloc_hint = remaining;
904 pkt.u.request.context_id = 0;
905 pkt.u.request.opnum = opnum;
908 pkt.u.request.object.object = *object;
909 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
910 chunk_size -= ndr_size_GUID(object,0);
913 DLIST_ADD(p->pending, req);
915 /* we send a series of pdus without waiting for a reply */
916 while (remaining > 0 || first_packet) {
917 uint32_t chunk = MIN(chunk_size, remaining);
918 BOOL last_frag = False;
920 first_packet = False;
921 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
923 if (remaining == stub_data->length) {
924 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
926 if (chunk == remaining) {
927 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
931 pkt.u.request.stub_and_verifier.data = stub_data->data +
932 (stub_data->length - remaining);
933 pkt.u.request.stub_and_verifier.length = chunk;
935 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
936 if (!NT_STATUS_IS_OK(req->status)) {
937 req->state = RPC_REQUEST_DONE;
938 DLIST_REMOVE(p->pending, req);
942 req->status = p->transport.send_request(p, &blob, last_frag);
943 if (!NT_STATUS_IS_OK(req->status)) {
944 req->state = RPC_REQUEST_DONE;
945 DLIST_REMOVE(p->pending, req);
952 talloc_set_destructor(req, dcerpc_req_destructor);
958 return the event context for a dcerpc pipe
959 used by callers who wish to operate asynchronously
961 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
963 return p->transport.event_context(p);
969 perform the receive side of a async dcerpc request
971 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
973 DATA_BLOB *stub_data)
977 while (req->state == RPC_REQUEST_PENDING) {
978 struct event_context *ctx = dcerpc_event_context(req->p);
979 if (event_loop_once(ctx) != 0) {
980 return NT_STATUS_CONNECTION_DISCONNECTED;
983 *stub_data = req->payload;
984 status = req->status;
985 if (stub_data->data) {
986 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
988 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
989 req->p->last_fault_code = req->fault_code;
996 perform a full request/response pair on a dcerpc pipe
998 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
1001 TALLOC_CTX *mem_ctx,
1002 DATA_BLOB *stub_data_in,
1003 DATA_BLOB *stub_data_out)
1005 struct rpc_request *req;
1007 req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
1009 return NT_STATUS_NO_MEMORY;
1012 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1017 this is a paranoid NDR validator. For every packet we push onto the wire
1018 we pull it back again, then push it again. Then we compare the raw NDR data
1019 for that to the NDR we initially generated. If they don't match then we know
1020 we must have a bug in either the pull or push side of our code
1022 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
1023 TALLOC_CTX *mem_ctx,
1026 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1027 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1030 struct ndr_pull *pull;
1031 struct ndr_push *push;
1035 st = talloc(mem_ctx, struct_size);
1037 return NT_STATUS_NO_MEMORY;
1040 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1042 return NT_STATUS_NO_MEMORY;
1045 status = ndr_pull(pull, NDR_IN, st);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1048 "failed input validation pull - %s",
1052 push = ndr_push_init_ctx(mem_ctx);
1054 return NT_STATUS_NO_MEMORY;
1057 status = ndr_push(push, NDR_IN, st);
1058 if (!NT_STATUS_IS_OK(status)) {
1059 return ndr_push_error(push, NDR_ERR_VALIDATE,
1060 "failed input validation push - %s",
1064 blob2 = ndr_push_blob(push);
1066 if (!data_blob_equal(&blob, &blob2)) {
1067 DEBUG(3,("original:\n"));
1068 dump_data(3, blob.data, blob.length);
1069 DEBUG(3,("secondary:\n"));
1070 dump_data(3, blob2.data, blob2.length);
1071 return ndr_push_error(push, NDR_ERR_VALIDATE,
1072 "failed input validation data - %s",
1076 return NT_STATUS_OK;
1080 this is a paranoid NDR input validator. For every packet we pull
1081 from the wire we push it back again then pull and push it
1082 again. Then we compare the raw NDR data for that to the NDR we
1083 initially generated. If they don't match then we know we must have a
1084 bug in either the pull or push side of our code
1086 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1087 TALLOC_CTX *mem_ctx,
1090 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1091 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1094 struct ndr_pull *pull;
1095 struct ndr_push *push;
1097 DATA_BLOB blob, blob2;
1099 st = talloc(mem_ctx, struct_size);
1101 return NT_STATUS_NO_MEMORY;
1103 memcpy(st, struct_ptr, struct_size);
1105 push = ndr_push_init_ctx(mem_ctx);
1107 return NT_STATUS_NO_MEMORY;
1110 status = ndr_push(push, NDR_OUT, struct_ptr);
1111 if (!NT_STATUS_IS_OK(status)) {
1112 return ndr_push_error(push, NDR_ERR_VALIDATE,
1113 "failed output validation push - %s",
1117 blob = ndr_push_blob(push);
1119 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1121 return NT_STATUS_NO_MEMORY;
1124 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1125 status = ndr_pull(pull, NDR_OUT, st);
1126 if (!NT_STATUS_IS_OK(status)) {
1127 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1128 "failed output validation pull - %s",
1132 push = ndr_push_init_ctx(mem_ctx);
1134 return NT_STATUS_NO_MEMORY;
1137 status = ndr_push(push, NDR_OUT, st);
1138 if (!NT_STATUS_IS_OK(status)) {
1139 return ndr_push_error(push, NDR_ERR_VALIDATE,
1140 "failed output validation push2 - %s",
1144 blob2 = ndr_push_blob(push);
1146 if (!data_blob_equal(&blob, &blob2)) {
1147 DEBUG(3,("original:\n"));
1148 dump_data(3, blob.data, blob.length);
1149 DEBUG(3,("secondary:\n"));
1150 dump_data(3, blob2.data, blob2.length);
1151 return ndr_push_error(push, NDR_ERR_VALIDATE,
1152 "failed output validation data - %s",
1156 return NT_STATUS_OK;
1161 send a rpc request given a dcerpc_call structure
1163 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1164 const struct GUID *object,
1165 const struct dcerpc_interface_table *table,
1167 TALLOC_CTX *mem_ctx,
1170 const struct dcerpc_interface_call *call;
1171 struct ndr_push *push;
1174 struct rpc_request *req;
1176 call = &table->calls[opnum];
1178 /* setup for a ndr_push_* call */
1179 push = ndr_push_init();
1184 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1185 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1188 /* push the structure into a blob */
1189 status = call->ndr_push(push, NDR_IN, r);
1190 if (!NT_STATUS_IS_OK(status)) {
1191 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1192 nt_errstr(status)));
1193 ndr_push_free(push);
1197 /* retrieve the blob */
1198 request = ndr_push_blob(push);
1200 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1201 status = dcerpc_ndr_validate_in(p, mem_ctx, request, call->struct_size,
1202 call->ndr_push, call->ndr_pull);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1205 nt_errstr(status)));
1206 ndr_push_free(push);
1211 DEBUG(10,("rpc request data:\n"));
1212 dump_data(10, request.data, request.length);
1214 /* make the actual dcerpc request */
1215 req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1218 req->ndr.table = table;
1219 req->ndr.opnum = opnum;
1220 req->ndr.struct_ptr = r;
1221 req->ndr.mem_ctx = mem_ctx;
1224 ndr_push_free(push);
1230 receive the answer from a dcerpc_ndr_request_send()
1232 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1234 struct dcerpc_pipe *p = req->p;
1237 struct ndr_pull *pull;
1239 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1240 void *r = req->ndr.struct_ptr;
1241 uint32_t opnum = req->ndr.opnum;
1242 const struct dcerpc_interface_table *table = req->ndr.table;
1243 const struct dcerpc_interface_call *call = &table->calls[opnum];
1245 /* make sure the recv code doesn't free the request, as we
1246 need to grab the flags element before it is freed */
1247 talloc_increase_ref_count(req);
1249 status = dcerpc_request_recv(req, mem_ctx, &response);
1250 if (!NT_STATUS_IS_OK(status)) {
1257 /* prepare for ndr_pull_* */
1258 pull = ndr_pull_init_flags(p, &response, mem_ctx);
1260 return NT_STATUS_NO_MEMORY;
1263 if (flags & DCERPC_PULL_BIGENDIAN) {
1264 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1267 DEBUG(10,("rpc reply data:\n"));
1268 dump_data(10, pull->data, pull->data_size);
1270 /* pull the structure from the blob */
1271 status = call->ndr_pull(pull, NDR_OUT, r);
1272 if (!NT_STATUS_IS_OK(status)) {
1273 dcerpc_log_packet(table, opnum, NDR_OUT,
1278 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1279 status = dcerpc_ndr_validate_out(p, mem_ctx, r, call->struct_size,
1280 call->ndr_push, call->ndr_pull);
1281 if (!NT_STATUS_IS_OK(status)) {
1282 dcerpc_log_packet(table, opnum, NDR_OUT,
1288 if (pull->offset != pull->data_size) {
1289 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1290 pull->data_size - pull->offset));
1291 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1292 but it turns out that early versions of NT
1293 (specifically NT3.1) add junk onto the end of rpc
1294 packets, so if we want to interoperate at all with
1295 those versions then we need to ignore this error */
1298 return NT_STATUS_OK;
1303 a useful helper function for synchronous rpc requests
1305 this can be used when you have ndr push/pull functions in the
1308 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1309 const struct GUID *object,
1310 const struct dcerpc_interface_table *table,
1312 TALLOC_CTX *mem_ctx,
1315 struct rpc_request *req;
1317 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1319 return NT_STATUS_NO_MEMORY;
1322 return dcerpc_ndr_request_recv(req);
1327 a useful function for retrieving the server name we connected to
1329 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1331 if (!p->transport.peer_name) {
1334 return p->transport.peer_name(p);
1338 a useful function to get the auth_level
1341 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1345 if (p->flags & DCERPC_SEAL) {
1346 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1347 } else if (p->flags & DCERPC_SIGN) {
1348 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1349 } else if (p->flags & DCERPC_CONNECT) {
1350 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1352 auth_level = DCERPC_AUTH_LEVEL_NONE;