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 /* initialise a dcerpc pipe. */
28 struct dcerpc_pipe *dcerpc_pipe_init(void)
30 struct dcerpc_pipe *p;
32 p = talloc_p(NULL, struct dcerpc_pipe);
37 p->reference_count = 0;
39 p->security_state.auth_info = NULL;
40 p->security_state.session_key = dcerpc_generic_session_key;
41 p->security_state.generic_state = NULL;
42 p->binding_string = NULL;
44 p->srv_max_xmit_frag = 0;
45 p->srv_max_recv_frag = 0;
46 p->last_fault_code = 0;
53 choose the next call id to use
55 static uint32_t next_call_id(struct dcerpc_pipe *p)
58 if (p->call_id == 0) {
64 /* close down a dcerpc over SMB pipe */
65 void dcerpc_pipe_close(struct dcerpc_pipe *p)
69 if (p->reference_count <= 0) {
70 if (p->security_state.generic_state) {
71 gensec_end(&p->security_state.generic_state);
73 p->transport.shutdown_pipe(p);
78 /* we need to be able to get/set the fragment length without doing a full
80 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
82 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
83 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
85 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
89 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
91 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
92 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
94 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
98 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
100 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
101 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
103 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
109 setup for a ndr pull, also setting up any flags from the binding string
111 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
113 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
115 if (ndr == NULL) return ndr;
117 if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
118 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
121 if (p->flags & DCERPC_NDR_REF_ALLOC) {
122 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
129 parse a data blob into a dcerpc_packet structure. This handles both
130 input and output packets
132 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
133 struct dcerpc_packet *pkt)
135 struct ndr_pull *ndr;
137 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
139 return NT_STATUS_NO_MEMORY;
142 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
143 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
146 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
150 generate a CONNECT level verifier
152 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
154 *blob = data_blob_talloc(mem_ctx, NULL, 16);
155 if (blob->data == NULL) {
156 return NT_STATUS_NO_MEMORY;
158 SIVAL(blob->data, 0, 1);
159 memset(blob->data+4, 0, 12);
164 generate a CONNECT level verifier
166 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
168 if (blob->length != 16 ||
169 IVAL(blob->data, 0) != 1) {
170 return NT_STATUS_ACCESS_DENIED;
176 parse a possibly signed blob into a dcerpc request packet structure
178 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
179 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
180 struct dcerpc_packet *pkt)
182 struct ndr_pull *ndr;
184 struct dcerpc_auth auth;
187 /* non-signed packets are simpler */
188 if (!p->security_state.auth_info ||
189 !p->security_state.generic_state) {
190 return dcerpc_pull(p, blob, mem_ctx, pkt);
193 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
195 return NT_STATUS_NO_MEMORY;
198 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
199 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
202 /* pull the basic packet */
203 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
204 if (!NT_STATUS_IS_OK(status)) {
208 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
212 if (pkt->auth_length == 0 &&
213 p->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
217 auth_blob.length = 8 + pkt->auth_length;
219 /* check for a valid length */
220 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
221 return NT_STATUS_INFO_LENGTH_MISMATCH;
225 pkt->u.response.stub_and_verifier.data +
226 pkt->u.response.stub_and_verifier.length - auth_blob.length;
227 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
229 /* pull the auth structure */
230 ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
232 return NT_STATUS_NO_MEMORY;
235 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
236 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
239 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
240 if (!NT_STATUS_IS_OK(status)) {
245 /* check signature or unseal the packet */
246 switch (p->security_state.auth_info->auth_level) {
247 case DCERPC_AUTH_LEVEL_PRIVACY:
248 status = gensec_unseal_packet(p->security_state.generic_state,
250 blob->data + DCERPC_REQUEST_LENGTH,
251 pkt->u.response.stub_and_verifier.length,
253 blob->length - auth.credentials.length,
255 memcpy(pkt->u.response.stub_and_verifier.data,
256 blob->data + DCERPC_REQUEST_LENGTH,
257 pkt->u.response.stub_and_verifier.length);
260 case DCERPC_AUTH_LEVEL_INTEGRITY:
261 status = gensec_check_packet(p->security_state.generic_state,
263 pkt->u.response.stub_and_verifier.data,
264 pkt->u.response.stub_and_verifier.length,
266 blob->length - auth.credentials.length,
270 case DCERPC_AUTH_LEVEL_CONNECT:
271 status = dcerpc_check_connect_verifier(&auth.credentials);
274 case DCERPC_AUTH_LEVEL_NONE:
278 status = NT_STATUS_INVALID_LEVEL;
282 /* remove the indicated amount of paddiing */
283 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
284 return NT_STATUS_INFO_LENGTH_MISMATCH;
286 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
293 push a dcerpc request packet into a blob, possibly signing it.
295 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
296 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
297 struct dcerpc_packet *pkt)
300 struct ndr_push *ndr;
303 /* non-signed packets are simpler */
304 if (!p->security_state.auth_info ||
305 !p->security_state.generic_state) {
306 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
309 ndr = ndr_push_init_ctx(mem_ctx);
311 return NT_STATUS_NO_MEMORY;
314 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
315 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
318 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
319 if (!NT_STATUS_IS_OK(status)) {
323 /* pad to 16 byte multiple in the payload portion of the
324 packet. This matches what w2k3 does */
325 p->security_state.auth_info->auth_pad_length =
326 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
327 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
329 /* sign or seal the packet */
330 switch (p->security_state.auth_info->auth_level) {
331 case DCERPC_AUTH_LEVEL_PRIVACY:
332 case DCERPC_AUTH_LEVEL_INTEGRITY:
333 p->security_state.auth_info->credentials
334 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
335 data_blob_clear(&p->security_state.auth_info->credentials);
338 case DCERPC_AUTH_LEVEL_CONNECT:
339 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
342 case DCERPC_AUTH_LEVEL_NONE:
343 p->security_state.auth_info->credentials = data_blob(NULL, 0);
347 status = NT_STATUS_INVALID_LEVEL;
351 if (!NT_STATUS_IS_OK(status)) {
355 /* add the auth verifier */
356 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
357 if (!NT_STATUS_IS_OK(status)) {
361 /* extract the whole packet as a blob */
362 *blob = ndr_push_blob(ndr);
364 /* fill in the fragment length and auth_length, we can't fill
365 in these earlier as we don't know the signature length (it
366 could be variable length) */
367 dcerpc_set_frag_length(blob, blob->length);
368 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
370 /* sign or seal the packet */
371 switch (p->security_state.auth_info->auth_level) {
372 case DCERPC_AUTH_LEVEL_PRIVACY:
373 status = gensec_seal_packet(p->security_state.generic_state,
375 blob->data + DCERPC_REQUEST_LENGTH,
376 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
379 p->security_state.auth_info->credentials.length,
381 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
384 case DCERPC_AUTH_LEVEL_INTEGRITY:
385 status = gensec_sign_packet(p->security_state.generic_state,
387 blob->data + DCERPC_REQUEST_LENGTH,
388 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
391 p->security_state.auth_info->credentials.length,
393 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
396 case DCERPC_AUTH_LEVEL_CONNECT:
399 case DCERPC_AUTH_LEVEL_NONE:
400 p->security_state.auth_info->credentials = data_blob(NULL, 0);
404 status = NT_STATUS_INVALID_LEVEL;
408 data_blob_free(&p->security_state.auth_info->credentials);
415 fill in the fixed values in a dcerpc header
417 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
420 pkt->rpc_vers_minor = 0;
421 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
424 pkt->drep[0] = DCERPC_DREP_LE;
432 hold the state of pending full requests
434 struct full_request_state {
435 DATA_BLOB *reply_blob;
440 receive a reply to a full request
442 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
445 struct full_request_state *state = p->full_request_private;
447 if (!NT_STATUS_IS_OK(status)) {
448 state->status = status;
451 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
452 state->reply_blob = NULL;
456 perform a single pdu synchronous request - used for the bind code
457 this cannot be mixed with normal async requests
459 static NTSTATUS full_request(struct dcerpc_pipe *p,
461 DATA_BLOB *request_blob,
462 DATA_BLOB *reply_blob)
464 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
468 return NT_STATUS_NO_MEMORY;
471 state->reply_blob = reply_blob;
472 state->status = NT_STATUS_OK;
474 p->transport.recv_data = full_request_recv;
475 p->full_request_private = state;
477 status = p->transport.send_request(p, request_blob, True);
478 if (!NT_STATUS_IS_OK(status)) {
482 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
483 struct event_context *ctx = p->transport.event_context(p);
484 if (event_loop_once(ctx) != 0) {
485 return NT_STATUS_CONNECTION_DISCONNECTED;
489 return state->status;
494 perform a bind using the given syntax
496 the auth_info structure is updated with the reply authentication info
499 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
501 const struct dcerpc_syntax_id *syntax,
502 const struct dcerpc_syntax_id *transfer_syntax)
504 struct dcerpc_packet pkt;
509 p->transfer_syntax = *transfer_syntax;
511 init_dcerpc_hdr(p, &pkt);
513 pkt.ptype = DCERPC_PKT_BIND;
514 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
515 pkt.call_id = p->call_id;
518 pkt.u.bind.max_xmit_frag = 5840;
519 pkt.u.bind.max_recv_frag = 5840;
520 pkt.u.bind.assoc_group_id = 0;
521 pkt.u.bind.num_contexts = 1;
522 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
523 if (!pkt.u.bind.ctx_list) {
524 return NT_STATUS_NO_MEMORY;
526 pkt.u.bind.ctx_list[0].context_id = 0;
527 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
528 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
529 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
530 pkt.u.bind.auth_info = data_blob(NULL, 0);
532 /* construct the NDR form of the packet */
533 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
534 if (!NT_STATUS_IS_OK(status)) {
538 /* send it on its way */
539 status = full_request(p, mem_ctx, &blob, &blob);
540 if (!NT_STATUS_IS_OK(status)) {
544 /* unmarshall the NDR */
545 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
546 if (!NT_STATUS_IS_OK(status)) {
550 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
551 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
552 return NT_STATUS_ACCESS_DENIED;
555 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
556 pkt.u.bind_ack.num_results == 0 ||
557 pkt.u.bind_ack.ctx_list[0].result != 0) {
558 return NT_STATUS_UNSUCCESSFUL;
561 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
562 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
563 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
566 /* the bind_ack might contain a reply set of credentials */
567 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
568 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
570 p->security_state.auth_info,
571 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
578 perform a alter context using the given syntax
580 the auth_info structure is updated with the reply authentication info
583 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
586 struct dcerpc_packet pkt;
590 init_dcerpc_hdr(p, &pkt);
592 pkt.ptype = DCERPC_PKT_ALTER;
593 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
594 pkt.call_id = p->call_id;
597 pkt.u.alter.max_xmit_frag = 0x2000;
598 pkt.u.alter.max_recv_frag = 0x2000;
599 pkt.u.alter.assoc_group_id = 0;
600 pkt.u.alter.num_contexts = 1;
601 pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
602 if (!pkt.u.alter.ctx_list) {
603 return NT_STATUS_NO_MEMORY;
605 pkt.u.alter.ctx_list[0].context_id = 0;
606 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
607 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
608 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
609 pkt.u.alter.auth_info = data_blob(NULL, 0);
611 /* construct the NDR form of the packet */
612 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
613 if (!NT_STATUS_IS_OK(status)) {
617 /* send it on its way */
618 status = full_request(p, mem_ctx, &blob, &blob);
619 if (!NT_STATUS_IS_OK(status)) {
623 /* unmarshall the NDR */
624 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
625 if (!NT_STATUS_IS_OK(status)) {
629 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
630 pkt.u.alter_ack.num_results == 0 ||
631 pkt.u.alter_ack.ctx_list[0].result != 0) {
632 status = NT_STATUS_UNSUCCESSFUL;
635 /* the bind_ack might contain a reply set of credentials */
636 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
637 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
639 p->security_state.auth_info,
640 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
647 perform a continued bind (and auth3)
649 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
652 struct dcerpc_packet pkt;
656 init_dcerpc_hdr(p, &pkt);
658 pkt.ptype = DCERPC_PKT_AUTH3;
659 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
660 pkt.call_id = next_call_id(p);
663 pkt.u.auth.auth_info = data_blob(NULL, 0);
665 /* construct the NDR form of the packet */
666 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
667 if (!NT_STATUS_IS_OK(status)) {
671 /* send it on its way */
672 status = p->transport.send_request(p, &blob, False);
673 if (!NT_STATUS_IS_OK(status)) {
681 /* perform a dcerpc bind, using the uuid as the key */
682 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
684 const char *uuid, uint_t version)
686 struct dcerpc_syntax_id syntax;
687 struct dcerpc_syntax_id transfer_syntax;
690 status = GUID_from_string(uuid, &syntax.uuid);
691 if (!NT_STATUS_IS_OK(status)) {
692 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
695 syntax.if_version = version;
697 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
698 if (!NT_STATUS_IS_OK(status)) {
701 transfer_syntax.if_version = NDR_GUID_VERSION;
703 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
707 process a fragment received from the transport layer during a
710 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
714 struct dcerpc_packet pkt;
715 struct rpc_request *req;
718 if (!NT_STATUS_IS_OK(status)) {
719 /* all pending requests get the error */
722 req->state = RPC_REQUEST_DONE;
723 req->status = status;
724 DLIST_REMOVE(p->pending, req);
725 if (req->async.callback) {
726 req->async.callback(req);
734 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
736 /* find the matching request. Notice we match before we check
737 the status. this is ok as a pending call_id can never be
739 for (req=p->pending;req;req=req->next) {
740 if (pkt.call_id == req->call_id) break;
744 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
748 if (!NT_STATUS_IS_OK(status)) {
749 req->status = status;
750 req->state = RPC_REQUEST_DONE;
751 DLIST_REMOVE(p->pending, req);
752 if (req->async.callback) {
753 req->async.callback(req);
758 if (pkt.ptype == DCERPC_PKT_FAULT) {
759 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
760 req->fault_code = pkt.u.fault.status;
761 req->status = NT_STATUS_NET_WRITE_FAULT;
762 req->state = RPC_REQUEST_DONE;
763 DLIST_REMOVE(p->pending, req);
764 if (req->async.callback) {
765 req->async.callback(req);
770 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
771 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
773 req->fault_code = DCERPC_FAULT_OTHER;
774 req->status = NT_STATUS_NET_WRITE_FAULT;
775 req->state = RPC_REQUEST_DONE;
776 DLIST_REMOVE(p->pending, req);
777 if (req->async.callback) {
778 req->async.callback(req);
783 length = pkt.u.response.stub_and_verifier.length;
786 req->payload.data = talloc_realloc(req,
788 req->payload.length + length);
789 if (!req->payload.data) {
790 req->status = NT_STATUS_NO_MEMORY;
791 req->state = RPC_REQUEST_DONE;
792 DLIST_REMOVE(p->pending, req);
793 if (req->async.callback) {
794 req->async.callback(req);
798 memcpy(req->payload.data+req->payload.length,
799 pkt.u.response.stub_and_verifier.data, length);
800 req->payload.length += length;
803 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
804 p->transport.send_read(p);
808 /* we've got the full payload */
809 req->state = RPC_REQUEST_DONE;
810 DLIST_REMOVE(p->pending, req);
812 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
813 req->flags |= DCERPC_PULL_BIGENDIAN;
815 req->flags &= ~DCERPC_PULL_BIGENDIAN;
818 if (req->async.callback) {
819 req->async.callback(req);
825 make sure requests are cleaned up
827 static int dcerpc_req_destructor(void *ptr)
829 struct rpc_request *req = ptr;
830 DLIST_REMOVE(req->p->pending, req);
835 perform the send size of a async dcerpc request
837 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
841 DATA_BLOB *stub_data)
843 struct rpc_request *req;
844 struct dcerpc_packet pkt;
846 uint32_t remaining, chunk_size;
847 BOOL first_packet = True;
849 p->transport.recv_data = dcerpc_request_recv_data;
851 req = talloc_p(mem_ctx, struct rpc_request);
857 req->call_id = next_call_id(p);
858 req->status = NT_STATUS_OK;
859 req->state = RPC_REQUEST_PENDING;
860 req->payload = data_blob(NULL, 0);
863 req->async.callback = NULL;
865 init_dcerpc_hdr(p, &pkt);
867 remaining = stub_data->length;
869 /* we can write a full max_recv_frag size, minus the dcerpc
870 request header size */
871 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
873 pkt.ptype = DCERPC_PKT_REQUEST;
874 pkt.call_id = req->call_id;
876 pkt.u.request.alloc_hint = remaining;
877 pkt.u.request.context_id = 0;
878 pkt.u.request.opnum = opnum;
880 pkt.object.object = *object;
881 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
882 /* FIXME: pfc_cflags is reset below! */
885 DLIST_ADD(p->pending, req);
887 /* we send a series of pdus without waiting for a reply */
888 while (remaining > 0 || first_packet) {
889 uint32_t chunk = MIN(chunk_size, remaining);
890 BOOL last_frag = False;
892 first_packet = False;
895 if (remaining == stub_data->length) {
896 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
898 if (chunk == remaining) {
899 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
903 pkt.u.request.stub_and_verifier.data = stub_data->data +
904 (stub_data->length - remaining);
905 pkt.u.request.stub_and_verifier.length = chunk;
907 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
908 if (!NT_STATUS_IS_OK(req->status)) {
909 req->state = RPC_REQUEST_DONE;
910 DLIST_REMOVE(p->pending, req);
914 req->status = p->transport.send_request(p, &blob, last_frag);
915 if (!NT_STATUS_IS_OK(req->status)) {
916 req->state = RPC_REQUEST_DONE;
917 DLIST_REMOVE(p->pending, req);
924 talloc_set_destructor(req, dcerpc_req_destructor);
930 return the event context for a dcerpc pipe
931 used by callers who wish to operate asynchronously
933 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
935 return p->transport.event_context(p);
941 perform the receive side of a async dcerpc request
943 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
945 DATA_BLOB *stub_data)
949 while (req->state == RPC_REQUEST_PENDING) {
950 struct event_context *ctx = dcerpc_event_context(req->p);
951 if (event_loop_once(ctx) != 0) {
952 return NT_STATUS_CONNECTION_DISCONNECTED;
955 *stub_data = req->payload;
956 status = req->status;
957 if (stub_data->data) {
958 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
960 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
961 req->p->last_fault_code = req->fault_code;
968 perform a full request/response pair on a dcerpc pipe
970 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
974 DATA_BLOB *stub_data_in,
975 DATA_BLOB *stub_data_out)
977 struct rpc_request *req;
979 req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
981 return NT_STATUS_NO_MEMORY;
984 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
989 this is a paranoid NDR validator. For every packet we push onto the wire
990 we pull it back again, then push it again. Then we compare the raw NDR data
991 for that to the NDR we initially generated. If they don't match then we know
992 we must have a bug in either the pull or push side of our code
994 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
998 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
999 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1002 struct ndr_pull *pull;
1003 struct ndr_push *push;
1007 st = talloc(mem_ctx, struct_size);
1009 return NT_STATUS_NO_MEMORY;
1012 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1014 return NT_STATUS_NO_MEMORY;
1017 status = ndr_pull(pull, NDR_IN, st);
1018 if (!NT_STATUS_IS_OK(status)) {
1019 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1020 "failed input validation pull - %s",
1024 push = ndr_push_init_ctx(mem_ctx);
1026 return NT_STATUS_NO_MEMORY;
1029 status = ndr_push(push, NDR_IN, st);
1030 if (!NT_STATUS_IS_OK(status)) {
1031 return ndr_push_error(push, NDR_ERR_VALIDATE,
1032 "failed input validation push - %s",
1036 blob2 = ndr_push_blob(push);
1038 if (!data_blob_equal(&blob, &blob2)) {
1039 DEBUG(3,("original:\n"));
1040 dump_data(3, blob.data, blob.length);
1041 DEBUG(3,("secondary:\n"));
1042 dump_data(3, blob2.data, blob2.length);
1043 return ndr_push_error(push, NDR_ERR_VALIDATE,
1044 "failed input validation data - %s",
1048 return NT_STATUS_OK;
1052 this is a paranoid NDR input validator. For every packet we pull
1053 from the wire we push it back again then pull and push it
1054 again. Then we compare the raw NDR data for that to the NDR we
1055 initially generated. If they don't match then we know we must have a
1056 bug in either the pull or push side of our code
1058 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1059 TALLOC_CTX *mem_ctx,
1062 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1063 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1066 struct ndr_pull *pull;
1067 struct ndr_push *push;
1069 DATA_BLOB blob, blob2;
1071 st = talloc(mem_ctx, struct_size);
1073 return NT_STATUS_NO_MEMORY;
1075 memcpy(st, struct_ptr, struct_size);
1077 push = ndr_push_init_ctx(mem_ctx);
1079 return NT_STATUS_NO_MEMORY;
1082 status = ndr_push(push, NDR_OUT, struct_ptr);
1083 if (!NT_STATUS_IS_OK(status)) {
1084 return ndr_push_error(push, NDR_ERR_VALIDATE,
1085 "failed output validation push - %s",
1089 blob = ndr_push_blob(push);
1091 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1093 return NT_STATUS_NO_MEMORY;
1096 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1097 status = ndr_pull(pull, NDR_OUT, st);
1098 if (!NT_STATUS_IS_OK(status)) {
1099 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1100 "failed output validation pull - %s",
1104 push = ndr_push_init_ctx(mem_ctx);
1106 return NT_STATUS_NO_MEMORY;
1109 status = ndr_push(push, NDR_OUT, st);
1110 if (!NT_STATUS_IS_OK(status)) {
1111 return ndr_push_error(push, NDR_ERR_VALIDATE,
1112 "failed output validation push2 - %s",
1116 blob2 = ndr_push_blob(push);
1118 if (!data_blob_equal(&blob, &blob2)) {
1119 DEBUG(3,("original:\n"));
1120 dump_data(3, blob.data, blob.length);
1121 DEBUG(3,("secondary:\n"));
1122 dump_data(3, blob2.data, blob2.length);
1123 return ndr_push_error(push, NDR_ERR_VALIDATE,
1124 "failed output validation data - %s",
1128 return NT_STATUS_OK;
1133 send a rpc request with a given set of ndr helper functions
1135 call dcerpc_ndr_request_recv() to receive the answer
1137 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1138 struct GUID *object,
1140 TALLOC_CTX *mem_ctx,
1141 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1142 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1146 struct ndr_push *push;
1149 struct rpc_request *req;
1151 /* setup for a ndr_push_* call */
1152 push = ndr_push_init();
1157 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1158 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1161 /* push the structure into a blob */
1162 status = ndr_push(push, NDR_IN, struct_ptr);
1163 if (!NT_STATUS_IS_OK(status)) {
1164 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1165 nt_errstr(status)));
1166 ndr_push_free(push);
1170 /* retrieve the blob */
1171 request = ndr_push_blob(push);
1173 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1174 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size,
1175 ndr_push, ndr_pull);
1176 if (!NT_STATUS_IS_OK(status)) {
1177 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1178 nt_errstr(status)));
1179 ndr_push_free(push);
1184 DEBUG(10,("rpc request data:\n"));
1185 dump_data(10, request.data, request.length);
1187 /* make the actual dcerpc request */
1188 req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1191 req->ndr.ndr_push = ndr_push;
1192 req->ndr.ndr_pull = ndr_pull;
1193 req->ndr.struct_ptr = struct_ptr;
1194 req->ndr.struct_size = struct_size;
1195 req->ndr.mem_ctx = mem_ctx;
1198 ndr_push_free(push);
1204 receive the answer from a dcerpc_ndr_request_send()
1206 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1208 struct dcerpc_pipe *p = req->p;
1211 struct ndr_pull *pull;
1212 struct rpc_request_ndr ndr = req->ndr;
1215 /* make sure the recv code doesn't free the request, as we
1216 need to grab the flags element before it is freed */
1217 talloc_increase_ref_count(req);
1219 status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1220 if (!NT_STATUS_IS_OK(status)) {
1227 /* prepare for ndr_pull_* */
1228 pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1230 return NT_STATUS_NO_MEMORY;
1233 if (flags & DCERPC_PULL_BIGENDIAN) {
1234 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1237 DEBUG(10,("rpc reply data:\n"));
1238 dump_data(10, pull->data, pull->data_size);
1240 /* pull the structure from the blob */
1241 status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1242 if (!NT_STATUS_IS_OK(status)) {
1246 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1247 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
1248 ndr.ndr_push, ndr.ndr_pull);
1249 if (!NT_STATUS_IS_OK(status)) {
1254 if (pull->offset != pull->data_size) {
1255 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1256 pull->data_size - pull->offset));
1257 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1258 but it turns out that early versions of NT
1259 (specifically NT3.1) add junk onto the end of rpc
1260 packets, so if we want to interoperate at all with
1261 those versions then we need to ignore this error */
1264 return NT_STATUS_OK;
1269 a useful helper function for synchronous rpc requests
1271 this can be used when you have ndr push/pull functions in the
1274 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1275 struct GUID *object,
1277 TALLOC_CTX *mem_ctx,
1278 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1279 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1283 struct rpc_request *req;
1285 req = dcerpc_ndr_request_send(p, object, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1287 return NT_STATUS_NO_MEMORY;
1290 return dcerpc_ndr_request_recv(req);
1295 a useful function for retrieving the server name we connected to
1297 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1299 if (!p->transport.peer_name) {
1302 return p->transport.peer_name(p);
1306 a useful function to get the auth_level
1309 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1313 if (p->flags & DCERPC_SEAL) {
1314 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1315 } else if (p->flags & DCERPC_SIGN) {
1316 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1317 } else if (p->flags & DCERPC_CONNECT) {
1318 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1320 auth_level = DCERPC_AUTH_LEVEL_NONE;