2 Unix SMB/CIFS implementation.
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.
25 #include "dlinklist.h"
26 #include "librpc/gen_ndr/ndr_epmapper.h"
27 #include "librpc/gen_ndr/ndr_dcerpc.h"
29 static struct dcerpc_interface_list *dcerpc_pipes = NULL;
32 register a dcerpc client interface
34 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
36 struct dcerpc_interface_list *l = talloc_p(talloc_autofree_context(),
37 struct dcerpc_interface_list);
39 if (idl_iface_by_name (interface->name) != NULL) {
40 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
41 return NT_STATUS_OBJECT_NAME_COLLISION;
45 DLIST_ADD(dcerpc_pipes, l);
51 return the list of registered dcerpc_pipes
53 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
58 /* destroy a dcerpc connection */
59 static int dcerpc_connection_destructor(void *ptr)
61 struct dcerpc_connection *c = ptr;
62 if (c->transport.shutdown_pipe) {
63 c->transport.shutdown_pipe(c);
69 /* initialise a dcerpc connection. */
70 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx)
72 struct dcerpc_connection *c;
74 c = talloc_zero(mem_ctx, struct dcerpc_connection);
80 c->security_state.auth_info = NULL;
81 c->security_state.session_key = dcerpc_generic_session_key;
82 c->security_state.generic_state = NULL;
83 c->binding_string = NULL;
85 c->srv_max_xmit_frag = 0;
86 c->srv_max_recv_frag = 0;
89 talloc_set_destructor(c, dcerpc_connection_destructor);
94 /* initialise a dcerpc pipe. */
95 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx)
97 struct dcerpc_pipe *p;
99 p = talloc_p(mem_ctx, struct dcerpc_pipe);
104 p->conn = dcerpc_connection_init(p);
105 if (p->conn == NULL) {
110 p->last_fault_code = 0;
113 ZERO_STRUCT(p->syntax);
114 ZERO_STRUCT(p->transfer_syntax);
121 choose the next call id to use
123 static uint32_t next_call_id(struct dcerpc_connection *c)
126 if (c->call_id == 0) {
132 /* close down a dcerpc over SMB pipe */
133 void dcerpc_pipe_close(struct dcerpc_pipe *p)
138 /* we need to be able to get/set the fragment length without doing a full
140 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
142 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
143 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
145 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
149 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
151 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
152 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
154 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
158 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
160 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
161 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
163 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
169 setup for a ndr pull, also setting up any flags from the binding string
171 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
172 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
174 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
176 if (ndr == NULL) return ndr;
178 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
179 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
182 if (c->flags & DCERPC_NDR_REF_ALLOC) {
183 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
190 parse a data blob into a dcerpc_packet structure. This handles both
191 input and output packets
193 static NTSTATUS dcerpc_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
194 struct dcerpc_packet *pkt)
196 struct ndr_pull *ndr;
198 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
200 return NT_STATUS_NO_MEMORY;
203 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
204 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
207 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
211 generate a CONNECT level verifier
213 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
215 *blob = data_blob_talloc(mem_ctx, NULL, 16);
216 if (blob->data == NULL) {
217 return NT_STATUS_NO_MEMORY;
219 SIVAL(blob->data, 0, 1);
220 memset(blob->data+4, 0, 12);
225 check a CONNECT level verifier
227 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
229 if (blob->length != 16 ||
230 IVAL(blob->data, 0) != 1) {
231 return NT_STATUS_ACCESS_DENIED;
237 parse a possibly signed blob into a dcerpc request packet structure
239 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_connection *c,
240 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
241 struct dcerpc_packet *pkt)
243 struct ndr_pull *ndr;
245 struct dcerpc_auth auth;
248 /* non-signed packets are simpler */
249 if (!c->security_state.auth_info ||
250 !c->security_state.generic_state) {
251 return dcerpc_pull(c, blob, mem_ctx, pkt);
254 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
256 return NT_STATUS_NO_MEMORY;
259 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
260 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
263 /* pull the basic packet */
264 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
265 if (!NT_STATUS_IS_OK(status)) {
269 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
273 if (pkt->auth_length == 0 &&
274 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
278 auth_blob.length = 8 + pkt->auth_length;
280 /* check for a valid length */
281 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
282 return NT_STATUS_INFO_LENGTH_MISMATCH;
286 pkt->u.response.stub_and_verifier.data +
287 pkt->u.response.stub_and_verifier.length - auth_blob.length;
288 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
290 /* pull the auth structure */
291 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
293 return NT_STATUS_NO_MEMORY;
296 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
297 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
300 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
301 if (!NT_STATUS_IS_OK(status)) {
306 /* check signature or unseal the packet */
307 switch (c->security_state.auth_info->auth_level) {
308 case DCERPC_AUTH_LEVEL_PRIVACY:
309 status = gensec_unseal_packet(c->security_state.generic_state,
311 blob->data + DCERPC_REQUEST_LENGTH,
312 pkt->u.response.stub_and_verifier.length,
314 blob->length - auth.credentials.length,
316 memcpy(pkt->u.response.stub_and_verifier.data,
317 blob->data + DCERPC_REQUEST_LENGTH,
318 pkt->u.response.stub_and_verifier.length);
321 case DCERPC_AUTH_LEVEL_INTEGRITY:
322 status = gensec_check_packet(c->security_state.generic_state,
324 pkt->u.response.stub_and_verifier.data,
325 pkt->u.response.stub_and_verifier.length,
327 blob->length - auth.credentials.length,
331 case DCERPC_AUTH_LEVEL_CONNECT:
332 status = dcerpc_check_connect_verifier(&auth.credentials);
335 case DCERPC_AUTH_LEVEL_NONE:
339 status = NT_STATUS_INVALID_LEVEL;
343 /* remove the indicated amount of paddiing */
344 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
345 return NT_STATUS_INFO_LENGTH_MISMATCH;
347 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
354 push a dcerpc request packet into a blob, possibly signing it.
356 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_connection *c,
357 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
358 struct dcerpc_packet *pkt)
361 struct ndr_push *ndr;
364 /* non-signed packets are simpler */
365 if (!c->security_state.auth_info ||
366 !c->security_state.generic_state) {
367 return dcerpc_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
370 ndr = ndr_push_init_ctx(mem_ctx);
372 return NT_STATUS_NO_MEMORY;
375 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
376 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
379 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
380 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
383 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
384 if (!NT_STATUS_IS_OK(status)) {
388 /* pad to 16 byte multiple in the payload portion of the
389 packet. This matches what w2k3 does */
390 c->security_state.auth_info->auth_pad_length =
391 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
392 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
394 /* sign or seal the packet */
395 switch (c->security_state.auth_info->auth_level) {
396 case DCERPC_AUTH_LEVEL_PRIVACY:
397 case DCERPC_AUTH_LEVEL_INTEGRITY:
398 c->security_state.auth_info->credentials
399 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state));
400 data_blob_clear(&c->security_state.auth_info->credentials);
403 case DCERPC_AUTH_LEVEL_CONNECT:
404 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
407 case DCERPC_AUTH_LEVEL_NONE:
408 c->security_state.auth_info->credentials = data_blob(NULL, 0);
412 status = NT_STATUS_INVALID_LEVEL;
416 if (!NT_STATUS_IS_OK(status)) {
420 /* add the auth verifier */
421 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
422 if (!NT_STATUS_IS_OK(status)) {
426 /* extract the whole packet as a blob */
427 *blob = ndr_push_blob(ndr);
429 /* fill in the fragment length and auth_length, we can't fill
430 in these earlier as we don't know the signature length (it
431 could be variable length) */
432 dcerpc_set_frag_length(blob, blob->length);
433 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
435 /* sign or seal the packet */
436 switch (c->security_state.auth_info->auth_level) {
437 case DCERPC_AUTH_LEVEL_PRIVACY:
438 status = gensec_seal_packet(c->security_state.generic_state,
440 blob->data + DCERPC_REQUEST_LENGTH,
441 pkt->u.request.stub_and_verifier.length +
442 c->security_state.auth_info->auth_pad_length,
445 c->security_state.auth_info->credentials.length,
447 if (!NT_STATUS_IS_OK(status)) {
450 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
453 case DCERPC_AUTH_LEVEL_INTEGRITY:
454 status = gensec_sign_packet(c->security_state.generic_state,
456 blob->data + DCERPC_REQUEST_LENGTH,
457 pkt->u.request.stub_and_verifier.length +
458 c->security_state.auth_info->auth_pad_length,
461 c->security_state.auth_info->credentials.length,
463 if (!NT_STATUS_IS_OK(status)) {
466 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
469 case DCERPC_AUTH_LEVEL_CONNECT:
472 case DCERPC_AUTH_LEVEL_NONE:
473 c->security_state.auth_info->credentials = data_blob(NULL, 0);
477 status = NT_STATUS_INVALID_LEVEL;
481 data_blob_free(&c->security_state.auth_info->credentials);
488 fill in the fixed values in a dcerpc header
490 static void init_dcerpc_hdr(struct dcerpc_connection *c, struct dcerpc_packet *pkt)
493 pkt->rpc_vers_minor = 0;
494 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
497 pkt->drep[0] = DCERPC_DREP_LE;
505 hold the state of pending full requests
507 struct full_request_state {
508 DATA_BLOB *reply_blob;
513 receive a reply to a full request
515 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob,
518 struct full_request_state *state = c->full_request_private;
520 if (!NT_STATUS_IS_OK(status)) {
521 state->status = status;
524 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
525 state->reply_blob = NULL;
529 perform a single pdu synchronous request - used for the bind code
530 this cannot be mixed with normal async requests
532 static NTSTATUS full_request(struct dcerpc_connection *c,
534 DATA_BLOB *request_blob,
535 DATA_BLOB *reply_blob)
537 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
541 return NT_STATUS_NO_MEMORY;
544 state->reply_blob = reply_blob;
545 state->status = NT_STATUS_OK;
547 c->transport.recv_data = full_request_recv;
548 c->full_request_private = state;
550 status = c->transport.send_request(c, request_blob, True);
551 if (!NT_STATUS_IS_OK(status)) {
555 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
556 struct event_context *ctx = c->transport.event_context(c);
557 if (event_loop_once(ctx) != 0) {
558 return NT_STATUS_CONNECTION_DISCONNECTED;
562 return state->status;
567 perform a bind using the given syntax
569 the auth_info structure is updated with the reply authentication info
572 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
574 const struct dcerpc_syntax_id *syntax,
575 const struct dcerpc_syntax_id *transfer_syntax)
577 struct dcerpc_packet pkt;
582 p->transfer_syntax = *transfer_syntax;
584 init_dcerpc_hdr(p->conn, &pkt);
586 pkt.ptype = DCERPC_PKT_BIND;
587 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
588 pkt.call_id = p->conn->call_id;
591 pkt.u.bind.max_xmit_frag = 5840;
592 pkt.u.bind.max_recv_frag = 5840;
593 pkt.u.bind.assoc_group_id = 0;
594 pkt.u.bind.num_contexts = 1;
595 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
596 if (!pkt.u.bind.ctx_list) {
597 return NT_STATUS_NO_MEMORY;
599 pkt.u.bind.ctx_list[0].context_id = p->context_id;
600 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
601 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
602 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
603 pkt.u.bind.auth_info = data_blob(NULL, 0);
605 /* construct the NDR form of the packet */
606 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
607 if (!NT_STATUS_IS_OK(status)) {
611 /* send it on its way */
612 status = full_request(p->conn, mem_ctx, &blob, &blob);
613 if (!NT_STATUS_IS_OK(status)) {
617 /* unmarshall the NDR */
618 status = dcerpc_pull(p->conn, &blob, mem_ctx, &pkt);
619 if (!NT_STATUS_IS_OK(status)) {
623 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
624 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
625 return NT_STATUS_ACCESS_DENIED;
628 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
629 pkt.u.bind_ack.num_results == 0 ||
630 pkt.u.bind_ack.ctx_list[0].result != 0) {
631 return NT_STATUS_UNSUCCESSFUL;
634 p->conn->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
635 p->conn->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
637 /* the bind_ack might contain a reply set of credentials */
638 if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
639 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
641 p->conn->security_state.auth_info,
642 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
650 perform a continued bind (and auth3)
652 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
655 struct dcerpc_packet pkt;
659 init_dcerpc_hdr(c, &pkt);
661 pkt.ptype = DCERPC_PKT_AUTH3;
662 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
663 pkt.call_id = next_call_id(c);
665 pkt.u.auth3._pad = 0;
666 pkt.u.auth3.auth_info = data_blob(NULL, 0);
668 /* construct the NDR form of the packet */
669 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
670 if (!NT_STATUS_IS_OK(status)) {
674 /* send it on its way */
675 status = c->transport.send_request(c, &blob, False);
676 if (!NT_STATUS_IS_OK(status)) {
684 /* perform a dcerpc bind, using the uuid as the key */
685 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
687 const char *uuid, uint_t version)
689 struct dcerpc_syntax_id syntax;
690 struct dcerpc_syntax_id transfer_syntax;
693 status = GUID_from_string(uuid, &syntax.uuid);
694 if (!NT_STATUS_IS_OK(status)) {
695 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
698 syntax.if_version = version;
700 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
701 if (!NT_STATUS_IS_OK(status)) {
704 transfer_syntax.if_version = NDR_GUID_VERSION;
706 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
710 process a fragment received from the transport layer during a
713 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
717 struct dcerpc_packet pkt;
718 struct rpc_request *req;
721 if (!NT_STATUS_IS_OK(status)) {
722 /* all pending requests get the error */
725 req->state = RPC_REQUEST_DONE;
726 req->status = status;
727 DLIST_REMOVE(c->pending, req);
728 if (req->async.callback) {
729 req->async.callback(req);
737 status = dcerpc_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
739 /* find the matching request. Notice we match before we check
740 the status. this is ok as a pending call_id can never be
742 for (req=c->pending;req;req=req->next) {
743 if (pkt.call_id == req->call_id) break;
747 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
751 if (!NT_STATUS_IS_OK(status)) {
752 req->status = status;
753 req->state = RPC_REQUEST_DONE;
754 DLIST_REMOVE(c->pending, req);
755 if (req->async.callback) {
756 req->async.callback(req);
761 if (pkt.ptype == DCERPC_PKT_FAULT) {
762 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
763 req->fault_code = pkt.u.fault.status;
764 req->status = NT_STATUS_NET_WRITE_FAULT;
765 req->state = RPC_REQUEST_DONE;
766 DLIST_REMOVE(c->pending, req);
767 if (req->async.callback) {
768 req->async.callback(req);
773 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
774 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
776 req->fault_code = DCERPC_FAULT_OTHER;
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);
786 length = pkt.u.response.stub_and_verifier.length;
789 req->payload.data = talloc_realloc(req,
792 req->payload.length + length);
793 if (!req->payload.data) {
794 req->status = NT_STATUS_NO_MEMORY;
795 req->state = RPC_REQUEST_DONE;
796 DLIST_REMOVE(c->pending, req);
797 if (req->async.callback) {
798 req->async.callback(req);
802 memcpy(req->payload.data+req->payload.length,
803 pkt.u.response.stub_and_verifier.data, length);
804 req->payload.length += length;
807 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
808 c->transport.send_read(c);
812 /* we've got the full payload */
813 req->state = RPC_REQUEST_DONE;
814 DLIST_REMOVE(c->pending, req);
816 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
817 req->flags |= DCERPC_PULL_BIGENDIAN;
819 req->flags &= ~DCERPC_PULL_BIGENDIAN;
822 if (req->async.callback) {
823 req->async.callback(req);
829 make sure requests are cleaned up
831 static int dcerpc_req_destructor(void *ptr)
833 struct rpc_request *req = ptr;
834 DLIST_REMOVE(req->p->conn->pending, req);
839 perform the send side of a async dcerpc request
841 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
842 const struct GUID *object,
845 DATA_BLOB *stub_data)
847 struct rpc_request *req;
848 struct dcerpc_packet pkt;
850 uint32_t remaining, chunk_size;
851 BOOL first_packet = True;
853 p->conn->transport.recv_data = dcerpc_request_recv_data;
855 req = talloc_p(mem_ctx, struct rpc_request);
861 req->call_id = next_call_id(p->conn);
862 req->status = NT_STATUS_OK;
863 req->state = RPC_REQUEST_PENDING;
864 req->payload = data_blob(NULL, 0);
867 req->async.callback = NULL;
869 init_dcerpc_hdr(p->conn, &pkt);
871 remaining = stub_data->length;
873 /* we can write a full max_recv_frag size, minus the dcerpc
874 request header size */
875 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
877 pkt.ptype = DCERPC_PKT_REQUEST;
878 pkt.call_id = req->call_id;
881 pkt.u.request.alloc_hint = remaining;
882 pkt.u.request.context_id = p->context_id;
883 pkt.u.request.opnum = opnum;
886 pkt.u.request.object.object = *object;
887 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
888 chunk_size -= ndr_size_GUID(object,0);
891 DLIST_ADD(p->conn->pending, req);
893 /* we send a series of pdus without waiting for a reply */
894 while (remaining > 0 || first_packet) {
895 uint32_t chunk = MIN(chunk_size, remaining);
896 BOOL last_frag = False;
898 first_packet = False;
899 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
901 if (remaining == stub_data->length) {
902 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
904 if (chunk == remaining) {
905 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
909 pkt.u.request.stub_and_verifier.data = stub_data->data +
910 (stub_data->length - remaining);
911 pkt.u.request.stub_and_verifier.length = chunk;
913 req->status = dcerpc_push_request_sign(p->conn, &blob, mem_ctx, &pkt);
914 if (!NT_STATUS_IS_OK(req->status)) {
915 req->state = RPC_REQUEST_DONE;
916 DLIST_REMOVE(p->conn->pending, req);
920 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
921 if (!NT_STATUS_IS_OK(req->status)) {
922 req->state = RPC_REQUEST_DONE;
923 DLIST_REMOVE(p->conn->pending, req);
930 talloc_set_destructor(req, dcerpc_req_destructor);
936 return the event context for a dcerpc pipe
937 used by callers who wish to operate asynchronously
939 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
941 return p->conn->transport.event_context(p->conn);
947 perform the receive side of a async dcerpc request
949 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
951 DATA_BLOB *stub_data)
955 while (req->state == RPC_REQUEST_PENDING) {
956 struct event_context *ctx = dcerpc_event_context(req->p);
957 if (event_loop_once(ctx) != 0) {
958 return NT_STATUS_CONNECTION_DISCONNECTED;
961 *stub_data = req->payload;
962 status = req->status;
963 if (stub_data->data) {
964 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
966 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
967 req->p->last_fault_code = req->fault_code;
974 perform a full request/response pair on a dcerpc pipe
976 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
980 DATA_BLOB *stub_data_in,
981 DATA_BLOB *stub_data_out)
983 struct rpc_request *req;
985 req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
987 return NT_STATUS_NO_MEMORY;
990 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
995 this is a paranoid NDR validator. For every packet we push onto the wire
996 we pull it back again, then push it again. Then we compare the raw NDR data
997 for that to the NDR we initially generated. If they don't match then we know
998 we must have a bug in either the pull or push side of our code
1000 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1001 TALLOC_CTX *mem_ctx,
1004 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1005 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1008 struct ndr_pull *pull;
1009 struct ndr_push *push;
1013 st = talloc_size(mem_ctx, struct_size);
1015 return NT_STATUS_NO_MEMORY;
1018 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1020 return NT_STATUS_NO_MEMORY;
1023 status = ndr_pull(pull, NDR_IN, st);
1024 if (!NT_STATUS_IS_OK(status)) {
1025 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1026 "failed input validation pull - %s",
1030 push = ndr_push_init_ctx(mem_ctx);
1032 return NT_STATUS_NO_MEMORY;
1035 status = ndr_push(push, NDR_IN, st);
1036 if (!NT_STATUS_IS_OK(status)) {
1037 return ndr_push_error(push, NDR_ERR_VALIDATE,
1038 "failed input validation push - %s",
1042 blob2 = ndr_push_blob(push);
1044 if (!data_blob_equal(&blob, &blob2)) {
1045 DEBUG(3,("original:\n"));
1046 dump_data(3, blob.data, blob.length);
1047 DEBUG(3,("secondary:\n"));
1048 dump_data(3, blob2.data, blob2.length);
1049 return ndr_push_error(push, NDR_ERR_VALIDATE,
1050 "failed input validation data - %s",
1054 return NT_STATUS_OK;
1058 this is a paranoid NDR input validator. For every packet we pull
1059 from the wire we push it back again then pull and push it
1060 again. Then we compare the raw NDR data for that to the NDR we
1061 initially generated. If they don't match then we know we must have a
1062 bug in either the pull or push side of our code
1064 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1065 TALLOC_CTX *mem_ctx,
1068 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1069 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1072 struct ndr_pull *pull;
1073 struct ndr_push *push;
1075 DATA_BLOB blob, blob2;
1077 st = talloc_size(mem_ctx, struct_size);
1079 return NT_STATUS_NO_MEMORY;
1081 memcpy(st, struct_ptr, struct_size);
1083 push = ndr_push_init_ctx(mem_ctx);
1085 return NT_STATUS_NO_MEMORY;
1088 status = ndr_push(push, NDR_OUT, struct_ptr);
1089 if (!NT_STATUS_IS_OK(status)) {
1090 return ndr_push_error(push, NDR_ERR_VALIDATE,
1091 "failed output validation push - %s",
1095 blob = ndr_push_blob(push);
1097 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1099 return NT_STATUS_NO_MEMORY;
1102 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1103 status = ndr_pull(pull, NDR_OUT, st);
1104 if (!NT_STATUS_IS_OK(status)) {
1105 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1106 "failed output validation pull - %s",
1110 push = ndr_push_init_ctx(mem_ctx);
1112 return NT_STATUS_NO_MEMORY;
1115 status = ndr_push(push, NDR_OUT, st);
1116 if (!NT_STATUS_IS_OK(status)) {
1117 return ndr_push_error(push, NDR_ERR_VALIDATE,
1118 "failed output validation push2 - %s",
1122 blob2 = ndr_push_blob(push);
1124 if (!data_blob_equal(&blob, &blob2)) {
1125 DEBUG(3,("original:\n"));
1126 dump_data(3, blob.data, blob.length);
1127 DEBUG(3,("secondary:\n"));
1128 dump_data(3, blob2.data, blob2.length);
1129 return ndr_push_error(push, NDR_ERR_VALIDATE,
1130 "failed output validation data - %s",
1134 return NT_STATUS_OK;
1139 send a rpc request given a dcerpc_call structure
1141 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1142 const struct GUID *object,
1143 const struct dcerpc_interface_table *table,
1145 TALLOC_CTX *mem_ctx,
1148 const struct dcerpc_interface_call *call;
1149 struct ndr_push *push;
1152 struct rpc_request *req;
1154 call = &table->calls[opnum];
1156 /* setup for a ndr_push_* call */
1157 push = ndr_push_init();
1162 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1163 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1166 /* push the structure into a blob */
1167 status = call->ndr_push(push, NDR_IN, r);
1168 if (!NT_STATUS_IS_OK(status)) {
1169 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1170 nt_errstr(status)));
1171 ndr_push_free(push);
1175 /* retrieve the blob */
1176 request = ndr_push_blob(push);
1178 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1179 status = dcerpc_ndr_validate_in(p->conn, mem_ctx, request, call->struct_size,
1180 call->ndr_push, call->ndr_pull);
1181 if (!NT_STATUS_IS_OK(status)) {
1182 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1183 nt_errstr(status)));
1184 ndr_push_free(push);
1189 DEBUG(10,("rpc request data:\n"));
1190 dump_data(10, request.data, request.length);
1192 /* make the actual dcerpc request */
1193 req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1196 req->ndr.table = table;
1197 req->ndr.opnum = opnum;
1198 req->ndr.struct_ptr = r;
1199 req->ndr.mem_ctx = mem_ctx;
1202 ndr_push_free(push);
1208 receive the answer from a dcerpc_ndr_request_send()
1210 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1212 struct dcerpc_pipe *p = req->p;
1215 struct ndr_pull *pull;
1217 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1218 void *r = req->ndr.struct_ptr;
1219 uint32_t opnum = req->ndr.opnum;
1220 const struct dcerpc_interface_table *table = req->ndr.table;
1221 const struct dcerpc_interface_call *call = &table->calls[opnum];
1223 /* make sure the recv code doesn't free the request, as we
1224 need to grab the flags element before it is freed */
1225 talloc_increase_ref_count(req);
1227 status = dcerpc_request_recv(req, mem_ctx, &response);
1228 if (!NT_STATUS_IS_OK(status)) {
1235 /* prepare for ndr_pull_* */
1236 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1238 return NT_STATUS_NO_MEMORY;
1241 if (flags & DCERPC_PULL_BIGENDIAN) {
1242 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1245 DEBUG(10,("rpc reply data:\n"));
1246 dump_data(10, pull->data, pull->data_size);
1248 /* pull the structure from the blob */
1249 status = call->ndr_pull(pull, NDR_OUT, r);
1250 if (!NT_STATUS_IS_OK(status)) {
1251 dcerpc_log_packet(table, opnum, NDR_OUT,
1256 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1257 status = dcerpc_ndr_validate_out(p->conn, mem_ctx, r, call->struct_size,
1258 call->ndr_push, call->ndr_pull);
1259 if (!NT_STATUS_IS_OK(status)) {
1260 dcerpc_log_packet(table, opnum, NDR_OUT,
1266 if (pull->offset != pull->data_size) {
1267 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1268 pull->data_size - pull->offset));
1269 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1270 but it turns out that early versions of NT
1271 (specifically NT3.1) add junk onto the end of rpc
1272 packets, so if we want to interoperate at all with
1273 those versions then we need to ignore this error */
1276 return NT_STATUS_OK;
1281 a useful helper function for synchronous rpc requests
1283 this can be used when you have ndr push/pull functions in the
1286 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1287 const struct GUID *object,
1288 const struct dcerpc_interface_table *table,
1290 TALLOC_CTX *mem_ctx,
1293 struct rpc_request *req;
1295 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1297 return NT_STATUS_NO_MEMORY;
1300 return dcerpc_ndr_request_recv(req);
1305 a useful function for retrieving the server name we connected to
1307 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1309 if (!p->conn->transport.peer_name) {
1312 return p->conn->transport.peer_name(p->conn);
1317 get the dcerpc auth_level for a open connection
1319 uint32 dcerpc_auth_level(struct dcerpc_connection *c)
1323 if (c->flags & DCERPC_SEAL) {
1324 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1325 } else if (c->flags & DCERPC_SIGN) {
1326 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1327 } else if (c->flags & DCERPC_CONNECT) {
1328 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1330 auth_level = DCERPC_AUTH_LEVEL_NONE;
1337 send a dcerpc alter_context request
1339 NTSTATUS dcerpc_alter_context(struct dcerpc_pipe *p,
1340 TALLOC_CTX *mem_ctx,
1341 const struct dcerpc_syntax_id *syntax,
1342 const struct dcerpc_syntax_id *transfer_syntax)
1344 struct dcerpc_packet pkt;
1348 p->syntax = *syntax;
1349 p->transfer_syntax = *transfer_syntax;
1351 init_dcerpc_hdr(p->conn, &pkt);
1353 pkt.ptype = DCERPC_PKT_ALTER;
1354 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1355 pkt.call_id = p->conn->call_id;
1356 pkt.auth_length = 0;
1358 pkt.u.alter.max_xmit_frag = 5840;
1359 pkt.u.alter.max_recv_frag = 5840;
1360 pkt.u.alter.assoc_group_id = 0;
1361 pkt.u.alter.num_contexts = 1;
1362 pkt.u.alter.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
1363 if (!pkt.u.alter.ctx_list) {
1364 return NT_STATUS_NO_MEMORY;
1366 pkt.u.alter.ctx_list[0].context_id = p->context_id;
1367 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
1368 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
1369 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
1370 pkt.u.alter.auth_info = data_blob(NULL, 0);
1372 /* construct the NDR form of the packet */
1373 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
1374 if (!NT_STATUS_IS_OK(status)) {
1378 /* send it on its way */
1379 status = full_request(p->conn, mem_ctx, &blob, &blob);
1380 if (!NT_STATUS_IS_OK(status)) {
1384 /* unmarshall the NDR */
1385 status = dcerpc_pull(p->conn, &blob, mem_ctx, &pkt);
1386 if (!NT_STATUS_IS_OK(status)) {
1390 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
1391 DEBUG(2,("dcerpc: alter_nak reason %d\n", pkt.u.bind_nak.reject_reason));
1392 return NT_STATUS_ACCESS_DENIED;
1395 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
1396 pkt.u.alter_ack.num_results == 0 ||
1397 pkt.u.alter_ack.ctx_list[0].result != 0) {
1398 return NT_STATUS_UNSUCCESSFUL;
1401 /* the alter_ack might contain a reply set of credentials */
1402 if (p->conn->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
1403 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
1405 p->conn->security_state.auth_info,
1406 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);