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"
28 static struct dcerpc_interface_list *dcerpc_pipes = NULL;
31 register a dcerpc client interface
33 NTSTATUS librpc_register_interface(const struct dcerpc_interface_table *interface)
35 struct dcerpc_interface_list *l = talloc_p(talloc_autofree_context(),
36 struct dcerpc_interface_list);
38 if (idl_iface_by_name (interface->name) != NULL) {
39 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
40 return NT_STATUS_OBJECT_NAME_COLLISION;
44 DLIST_ADD(dcerpc_pipes, l);
50 return the list of registered dcerpc_pipes
52 const struct dcerpc_interface_list *librpc_dcerpc_pipes(void)
57 /* destroy a dcerpc connection */
58 static int dcerpc_connection_destructor(void *ptr)
60 struct dcerpc_connection *c = ptr;
61 if (c->transport.shutdown_pipe) {
62 c->transport.shutdown_pipe(c);
68 /* initialise a dcerpc connection. */
69 struct dcerpc_connection *dcerpc_connection_init(TALLOC_CTX *mem_ctx)
71 struct dcerpc_connection *c;
73 c = talloc_zero(mem_ctx, struct dcerpc_connection);
79 c->security_state.auth_info = NULL;
80 c->security_state.session_key = dcerpc_generic_session_key;
81 c->security_state.generic_state = NULL;
82 c->binding_string = NULL;
84 c->srv_max_xmit_frag = 0;
85 c->srv_max_recv_frag = 0;
88 talloc_set_destructor(c, dcerpc_connection_destructor);
93 /* initialise a dcerpc pipe. */
94 struct dcerpc_pipe *dcerpc_pipe_init(TALLOC_CTX *mem_ctx)
96 struct dcerpc_pipe *p;
98 p = talloc_p(mem_ctx, struct dcerpc_pipe);
103 p->conn = dcerpc_connection_init(p);
104 if (p->conn == NULL) {
109 p->last_fault_code = 0;
112 ZERO_STRUCT(p->syntax);
113 ZERO_STRUCT(p->transfer_syntax);
120 choose the next call id to use
122 static uint32_t next_call_id(struct dcerpc_connection *c)
125 if (c->call_id == 0) {
131 /* close down a dcerpc over SMB pipe */
132 void dcerpc_pipe_close(struct dcerpc_pipe *p)
137 /* we need to be able to get/set the fragment length without doing a full
139 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
141 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
142 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
144 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
148 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
150 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
151 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
153 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
157 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
159 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
160 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
162 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
168 setup for a ndr pull, also setting up any flags from the binding string
170 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_connection *c,
171 DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
173 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
175 if (ndr == NULL) return ndr;
177 if (c->flags & DCERPC_DEBUG_PAD_CHECK) {
178 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
181 if (c->flags & DCERPC_NDR_REF_ALLOC) {
182 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
189 parse a data blob into a dcerpc_packet structure. This handles both
190 input and output packets
192 static NTSTATUS dcerpc_pull(struct dcerpc_connection *c, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
193 struct dcerpc_packet *pkt)
195 struct ndr_pull *ndr;
197 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
199 return NT_STATUS_NO_MEMORY;
202 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
203 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
206 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
210 generate a CONNECT level verifier
212 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
214 *blob = data_blob_talloc(mem_ctx, NULL, 16);
215 if (blob->data == NULL) {
216 return NT_STATUS_NO_MEMORY;
218 SIVAL(blob->data, 0, 1);
219 memset(blob->data+4, 0, 12);
224 check a CONNECT level verifier
226 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
228 if (blob->length != 16 ||
229 IVAL(blob->data, 0) != 1) {
230 return NT_STATUS_ACCESS_DENIED;
236 parse a possibly signed blob into a dcerpc request packet structure
238 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_connection *c,
239 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
240 struct dcerpc_packet *pkt)
242 struct ndr_pull *ndr;
244 struct dcerpc_auth auth;
247 /* non-signed packets are simpler */
248 if (!c->security_state.auth_info ||
249 !c->security_state.generic_state) {
250 return dcerpc_pull(c, blob, mem_ctx, pkt);
253 ndr = ndr_pull_init_flags(c, blob, mem_ctx);
255 return NT_STATUS_NO_MEMORY;
258 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
259 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
262 /* pull the basic packet */
263 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
264 if (!NT_STATUS_IS_OK(status)) {
268 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
272 if (pkt->auth_length == 0 &&
273 c->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
277 auth_blob.length = 8 + pkt->auth_length;
279 /* check for a valid length */
280 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
281 return NT_STATUS_INFO_LENGTH_MISMATCH;
285 pkt->u.response.stub_and_verifier.data +
286 pkt->u.response.stub_and_verifier.length - auth_blob.length;
287 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
289 /* pull the auth structure */
290 ndr = ndr_pull_init_flags(c, &auth_blob, mem_ctx);
292 return NT_STATUS_NO_MEMORY;
295 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
296 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
299 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
300 if (!NT_STATUS_IS_OK(status)) {
305 /* check signature or unseal the packet */
306 switch (c->security_state.auth_info->auth_level) {
307 case DCERPC_AUTH_LEVEL_PRIVACY:
308 status = gensec_unseal_packet(c->security_state.generic_state,
310 blob->data + DCERPC_REQUEST_LENGTH,
311 pkt->u.response.stub_and_verifier.length,
313 blob->length - auth.credentials.length,
315 memcpy(pkt->u.response.stub_and_verifier.data,
316 blob->data + DCERPC_REQUEST_LENGTH,
317 pkt->u.response.stub_and_verifier.length);
320 case DCERPC_AUTH_LEVEL_INTEGRITY:
321 status = gensec_check_packet(c->security_state.generic_state,
323 pkt->u.response.stub_and_verifier.data,
324 pkt->u.response.stub_and_verifier.length,
326 blob->length - auth.credentials.length,
330 case DCERPC_AUTH_LEVEL_CONNECT:
331 status = dcerpc_check_connect_verifier(&auth.credentials);
334 case DCERPC_AUTH_LEVEL_NONE:
338 status = NT_STATUS_INVALID_LEVEL;
342 /* remove the indicated amount of paddiing */
343 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
344 return NT_STATUS_INFO_LENGTH_MISMATCH;
346 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
353 push a dcerpc request packet into a blob, possibly signing it.
355 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_connection *c,
356 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
357 struct dcerpc_packet *pkt)
360 struct ndr_push *ndr;
363 /* non-signed packets are simpler */
364 if (!c->security_state.auth_info ||
365 !c->security_state.generic_state) {
366 return dcerpc_push_auth(blob, mem_ctx, pkt, c->security_state.auth_info);
369 ndr = ndr_push_init_ctx(mem_ctx);
371 return NT_STATUS_NO_MEMORY;
374 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
375 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
378 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
379 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
382 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
383 if (!NT_STATUS_IS_OK(status)) {
387 /* pad to 16 byte multiple in the payload portion of the
388 packet. This matches what w2k3 does */
389 c->security_state.auth_info->auth_pad_length =
390 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
391 ndr_push_zero(ndr, c->security_state.auth_info->auth_pad_length);
393 /* sign or seal the packet */
394 switch (c->security_state.auth_info->auth_level) {
395 case DCERPC_AUTH_LEVEL_PRIVACY:
396 case DCERPC_AUTH_LEVEL_INTEGRITY:
397 c->security_state.auth_info->credentials
398 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(c->security_state.generic_state));
399 data_blob_clear(&c->security_state.auth_info->credentials);
402 case DCERPC_AUTH_LEVEL_CONNECT:
403 status = dcerpc_connect_verifier(mem_ctx, &c->security_state.auth_info->credentials);
406 case DCERPC_AUTH_LEVEL_NONE:
407 c->security_state.auth_info->credentials = data_blob(NULL, 0);
411 status = NT_STATUS_INVALID_LEVEL;
415 if (!NT_STATUS_IS_OK(status)) {
419 /* add the auth verifier */
420 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, c->security_state.auth_info);
421 if (!NT_STATUS_IS_OK(status)) {
425 /* extract the whole packet as a blob */
426 *blob = ndr_push_blob(ndr);
428 /* fill in the fragment length and auth_length, we can't fill
429 in these earlier as we don't know the signature length (it
430 could be variable length) */
431 dcerpc_set_frag_length(blob, blob->length);
432 dcerpc_set_auth_length(blob, c->security_state.auth_info->credentials.length);
434 /* sign or seal the packet */
435 switch (c->security_state.auth_info->auth_level) {
436 case DCERPC_AUTH_LEVEL_PRIVACY:
437 status = gensec_seal_packet(c->security_state.generic_state,
439 blob->data + DCERPC_REQUEST_LENGTH,
440 pkt->u.request.stub_and_verifier.length +
441 c->security_state.auth_info->auth_pad_length,
444 c->security_state.auth_info->credentials.length,
446 if (!NT_STATUS_IS_OK(status)) {
449 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
452 case DCERPC_AUTH_LEVEL_INTEGRITY:
453 status = gensec_sign_packet(c->security_state.generic_state,
455 blob->data + DCERPC_REQUEST_LENGTH,
456 pkt->u.request.stub_and_verifier.length +
457 c->security_state.auth_info->auth_pad_length,
460 c->security_state.auth_info->credentials.length,
462 if (!NT_STATUS_IS_OK(status)) {
465 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
468 case DCERPC_AUTH_LEVEL_CONNECT:
471 case DCERPC_AUTH_LEVEL_NONE:
472 c->security_state.auth_info->credentials = data_blob(NULL, 0);
476 status = NT_STATUS_INVALID_LEVEL;
480 data_blob_free(&c->security_state.auth_info->credentials);
487 fill in the fixed values in a dcerpc header
489 static void init_dcerpc_hdr(struct dcerpc_connection *c, struct dcerpc_packet *pkt)
492 pkt->rpc_vers_minor = 0;
493 if (c->flags & DCERPC_PUSH_BIGENDIAN) {
496 pkt->drep[0] = DCERPC_DREP_LE;
504 hold the state of pending full requests
506 struct full_request_state {
507 DATA_BLOB *reply_blob;
512 receive a reply to a full request
514 static void full_request_recv(struct dcerpc_connection *c, DATA_BLOB *blob,
517 struct full_request_state *state = c->full_request_private;
519 if (!NT_STATUS_IS_OK(status)) {
520 state->status = status;
523 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
524 state->reply_blob = NULL;
528 perform a single pdu synchronous request - used for the bind code
529 this cannot be mixed with normal async requests
531 static NTSTATUS full_request(struct dcerpc_connection *c,
533 DATA_BLOB *request_blob,
534 DATA_BLOB *reply_blob)
536 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
540 return NT_STATUS_NO_MEMORY;
543 state->reply_blob = reply_blob;
544 state->status = NT_STATUS_OK;
546 c->transport.recv_data = full_request_recv;
547 c->full_request_private = state;
549 status = c->transport.send_request(c, request_blob, True);
550 if (!NT_STATUS_IS_OK(status)) {
554 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
555 struct event_context *ctx = c->transport.event_context(c);
556 if (event_loop_once(ctx) != 0) {
557 return NT_STATUS_CONNECTION_DISCONNECTED;
561 return state->status;
566 perform a bind using the given syntax
568 the auth_info structure is updated with the reply authentication info
571 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
573 const struct dcerpc_syntax_id *syntax,
574 const struct dcerpc_syntax_id *transfer_syntax)
576 struct dcerpc_packet pkt;
581 p->transfer_syntax = *transfer_syntax;
583 init_dcerpc_hdr(p->conn, &pkt);
585 pkt.ptype = DCERPC_PKT_BIND;
586 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
587 pkt.call_id = p->conn->call_id;
590 pkt.u.bind.max_xmit_frag = 5840;
591 pkt.u.bind.max_recv_frag = 5840;
592 pkt.u.bind.assoc_group_id = 0;
593 pkt.u.bind.num_contexts = 1;
594 pkt.u.bind.ctx_list = talloc_array(mem_ctx, struct dcerpc_ctx_list, 1);
595 if (!pkt.u.bind.ctx_list) {
596 return NT_STATUS_NO_MEMORY;
598 pkt.u.bind.ctx_list[0].context_id = p->context_id;
599 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
600 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
601 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
602 pkt.u.bind.auth_info = data_blob(NULL, 0);
604 /* construct the NDR form of the packet */
605 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->conn->security_state.auth_info);
606 if (!NT_STATUS_IS_OK(status)) {
610 /* send it on its way */
611 status = full_request(p->conn, mem_ctx, &blob, &blob);
612 if (!NT_STATUS_IS_OK(status)) {
616 /* unmarshall the NDR */
617 status = dcerpc_pull(p->conn, &blob, mem_ctx, &pkt);
618 if (!NT_STATUS_IS_OK(status)) {
622 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
623 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
624 return NT_STATUS_ACCESS_DENIED;
627 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
628 pkt.u.bind_ack.num_results == 0 ||
629 pkt.u.bind_ack.ctx_list[0].result != 0) {
630 return NT_STATUS_UNSUCCESSFUL;
633 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
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;
638 /* the bind_ack might contain a reply set of credentials */
639 if (p->conn->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
640 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
642 p->conn->security_state.auth_info,
643 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
651 perform a continued bind (and auth3)
653 NTSTATUS dcerpc_auth3(struct dcerpc_connection *c,
656 struct dcerpc_packet pkt;
660 init_dcerpc_hdr(c, &pkt);
662 pkt.ptype = DCERPC_PKT_AUTH3;
663 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
664 pkt.call_id = next_call_id(c);
666 pkt.u.auth3._pad = 0;
667 pkt.u.auth3.auth_info = data_blob(NULL, 0);
669 /* construct the NDR form of the packet */
670 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, c->security_state.auth_info);
671 if (!NT_STATUS_IS_OK(status)) {
675 /* send it on its way */
676 status = c->transport.send_request(c, &blob, False);
677 if (!NT_STATUS_IS_OK(status)) {
685 /* perform a dcerpc bind, using the uuid as the key */
686 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
688 const char *uuid, uint_t version)
690 struct dcerpc_syntax_id syntax;
691 struct dcerpc_syntax_id transfer_syntax;
694 status = GUID_from_string(uuid, &syntax.uuid);
695 if (!NT_STATUS_IS_OK(status)) {
696 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
699 syntax.if_version = version;
701 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
702 if (!NT_STATUS_IS_OK(status)) {
705 transfer_syntax.if_version = NDR_GUID_VERSION;
707 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
711 process a fragment received from the transport layer during a
714 static void dcerpc_request_recv_data(struct dcerpc_connection *c,
718 struct dcerpc_packet pkt;
719 struct rpc_request *req;
722 if (!NT_STATUS_IS_OK(status)) {
723 /* all pending requests get the error */
726 req->state = RPC_REQUEST_DONE;
727 req->status = status;
728 DLIST_REMOVE(c->pending, req);
729 if (req->async.callback) {
730 req->async.callback(req);
738 status = dcerpc_pull_request_sign(c, data, (TALLOC_CTX *)data->data, &pkt);
740 /* find the matching request. Notice we match before we check
741 the status. this is ok as a pending call_id can never be
743 for (req=c->pending;req;req=req->next) {
744 if (pkt.call_id == req->call_id) break;
748 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
752 if (!NT_STATUS_IS_OK(status)) {
753 req->status = status;
754 req->state = RPC_REQUEST_DONE;
755 DLIST_REMOVE(c->pending, req);
756 if (req->async.callback) {
757 req->async.callback(req);
762 if (pkt.ptype == DCERPC_PKT_FAULT) {
763 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(c, pkt.u.fault.status)));
764 req->fault_code = pkt.u.fault.status;
765 req->status = NT_STATUS_NET_WRITE_FAULT;
766 req->state = RPC_REQUEST_DONE;
767 DLIST_REMOVE(c->pending, req);
768 if (req->async.callback) {
769 req->async.callback(req);
774 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
775 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
777 req->fault_code = DCERPC_FAULT_OTHER;
778 req->status = NT_STATUS_NET_WRITE_FAULT;
779 req->state = RPC_REQUEST_DONE;
780 DLIST_REMOVE(c->pending, req);
781 if (req->async.callback) {
782 req->async.callback(req);
787 length = pkt.u.response.stub_and_verifier.length;
790 req->payload.data = talloc_realloc(req,
793 req->payload.length + length);
794 if (!req->payload.data) {
795 req->status = NT_STATUS_NO_MEMORY;
796 req->state = RPC_REQUEST_DONE;
797 DLIST_REMOVE(c->pending, req);
798 if (req->async.callback) {
799 req->async.callback(req);
803 memcpy(req->payload.data+req->payload.length,
804 pkt.u.response.stub_and_verifier.data, length);
805 req->payload.length += length;
808 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
809 c->transport.send_read(c);
813 /* we've got the full payload */
814 req->state = RPC_REQUEST_DONE;
815 DLIST_REMOVE(c->pending, req);
817 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
818 req->flags |= DCERPC_PULL_BIGENDIAN;
820 req->flags &= ~DCERPC_PULL_BIGENDIAN;
823 if (req->async.callback) {
824 req->async.callback(req);
830 make sure requests are cleaned up
832 static int dcerpc_req_destructor(void *ptr)
834 struct rpc_request *req = ptr;
835 DLIST_REMOVE(req->p->conn->pending, req);
840 perform the send side of a async dcerpc request
842 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
843 const struct GUID *object,
846 DATA_BLOB *stub_data)
848 struct rpc_request *req;
849 struct dcerpc_packet pkt;
851 uint32_t remaining, chunk_size;
852 BOOL first_packet = True;
854 p->conn->transport.recv_data = dcerpc_request_recv_data;
856 req = talloc_p(mem_ctx, struct rpc_request);
862 req->call_id = next_call_id(p->conn);
863 req->status = NT_STATUS_OK;
864 req->state = RPC_REQUEST_PENDING;
865 req->payload = data_blob(NULL, 0);
868 req->async.callback = NULL;
870 init_dcerpc_hdr(p->conn, &pkt);
872 remaining = stub_data->length;
874 /* we can write a full max_recv_frag size, minus the dcerpc
875 request header size */
876 chunk_size = p->conn->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
878 pkt.ptype = DCERPC_PKT_REQUEST;
879 pkt.call_id = req->call_id;
882 pkt.u.request.alloc_hint = remaining;
883 pkt.u.request.context_id = p->context_id;
884 pkt.u.request.opnum = opnum;
887 pkt.u.request.object.object = *object;
888 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
889 chunk_size -= ndr_size_GUID(object,0);
892 DLIST_ADD(p->conn->pending, req);
894 /* we send a series of pdus without waiting for a reply */
895 while (remaining > 0 || first_packet) {
896 uint32_t chunk = MIN(chunk_size, remaining);
897 BOOL last_frag = False;
899 first_packet = False;
900 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
902 if (remaining == stub_data->length) {
903 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
905 if (chunk == remaining) {
906 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
910 pkt.u.request.stub_and_verifier.data = stub_data->data +
911 (stub_data->length - remaining);
912 pkt.u.request.stub_and_verifier.length = chunk;
914 req->status = dcerpc_push_request_sign(p->conn, &blob, mem_ctx, &pkt);
915 if (!NT_STATUS_IS_OK(req->status)) {
916 req->state = RPC_REQUEST_DONE;
917 DLIST_REMOVE(p->conn->pending, req);
921 req->status = p->conn->transport.send_request(p->conn, &blob, last_frag);
922 if (!NT_STATUS_IS_OK(req->status)) {
923 req->state = RPC_REQUEST_DONE;
924 DLIST_REMOVE(p->conn->pending, req);
931 talloc_set_destructor(req, dcerpc_req_destructor);
937 return the event context for a dcerpc pipe
938 used by callers who wish to operate asynchronously
940 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
942 return p->conn->transport.event_context(p->conn);
948 perform the receive side of a async dcerpc request
950 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
952 DATA_BLOB *stub_data)
956 while (req->state == RPC_REQUEST_PENDING) {
957 struct event_context *ctx = dcerpc_event_context(req->p);
958 if (event_loop_once(ctx) != 0) {
959 return NT_STATUS_CONNECTION_DISCONNECTED;
962 *stub_data = req->payload;
963 status = req->status;
964 if (stub_data->data) {
965 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
967 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
968 req->p->last_fault_code = req->fault_code;
975 perform a full request/response pair on a dcerpc pipe
977 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
981 DATA_BLOB *stub_data_in,
982 DATA_BLOB *stub_data_out)
984 struct rpc_request *req;
986 req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
988 return NT_STATUS_NO_MEMORY;
991 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
996 this is a paranoid NDR validator. For every packet we push onto the wire
997 we pull it back again, then push it again. Then we compare the raw NDR data
998 for that to the NDR we initially generated. If they don't match then we know
999 we must have a bug in either the pull or push side of our code
1001 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_connection *c,
1002 TALLOC_CTX *mem_ctx,
1005 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1006 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1009 struct ndr_pull *pull;
1010 struct ndr_push *push;
1014 st = talloc_size(mem_ctx, struct_size);
1016 return NT_STATUS_NO_MEMORY;
1019 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1021 return NT_STATUS_NO_MEMORY;
1024 status = ndr_pull(pull, NDR_IN, st);
1025 if (!NT_STATUS_IS_OK(status)) {
1026 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1027 "failed input validation pull - %s",
1031 push = ndr_push_init_ctx(mem_ctx);
1033 return NT_STATUS_NO_MEMORY;
1036 status = ndr_push(push, NDR_IN, st);
1037 if (!NT_STATUS_IS_OK(status)) {
1038 return ndr_push_error(push, NDR_ERR_VALIDATE,
1039 "failed input validation push - %s",
1043 blob2 = ndr_push_blob(push);
1045 if (!data_blob_equal(&blob, &blob2)) {
1046 DEBUG(3,("original:\n"));
1047 dump_data(3, blob.data, blob.length);
1048 DEBUG(3,("secondary:\n"));
1049 dump_data(3, blob2.data, blob2.length);
1050 return ndr_push_error(push, NDR_ERR_VALIDATE,
1051 "failed input validation data - %s",
1055 return NT_STATUS_OK;
1059 this is a paranoid NDR input validator. For every packet we pull
1060 from the wire we push it back again then pull and push it
1061 again. Then we compare the raw NDR data for that to the NDR we
1062 initially generated. If they don't match then we know we must have a
1063 bug in either the pull or push side of our code
1065 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_connection *c,
1066 TALLOC_CTX *mem_ctx,
1069 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1070 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1073 struct ndr_pull *pull;
1074 struct ndr_push *push;
1076 DATA_BLOB blob, blob2;
1078 st = talloc_size(mem_ctx, struct_size);
1080 return NT_STATUS_NO_MEMORY;
1082 memcpy(st, struct_ptr, struct_size);
1084 push = ndr_push_init_ctx(mem_ctx);
1086 return NT_STATUS_NO_MEMORY;
1089 status = ndr_push(push, NDR_OUT, struct_ptr);
1090 if (!NT_STATUS_IS_OK(status)) {
1091 return ndr_push_error(push, NDR_ERR_VALIDATE,
1092 "failed output validation push - %s",
1096 blob = ndr_push_blob(push);
1098 pull = ndr_pull_init_flags(c, &blob, mem_ctx);
1100 return NT_STATUS_NO_MEMORY;
1103 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1104 status = ndr_pull(pull, NDR_OUT, st);
1105 if (!NT_STATUS_IS_OK(status)) {
1106 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1107 "failed output validation pull - %s",
1111 push = ndr_push_init_ctx(mem_ctx);
1113 return NT_STATUS_NO_MEMORY;
1116 status = ndr_push(push, NDR_OUT, st);
1117 if (!NT_STATUS_IS_OK(status)) {
1118 return ndr_push_error(push, NDR_ERR_VALIDATE,
1119 "failed output validation push2 - %s",
1123 blob2 = ndr_push_blob(push);
1125 if (!data_blob_equal(&blob, &blob2)) {
1126 DEBUG(3,("original:\n"));
1127 dump_data(3, blob.data, blob.length);
1128 DEBUG(3,("secondary:\n"));
1129 dump_data(3, blob2.data, blob2.length);
1130 return ndr_push_error(push, NDR_ERR_VALIDATE,
1131 "failed output validation data - %s",
1135 return NT_STATUS_OK;
1140 send a rpc request given a dcerpc_call structure
1142 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1143 const struct GUID *object,
1144 const struct dcerpc_interface_table *table,
1146 TALLOC_CTX *mem_ctx,
1149 const struct dcerpc_interface_call *call;
1150 struct ndr_push *push;
1153 struct rpc_request *req;
1155 call = &table->calls[opnum];
1157 /* setup for a ndr_push_* call */
1158 push = ndr_push_init();
1163 if (p->conn->flags & DCERPC_PUSH_BIGENDIAN) {
1164 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1167 /* push the structure into a blob */
1168 status = call->ndr_push(push, NDR_IN, r);
1169 if (!NT_STATUS_IS_OK(status)) {
1170 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1171 nt_errstr(status)));
1172 ndr_push_free(push);
1176 /* retrieve the blob */
1177 request = ndr_push_blob(push);
1179 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_IN) {
1180 status = dcerpc_ndr_validate_in(p->conn, mem_ctx, request, call->struct_size,
1181 call->ndr_push, call->ndr_pull);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1184 nt_errstr(status)));
1185 ndr_push_free(push);
1190 DEBUG(10,("rpc request data:\n"));
1191 dump_data(10, request.data, request.length);
1193 /* make the actual dcerpc request */
1194 req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1197 req->ndr.table = table;
1198 req->ndr.opnum = opnum;
1199 req->ndr.struct_ptr = r;
1200 req->ndr.mem_ctx = mem_ctx;
1203 ndr_push_free(push);
1209 receive the answer from a dcerpc_ndr_request_send()
1211 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1213 struct dcerpc_pipe *p = req->p;
1216 struct ndr_pull *pull;
1218 TALLOC_CTX *mem_ctx = req->ndr.mem_ctx;
1219 void *r = req->ndr.struct_ptr;
1220 uint32_t opnum = req->ndr.opnum;
1221 const struct dcerpc_interface_table *table = req->ndr.table;
1222 const struct dcerpc_interface_call *call = &table->calls[opnum];
1224 /* make sure the recv code doesn't free the request, as we
1225 need to grab the flags element before it is freed */
1226 talloc_increase_ref_count(req);
1228 status = dcerpc_request_recv(req, mem_ctx, &response);
1229 if (!NT_STATUS_IS_OK(status)) {
1236 /* prepare for ndr_pull_* */
1237 pull = ndr_pull_init_flags(p->conn, &response, mem_ctx);
1239 return NT_STATUS_NO_MEMORY;
1242 if (flags & DCERPC_PULL_BIGENDIAN) {
1243 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1246 DEBUG(10,("rpc reply data:\n"));
1247 dump_data(10, pull->data, pull->data_size);
1249 /* pull the structure from the blob */
1250 status = call->ndr_pull(pull, NDR_OUT, r);
1251 if (!NT_STATUS_IS_OK(status)) {
1252 dcerpc_log_packet(table, opnum, NDR_OUT,
1257 if (p->conn->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1258 status = dcerpc_ndr_validate_out(p->conn, mem_ctx, r, call->struct_size,
1259 call->ndr_push, call->ndr_pull);
1260 if (!NT_STATUS_IS_OK(status)) {
1261 dcerpc_log_packet(table, opnum, NDR_OUT,
1267 if (pull->offset != pull->data_size) {
1268 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1269 pull->data_size - pull->offset));
1270 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1271 but it turns out that early versions of NT
1272 (specifically NT3.1) add junk onto the end of rpc
1273 packets, so if we want to interoperate at all with
1274 those versions then we need to ignore this error */
1277 return NT_STATUS_OK;
1282 a useful helper function for synchronous rpc requests
1284 this can be used when you have ndr push/pull functions in the
1287 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1288 const struct GUID *object,
1289 const struct dcerpc_interface_table *table,
1291 TALLOC_CTX *mem_ctx,
1294 struct rpc_request *req;
1296 req = dcerpc_ndr_request_send(p, object, table, opnum, mem_ctx, r);
1298 return NT_STATUS_NO_MEMORY;
1301 return dcerpc_ndr_request_recv(req);
1306 a useful function for retrieving the server name we connected to
1308 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1310 if (!p->conn->transport.peer_name) {
1313 return p->conn->transport.peer_name(p->conn);
1318 get the dcerpc auth_level for a open connection
1320 uint32 dcerpc_auth_level(struct dcerpc_connection *c)
1324 if (c->flags & DCERPC_SEAL) {
1325 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1326 } else if (c->flags & DCERPC_SIGN) {
1327 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1328 } else if (c->flags & DCERPC_CONNECT) {
1329 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1331 auth_level = DCERPC_AUTH_LEVEL_NONE;