2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "dlinklist.h"
25 #include "librpc/gen_ndr/ndr_epmapper.h"
27 NTSTATUS librpc_init(void)
29 /* FIXME: Register module registration function here */
33 /* initialise a dcerpc pipe. */
34 struct dcerpc_pipe *dcerpc_pipe_init(void)
36 struct dcerpc_pipe *p;
38 p = talloc_p(NULL, struct dcerpc_pipe);
43 p->reference_count = 0;
45 p->security_state.auth_info = NULL;
46 p->security_state.session_key = dcerpc_generic_session_key;
47 p->security_state.generic_state = NULL;
48 p->binding_string = NULL;
50 p->srv_max_xmit_frag = 0;
51 p->srv_max_recv_frag = 0;
52 p->last_fault_code = 0;
59 choose the next call id to use
61 static uint32_t next_call_id(struct dcerpc_pipe *p)
64 if (p->call_id == 0) {
70 /* close down a dcerpc over SMB pipe */
71 void dcerpc_pipe_close(struct dcerpc_pipe *p)
75 if (p->reference_count <= 0) {
76 if (p->security_state.generic_state) {
77 gensec_end(&p->security_state.generic_state);
79 p->transport.shutdown_pipe(p);
84 /* we need to be able to get/set the fragment length without doing a full
86 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
88 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
89 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
91 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
95 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
97 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
98 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
100 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
104 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
106 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
107 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
109 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
115 setup for a ndr pull, also setting up any flags from the binding string
117 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
119 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
121 if (ndr == NULL) return ndr;
123 if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
124 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
127 if (p->flags & DCERPC_NDR_REF_ALLOC) {
128 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
135 parse a data blob into a dcerpc_packet structure. This handles both
136 input and output packets
138 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
139 struct dcerpc_packet *pkt)
141 struct ndr_pull *ndr;
143 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
145 return NT_STATUS_NO_MEMORY;
148 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
149 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
152 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
156 generate a CONNECT level verifier
158 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
160 *blob = data_blob_talloc(mem_ctx, NULL, 16);
161 if (blob->data == NULL) {
162 return NT_STATUS_NO_MEMORY;
164 SIVAL(blob->data, 0, 1);
165 memset(blob->data+4, 0, 12);
170 generate a CONNECT level verifier
172 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
174 if (blob->length != 16 ||
175 IVAL(blob->data, 0) != 1) {
176 return NT_STATUS_ACCESS_DENIED;
182 parse a possibly signed blob into a dcerpc request packet structure
184 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
185 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
186 struct dcerpc_packet *pkt)
188 struct ndr_pull *ndr;
190 struct dcerpc_auth auth;
193 /* non-signed packets are simpler */
194 if (!p->security_state.auth_info ||
195 !p->security_state.generic_state) {
196 return dcerpc_pull(p, blob, mem_ctx, pkt);
199 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
201 return NT_STATUS_NO_MEMORY;
204 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
205 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
208 /* pull the basic packet */
209 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
210 if (!NT_STATUS_IS_OK(status)) {
214 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
218 if (pkt->auth_length == 0 &&
219 p->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
223 auth_blob.length = 8 + pkt->auth_length;
225 /* check for a valid length */
226 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
227 return NT_STATUS_INFO_LENGTH_MISMATCH;
231 pkt->u.response.stub_and_verifier.data +
232 pkt->u.response.stub_and_verifier.length - auth_blob.length;
233 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
235 /* pull the auth structure */
236 ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
238 return NT_STATUS_NO_MEMORY;
241 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
242 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
245 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
246 if (!NT_STATUS_IS_OK(status)) {
251 /* check signature or unseal the packet */
252 switch (p->security_state.auth_info->auth_level) {
253 case DCERPC_AUTH_LEVEL_PRIVACY:
254 status = gensec_unseal_packet(p->security_state.generic_state,
256 blob->data + DCERPC_REQUEST_LENGTH,
257 pkt->u.response.stub_and_verifier.length,
259 blob->length - auth.credentials.length,
261 memcpy(pkt->u.response.stub_and_verifier.data,
262 blob->data + DCERPC_REQUEST_LENGTH,
263 pkt->u.response.stub_and_verifier.length);
266 case DCERPC_AUTH_LEVEL_INTEGRITY:
267 status = gensec_check_packet(p->security_state.generic_state,
269 pkt->u.response.stub_and_verifier.data,
270 pkt->u.response.stub_and_verifier.length,
272 blob->length - auth.credentials.length,
276 case DCERPC_AUTH_LEVEL_CONNECT:
277 status = dcerpc_check_connect_verifier(&auth.credentials);
280 case DCERPC_AUTH_LEVEL_NONE:
284 status = NT_STATUS_INVALID_LEVEL;
288 /* remove the indicated amount of paddiing */
289 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
290 return NT_STATUS_INFO_LENGTH_MISMATCH;
292 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
299 push a dcerpc request packet into a blob, possibly signing it.
301 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
302 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
303 struct dcerpc_packet *pkt)
306 struct ndr_push *ndr;
309 /* non-signed packets are simpler */
310 if (!p->security_state.auth_info ||
311 !p->security_state.generic_state) {
312 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
315 ndr = ndr_push_init_ctx(mem_ctx);
317 return NT_STATUS_NO_MEMORY;
320 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
321 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
324 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
325 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
328 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
329 if (!NT_STATUS_IS_OK(status)) {
333 /* pad to 16 byte multiple in the payload portion of the
334 packet. This matches what w2k3 does */
335 p->security_state.auth_info->auth_pad_length =
336 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
337 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
339 /* sign or seal the packet */
340 switch (p->security_state.auth_info->auth_level) {
341 case DCERPC_AUTH_LEVEL_PRIVACY:
342 case DCERPC_AUTH_LEVEL_INTEGRITY:
343 p->security_state.auth_info->credentials
344 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
345 data_blob_clear(&p->security_state.auth_info->credentials);
348 case DCERPC_AUTH_LEVEL_CONNECT:
349 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
352 case DCERPC_AUTH_LEVEL_NONE:
353 p->security_state.auth_info->credentials = data_blob(NULL, 0);
357 status = NT_STATUS_INVALID_LEVEL;
361 if (!NT_STATUS_IS_OK(status)) {
365 /* add the auth verifier */
366 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
367 if (!NT_STATUS_IS_OK(status)) {
371 /* extract the whole packet as a blob */
372 *blob = ndr_push_blob(ndr);
374 /* fill in the fragment length and auth_length, we can't fill
375 in these earlier as we don't know the signature length (it
376 could be variable length) */
377 dcerpc_set_frag_length(blob, blob->length);
378 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
380 /* sign or seal the packet */
381 switch (p->security_state.auth_info->auth_level) {
382 case DCERPC_AUTH_LEVEL_PRIVACY:
383 status = gensec_seal_packet(p->security_state.generic_state,
385 blob->data + DCERPC_REQUEST_LENGTH,
386 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
389 p->security_state.auth_info->credentials.length,
391 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
394 case DCERPC_AUTH_LEVEL_INTEGRITY:
395 status = gensec_sign_packet(p->security_state.generic_state,
397 blob->data + DCERPC_REQUEST_LENGTH,
398 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
401 p->security_state.auth_info->credentials.length,
403 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
406 case DCERPC_AUTH_LEVEL_CONNECT:
409 case DCERPC_AUTH_LEVEL_NONE:
410 p->security_state.auth_info->credentials = data_blob(NULL, 0);
414 status = NT_STATUS_INVALID_LEVEL;
418 data_blob_free(&p->security_state.auth_info->credentials);
425 fill in the fixed values in a dcerpc header
427 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
430 pkt->rpc_vers_minor = 0;
431 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
434 pkt->drep[0] = DCERPC_DREP_LE;
442 hold the state of pending full requests
444 struct full_request_state {
445 DATA_BLOB *reply_blob;
450 receive a reply to a full request
452 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
455 struct full_request_state *state = p->full_request_private;
457 if (!NT_STATUS_IS_OK(status)) {
458 state->status = status;
461 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
462 state->reply_blob = NULL;
466 perform a single pdu synchronous request - used for the bind code
467 this cannot be mixed with normal async requests
469 static NTSTATUS full_request(struct dcerpc_pipe *p,
471 DATA_BLOB *request_blob,
472 DATA_BLOB *reply_blob)
474 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
478 return NT_STATUS_NO_MEMORY;
481 state->reply_blob = reply_blob;
482 state->status = NT_STATUS_OK;
484 p->transport.recv_data = full_request_recv;
485 p->full_request_private = state;
487 status = p->transport.send_request(p, request_blob, True);
488 if (!NT_STATUS_IS_OK(status)) {
492 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
493 struct event_context *ctx = p->transport.event_context(p);
494 if (event_loop_once(ctx) != 0) {
495 return NT_STATUS_CONNECTION_DISCONNECTED;
499 return state->status;
504 perform a bind using the given syntax
506 the auth_info structure is updated with the reply authentication info
509 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
511 const struct dcerpc_syntax_id *syntax,
512 const struct dcerpc_syntax_id *transfer_syntax)
514 struct dcerpc_packet pkt;
519 p->transfer_syntax = *transfer_syntax;
521 init_dcerpc_hdr(p, &pkt);
523 pkt.ptype = DCERPC_PKT_BIND;
524 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
525 pkt.call_id = p->call_id;
528 pkt.u.bind.max_xmit_frag = 5840;
529 pkt.u.bind.max_recv_frag = 5840;
530 pkt.u.bind.assoc_group_id = 0;
531 pkt.u.bind.num_contexts = 1;
532 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
533 if (!pkt.u.bind.ctx_list) {
534 return NT_STATUS_NO_MEMORY;
536 pkt.u.bind.ctx_list[0].context_id = 0;
537 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
538 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
539 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
540 pkt.u.bind.auth_info = data_blob(NULL, 0);
542 /* construct the NDR form of the packet */
543 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
544 if (!NT_STATUS_IS_OK(status)) {
548 /* send it on its way */
549 status = full_request(p, mem_ctx, &blob, &blob);
550 if (!NT_STATUS_IS_OK(status)) {
554 /* unmarshall the NDR */
555 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
556 if (!NT_STATUS_IS_OK(status)) {
560 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
561 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
562 return NT_STATUS_ACCESS_DENIED;
565 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
566 pkt.u.bind_ack.num_results == 0 ||
567 pkt.u.bind_ack.ctx_list[0].result != 0) {
568 return NT_STATUS_UNSUCCESSFUL;
571 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
572 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
573 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
576 /* the bind_ack might contain a reply set of credentials */
577 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
578 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
580 p->security_state.auth_info,
581 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
588 perform a alter context using the given syntax
590 the auth_info structure is updated with the reply authentication info
593 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
596 struct dcerpc_packet pkt;
600 init_dcerpc_hdr(p, &pkt);
602 pkt.ptype = DCERPC_PKT_ALTER;
603 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
604 pkt.call_id = p->call_id;
607 pkt.u.alter.max_xmit_frag = 0x2000;
608 pkt.u.alter.max_recv_frag = 0x2000;
609 pkt.u.alter.assoc_group_id = 0;
610 pkt.u.alter.num_contexts = 1;
611 pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
612 if (!pkt.u.alter.ctx_list) {
613 return NT_STATUS_NO_MEMORY;
615 pkt.u.alter.ctx_list[0].context_id = 0;
616 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
617 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
618 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
619 pkt.u.alter.auth_info = data_blob(NULL, 0);
621 /* construct the NDR form of the packet */
622 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
623 if (!NT_STATUS_IS_OK(status)) {
627 /* send it on its way */
628 status = full_request(p, mem_ctx, &blob, &blob);
629 if (!NT_STATUS_IS_OK(status)) {
633 /* unmarshall the NDR */
634 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
635 if (!NT_STATUS_IS_OK(status)) {
639 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
640 pkt.u.alter_ack.num_results == 0 ||
641 pkt.u.alter_ack.ctx_list[0].result != 0) {
642 status = NT_STATUS_UNSUCCESSFUL;
645 /* the bind_ack might contain a reply set of credentials */
646 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
647 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
649 p->security_state.auth_info,
650 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
657 perform a continued bind (and auth3)
659 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
662 struct dcerpc_packet pkt;
666 init_dcerpc_hdr(p, &pkt);
668 pkt.ptype = DCERPC_PKT_AUTH3;
669 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
670 pkt.call_id = next_call_id(p);
673 pkt.u.auth.auth_info = data_blob(NULL, 0);
675 /* construct the NDR form of the packet */
676 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
677 if (!NT_STATUS_IS_OK(status)) {
681 /* send it on its way */
682 status = p->transport.send_request(p, &blob, False);
683 if (!NT_STATUS_IS_OK(status)) {
691 /* perform a dcerpc bind, using the uuid as the key */
692 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
694 const char *uuid, uint_t version)
696 struct dcerpc_syntax_id syntax;
697 struct dcerpc_syntax_id transfer_syntax;
700 status = GUID_from_string(uuid, &syntax.uuid);
701 if (!NT_STATUS_IS_OK(status)) {
702 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
705 syntax.if_version = version;
707 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
708 if (!NT_STATUS_IS_OK(status)) {
711 transfer_syntax.if_version = NDR_GUID_VERSION;
713 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
717 process a fragment received from the transport layer during a
720 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
724 struct dcerpc_packet pkt;
725 struct rpc_request *req;
728 if (!NT_STATUS_IS_OK(status)) {
729 /* all pending requests get the error */
732 req->state = RPC_REQUEST_DONE;
733 req->status = status;
734 DLIST_REMOVE(p->pending, req);
735 if (req->async.callback) {
736 req->async.callback(req);
744 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
746 /* find the matching request. Notice we match before we check
747 the status. this is ok as a pending call_id can never be
749 for (req=p->pending;req;req=req->next) {
750 if (pkt.call_id == req->call_id) break;
754 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
758 if (!NT_STATUS_IS_OK(status)) {
759 req->status = status;
760 req->state = RPC_REQUEST_DONE;
761 DLIST_REMOVE(p->pending, req);
762 if (req->async.callback) {
763 req->async.callback(req);
768 if (pkt.ptype == DCERPC_PKT_FAULT) {
769 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
770 req->fault_code = pkt.u.fault.status;
771 req->status = NT_STATUS_NET_WRITE_FAULT;
772 req->state = RPC_REQUEST_DONE;
773 DLIST_REMOVE(p->pending, req);
774 if (req->async.callback) {
775 req->async.callback(req);
780 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
781 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
783 req->fault_code = DCERPC_FAULT_OTHER;
784 req->status = NT_STATUS_NET_WRITE_FAULT;
785 req->state = RPC_REQUEST_DONE;
786 DLIST_REMOVE(p->pending, req);
787 if (req->async.callback) {
788 req->async.callback(req);
793 length = pkt.u.response.stub_and_verifier.length;
796 req->payload.data = talloc_realloc(req,
798 req->payload.length + length);
799 if (!req->payload.data) {
800 req->status = NT_STATUS_NO_MEMORY;
801 req->state = RPC_REQUEST_DONE;
802 DLIST_REMOVE(p->pending, req);
803 if (req->async.callback) {
804 req->async.callback(req);
808 memcpy(req->payload.data+req->payload.length,
809 pkt.u.response.stub_and_verifier.data, length);
810 req->payload.length += length;
813 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
814 p->transport.send_read(p);
818 /* we've got the full payload */
819 req->state = RPC_REQUEST_DONE;
820 DLIST_REMOVE(p->pending, req);
822 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
823 req->flags |= DCERPC_PULL_BIGENDIAN;
825 req->flags &= ~DCERPC_PULL_BIGENDIAN;
828 if (req->async.callback) {
829 req->async.callback(req);
835 make sure requests are cleaned up
837 static int dcerpc_req_destructor(void *ptr)
839 struct rpc_request *req = ptr;
840 DLIST_REMOVE(req->p->pending, req);
845 perform the send size of a async dcerpc request
847 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
851 DATA_BLOB *stub_data)
853 struct rpc_request *req;
854 struct dcerpc_packet pkt;
856 uint32_t remaining, chunk_size;
857 BOOL first_packet = True;
859 p->transport.recv_data = dcerpc_request_recv_data;
861 req = talloc_p(mem_ctx, struct rpc_request);
867 req->call_id = next_call_id(p);
868 req->status = NT_STATUS_OK;
869 req->state = RPC_REQUEST_PENDING;
870 req->payload = data_blob(NULL, 0);
873 req->async.callback = NULL;
875 init_dcerpc_hdr(p, &pkt);
877 remaining = stub_data->length;
879 /* we can write a full max_recv_frag size, minus the dcerpc
880 request header size */
881 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
883 pkt.ptype = DCERPC_PKT_REQUEST;
884 pkt.call_id = req->call_id;
887 pkt.u.request.alloc_hint = remaining;
888 pkt.u.request.context_id = 0;
889 pkt.u.request.opnum = opnum;
892 pkt.u.request.object.object = *object;
893 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
894 chunk_size -= ndr_size_GUID(0,object,0);
897 DLIST_ADD(p->pending, req);
899 /* we send a series of pdus without waiting for a reply */
900 while (remaining > 0 || first_packet) {
901 uint32_t chunk = MIN(chunk_size, remaining);
902 BOOL last_frag = False;
904 first_packet = False;
905 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
907 if (remaining == stub_data->length) {
908 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
910 if (chunk == remaining) {
911 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
915 pkt.u.request.stub_and_verifier.data = stub_data->data +
916 (stub_data->length - remaining);
917 pkt.u.request.stub_and_verifier.length = chunk;
919 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
920 if (!NT_STATUS_IS_OK(req->status)) {
921 req->state = RPC_REQUEST_DONE;
922 DLIST_REMOVE(p->pending, req);
926 req->status = p->transport.send_request(p, &blob, last_frag);
927 if (!NT_STATUS_IS_OK(req->status)) {
928 req->state = RPC_REQUEST_DONE;
929 DLIST_REMOVE(p->pending, req);
936 talloc_set_destructor(req, dcerpc_req_destructor);
942 return the event context for a dcerpc pipe
943 used by callers who wish to operate asynchronously
945 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
947 return p->transport.event_context(p);
953 perform the receive side of a async dcerpc request
955 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
957 DATA_BLOB *stub_data)
961 while (req->state == RPC_REQUEST_PENDING) {
962 struct event_context *ctx = dcerpc_event_context(req->p);
963 if (event_loop_once(ctx) != 0) {
964 return NT_STATUS_CONNECTION_DISCONNECTED;
967 *stub_data = req->payload;
968 status = req->status;
969 if (stub_data->data) {
970 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
972 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
973 req->p->last_fault_code = req->fault_code;
980 perform a full request/response pair on a dcerpc pipe
982 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
986 DATA_BLOB *stub_data_in,
987 DATA_BLOB *stub_data_out)
989 struct rpc_request *req;
991 req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
993 return NT_STATUS_NO_MEMORY;
996 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1001 this is a paranoid NDR validator. For every packet we push onto the wire
1002 we pull it back again, then push it again. Then we compare the raw NDR data
1003 for that to the NDR we initially generated. If they don't match then we know
1004 we must have a bug in either the pull or push side of our code
1006 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
1007 TALLOC_CTX *mem_ctx,
1010 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1011 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1014 struct ndr_pull *pull;
1015 struct ndr_push *push;
1019 st = talloc(mem_ctx, struct_size);
1021 return NT_STATUS_NO_MEMORY;
1024 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1026 return NT_STATUS_NO_MEMORY;
1029 status = ndr_pull(pull, NDR_IN, st);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1032 "failed input validation pull - %s",
1036 push = ndr_push_init_ctx(mem_ctx);
1038 return NT_STATUS_NO_MEMORY;
1041 status = ndr_push(push, NDR_IN, st);
1042 if (!NT_STATUS_IS_OK(status)) {
1043 return ndr_push_error(push, NDR_ERR_VALIDATE,
1044 "failed input validation push - %s",
1048 blob2 = ndr_push_blob(push);
1050 if (!data_blob_equal(&blob, &blob2)) {
1051 DEBUG(3,("original:\n"));
1052 dump_data(3, blob.data, blob.length);
1053 DEBUG(3,("secondary:\n"));
1054 dump_data(3, blob2.data, blob2.length);
1055 return ndr_push_error(push, NDR_ERR_VALIDATE,
1056 "failed input validation data - %s",
1060 return NT_STATUS_OK;
1064 this is a paranoid NDR input validator. For every packet we pull
1065 from the wire we push it back again then pull and push it
1066 again. Then we compare the raw NDR data for that to the NDR we
1067 initially generated. If they don't match then we know we must have a
1068 bug in either the pull or push side of our code
1070 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1071 TALLOC_CTX *mem_ctx,
1074 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1075 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1078 struct ndr_pull *pull;
1079 struct ndr_push *push;
1081 DATA_BLOB blob, blob2;
1083 st = talloc(mem_ctx, struct_size);
1085 return NT_STATUS_NO_MEMORY;
1087 memcpy(st, struct_ptr, struct_size);
1089 push = ndr_push_init_ctx(mem_ctx);
1091 return NT_STATUS_NO_MEMORY;
1094 status = ndr_push(push, NDR_OUT, struct_ptr);
1095 if (!NT_STATUS_IS_OK(status)) {
1096 return ndr_push_error(push, NDR_ERR_VALIDATE,
1097 "failed output validation push - %s",
1101 blob = ndr_push_blob(push);
1103 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1105 return NT_STATUS_NO_MEMORY;
1108 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1109 status = ndr_pull(pull, NDR_OUT, st);
1110 if (!NT_STATUS_IS_OK(status)) {
1111 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1112 "failed output validation pull - %s",
1116 push = ndr_push_init_ctx(mem_ctx);
1118 return NT_STATUS_NO_MEMORY;
1121 status = ndr_push(push, NDR_OUT, st);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 return ndr_push_error(push, NDR_ERR_VALIDATE,
1124 "failed output validation push2 - %s",
1128 blob2 = ndr_push_blob(push);
1130 if (!data_blob_equal(&blob, &blob2)) {
1131 DEBUG(3,("original:\n"));
1132 dump_data(3, blob.data, blob.length);
1133 DEBUG(3,("secondary:\n"));
1134 dump_data(3, blob2.data, blob2.length);
1135 return ndr_push_error(push, NDR_ERR_VALIDATE,
1136 "failed output validation data - %s",
1140 return NT_STATUS_OK;
1145 send a rpc request with a given set of ndr helper functions
1147 call dcerpc_ndr_request_recv() to receive the answer
1149 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1150 struct GUID *object,
1152 TALLOC_CTX *mem_ctx,
1153 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1154 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1158 struct ndr_push *push;
1161 struct rpc_request *req;
1163 /* setup for a ndr_push_* call */
1164 push = ndr_push_init();
1169 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1170 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1173 /* push the structure into a blob */
1174 status = ndr_push(push, NDR_IN, struct_ptr);
1175 if (!NT_STATUS_IS_OK(status)) {
1176 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1177 nt_errstr(status)));
1178 ndr_push_free(push);
1182 /* retrieve the blob */
1183 request = ndr_push_blob(push);
1185 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1186 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size,
1187 ndr_push, ndr_pull);
1188 if (!NT_STATUS_IS_OK(status)) {
1189 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1190 nt_errstr(status)));
1191 ndr_push_free(push);
1196 DEBUG(10,("rpc request data:\n"));
1197 dump_data(10, request.data, request.length);
1199 /* make the actual dcerpc request */
1200 req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1203 req->ndr.ndr_push = ndr_push;
1204 req->ndr.ndr_pull = ndr_pull;
1205 req->ndr.struct_ptr = struct_ptr;
1206 req->ndr.struct_size = struct_size;
1207 req->ndr.mem_ctx = mem_ctx;
1210 ndr_push_free(push);
1216 receive the answer from a dcerpc_ndr_request_send()
1218 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1220 struct dcerpc_pipe *p = req->p;
1223 struct ndr_pull *pull;
1224 struct rpc_request_ndr ndr = req->ndr;
1227 /* make sure the recv code doesn't free the request, as we
1228 need to grab the flags element before it is freed */
1229 talloc_increase_ref_count(req);
1231 status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1232 if (!NT_STATUS_IS_OK(status)) {
1239 /* prepare for ndr_pull_* */
1240 pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1242 return NT_STATUS_NO_MEMORY;
1245 if (flags & DCERPC_PULL_BIGENDIAN) {
1246 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1249 DEBUG(10,("rpc reply data:\n"));
1250 dump_data(10, pull->data, pull->data_size);
1252 /* pull the structure from the blob */
1253 status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1254 if (!NT_STATUS_IS_OK(status)) {
1258 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1259 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
1260 ndr.ndr_push, ndr.ndr_pull);
1261 if (!NT_STATUS_IS_OK(status)) {
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 struct GUID *object,
1289 TALLOC_CTX *mem_ctx,
1290 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1291 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1295 struct rpc_request *req;
1297 req = dcerpc_ndr_request_send(p, object, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1299 return NT_STATUS_NO_MEMORY;
1302 return dcerpc_ndr_request_recv(req);
1307 a useful function for retrieving the server name we connected to
1309 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1311 if (!p->transport.peer_name) {
1314 return p->transport.peer_name(p);
1318 a useful function to get the auth_level
1321 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1325 if (p->flags & DCERPC_SEAL) {
1326 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1327 } else if (p->flags & DCERPC_SIGN) {
1328 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1329 } else if (p->flags & DCERPC_CONNECT) {
1330 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1332 auth_level = DCERPC_AUTH_LEVEL_NONE;