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 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
325 if (!NT_STATUS_IS_OK(status)) {
329 /* pad to 16 byte multiple in the payload portion of the
330 packet. This matches what w2k3 does */
331 p->security_state.auth_info->auth_pad_length =
332 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
333 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
335 /* sign or seal the packet */
336 switch (p->security_state.auth_info->auth_level) {
337 case DCERPC_AUTH_LEVEL_PRIVACY:
338 case DCERPC_AUTH_LEVEL_INTEGRITY:
339 p->security_state.auth_info->credentials
340 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
341 data_blob_clear(&p->security_state.auth_info->credentials);
344 case DCERPC_AUTH_LEVEL_CONNECT:
345 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
348 case DCERPC_AUTH_LEVEL_NONE:
349 p->security_state.auth_info->credentials = data_blob(NULL, 0);
353 status = NT_STATUS_INVALID_LEVEL;
357 if (!NT_STATUS_IS_OK(status)) {
361 /* add the auth verifier */
362 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
363 if (!NT_STATUS_IS_OK(status)) {
367 /* extract the whole packet as a blob */
368 *blob = ndr_push_blob(ndr);
370 /* fill in the fragment length and auth_length, we can't fill
371 in these earlier as we don't know the signature length (it
372 could be variable length) */
373 dcerpc_set_frag_length(blob, blob->length);
374 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
376 /* sign or seal the packet */
377 switch (p->security_state.auth_info->auth_level) {
378 case DCERPC_AUTH_LEVEL_PRIVACY:
379 status = gensec_seal_packet(p->security_state.generic_state,
381 blob->data + DCERPC_REQUEST_LENGTH,
382 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
385 p->security_state.auth_info->credentials.length,
387 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
390 case DCERPC_AUTH_LEVEL_INTEGRITY:
391 status = gensec_sign_packet(p->security_state.generic_state,
393 blob->data + DCERPC_REQUEST_LENGTH,
394 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
397 p->security_state.auth_info->credentials.length,
399 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
402 case DCERPC_AUTH_LEVEL_CONNECT:
405 case DCERPC_AUTH_LEVEL_NONE:
406 p->security_state.auth_info->credentials = data_blob(NULL, 0);
410 status = NT_STATUS_INVALID_LEVEL;
414 data_blob_free(&p->security_state.auth_info->credentials);
421 fill in the fixed values in a dcerpc header
423 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
426 pkt->rpc_vers_minor = 0;
427 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
430 pkt->drep[0] = DCERPC_DREP_LE;
438 hold the state of pending full requests
440 struct full_request_state {
441 DATA_BLOB *reply_blob;
446 receive a reply to a full request
448 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
451 struct full_request_state *state = p->full_request_private;
453 if (!NT_STATUS_IS_OK(status)) {
454 state->status = status;
457 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
458 state->reply_blob = NULL;
462 perform a single pdu synchronous request - used for the bind code
463 this cannot be mixed with normal async requests
465 static NTSTATUS full_request(struct dcerpc_pipe *p,
467 DATA_BLOB *request_blob,
468 DATA_BLOB *reply_blob)
470 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
474 return NT_STATUS_NO_MEMORY;
477 state->reply_blob = reply_blob;
478 state->status = NT_STATUS_OK;
480 p->transport.recv_data = full_request_recv;
481 p->full_request_private = state;
483 status = p->transport.send_request(p, request_blob, True);
484 if (!NT_STATUS_IS_OK(status)) {
488 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
489 struct event_context *ctx = p->transport.event_context(p);
490 if (event_loop_once(ctx) != 0) {
491 return NT_STATUS_CONNECTION_DISCONNECTED;
495 return state->status;
500 perform a bind using the given syntax
502 the auth_info structure is updated with the reply authentication info
505 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
507 const struct dcerpc_syntax_id *syntax,
508 const struct dcerpc_syntax_id *transfer_syntax)
510 struct dcerpc_packet pkt;
515 p->transfer_syntax = *transfer_syntax;
517 init_dcerpc_hdr(p, &pkt);
519 pkt.ptype = DCERPC_PKT_BIND;
520 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
521 pkt.call_id = p->call_id;
524 pkt.u.bind.max_xmit_frag = 5840;
525 pkt.u.bind.max_recv_frag = 5840;
526 pkt.u.bind.assoc_group_id = 0;
527 pkt.u.bind.num_contexts = 1;
528 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
529 if (!pkt.u.bind.ctx_list) {
530 return NT_STATUS_NO_MEMORY;
532 pkt.u.bind.ctx_list[0].context_id = 0;
533 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
534 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
535 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
536 pkt.u.bind.auth_info = data_blob(NULL, 0);
538 /* construct the NDR form of the packet */
539 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
540 if (!NT_STATUS_IS_OK(status)) {
544 /* send it on its way */
545 status = full_request(p, mem_ctx, &blob, &blob);
546 if (!NT_STATUS_IS_OK(status)) {
550 /* unmarshall the NDR */
551 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
552 if (!NT_STATUS_IS_OK(status)) {
556 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
557 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
558 return NT_STATUS_ACCESS_DENIED;
561 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
562 pkt.u.bind_ack.num_results == 0 ||
563 pkt.u.bind_ack.ctx_list[0].result != 0) {
564 return NT_STATUS_UNSUCCESSFUL;
567 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
568 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
569 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
572 /* the bind_ack might contain a reply set of credentials */
573 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
574 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
576 p->security_state.auth_info,
577 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
584 perform a alter context using the given syntax
586 the auth_info structure is updated with the reply authentication info
589 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
592 struct dcerpc_packet pkt;
596 init_dcerpc_hdr(p, &pkt);
598 pkt.ptype = DCERPC_PKT_ALTER;
599 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
600 pkt.call_id = p->call_id;
603 pkt.u.alter.max_xmit_frag = 0x2000;
604 pkt.u.alter.max_recv_frag = 0x2000;
605 pkt.u.alter.assoc_group_id = 0;
606 pkt.u.alter.num_contexts = 1;
607 pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
608 if (!pkt.u.alter.ctx_list) {
609 return NT_STATUS_NO_MEMORY;
611 pkt.u.alter.ctx_list[0].context_id = 0;
612 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
613 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
614 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
615 pkt.u.alter.auth_info = data_blob(NULL, 0);
617 /* construct the NDR form of the packet */
618 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
619 if (!NT_STATUS_IS_OK(status)) {
623 /* send it on its way */
624 status = full_request(p, mem_ctx, &blob, &blob);
625 if (!NT_STATUS_IS_OK(status)) {
629 /* unmarshall the NDR */
630 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
631 if (!NT_STATUS_IS_OK(status)) {
635 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
636 pkt.u.alter_ack.num_results == 0 ||
637 pkt.u.alter_ack.ctx_list[0].result != 0) {
638 status = NT_STATUS_UNSUCCESSFUL;
641 /* the bind_ack might contain a reply set of credentials */
642 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
643 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
645 p->security_state.auth_info,
646 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
653 perform a continued bind (and auth3)
655 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
658 struct dcerpc_packet pkt;
662 init_dcerpc_hdr(p, &pkt);
664 pkt.ptype = DCERPC_PKT_AUTH3;
665 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
666 pkt.call_id = next_call_id(p);
669 pkt.u.auth.auth_info = data_blob(NULL, 0);
671 /* construct the NDR form of the packet */
672 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
673 if (!NT_STATUS_IS_OK(status)) {
677 /* send it on its way */
678 status = p->transport.send_request(p, &blob, False);
679 if (!NT_STATUS_IS_OK(status)) {
687 /* perform a dcerpc bind, using the uuid as the key */
688 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
690 const char *uuid, uint_t version)
692 struct dcerpc_syntax_id syntax;
693 struct dcerpc_syntax_id transfer_syntax;
696 status = GUID_from_string(uuid, &syntax.uuid);
697 if (!NT_STATUS_IS_OK(status)) {
698 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
701 syntax.if_version = version;
703 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
704 if (!NT_STATUS_IS_OK(status)) {
707 transfer_syntax.if_version = NDR_GUID_VERSION;
709 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
713 process a fragment received from the transport layer during a
716 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
720 struct dcerpc_packet pkt;
721 struct rpc_request *req;
724 if (!NT_STATUS_IS_OK(status)) {
725 /* all pending requests get the error */
728 req->state = RPC_REQUEST_DONE;
729 req->status = status;
730 DLIST_REMOVE(p->pending, req);
731 if (req->async.callback) {
732 req->async.callback(req);
740 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
742 /* find the matching request. Notice we match before we check
743 the status. this is ok as a pending call_id can never be
745 for (req=p->pending;req;req=req->next) {
746 if (pkt.call_id == req->call_id) break;
750 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
754 if (!NT_STATUS_IS_OK(status)) {
755 req->status = status;
756 req->state = RPC_REQUEST_DONE;
757 DLIST_REMOVE(p->pending, req);
758 if (req->async.callback) {
759 req->async.callback(req);
764 if (pkt.ptype == DCERPC_PKT_FAULT) {
765 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
766 req->fault_code = pkt.u.fault.status;
767 req->status = NT_STATUS_NET_WRITE_FAULT;
768 req->state = RPC_REQUEST_DONE;
769 DLIST_REMOVE(p->pending, req);
770 if (req->async.callback) {
771 req->async.callback(req);
776 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
777 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
779 req->fault_code = DCERPC_FAULT_OTHER;
780 req->status = NT_STATUS_NET_WRITE_FAULT;
781 req->state = RPC_REQUEST_DONE;
782 DLIST_REMOVE(p->pending, req);
783 if (req->async.callback) {
784 req->async.callback(req);
789 length = pkt.u.response.stub_and_verifier.length;
792 req->payload.data = talloc_realloc(req,
794 req->payload.length + length);
795 if (!req->payload.data) {
796 req->status = NT_STATUS_NO_MEMORY;
797 req->state = RPC_REQUEST_DONE;
798 DLIST_REMOVE(p->pending, req);
799 if (req->async.callback) {
800 req->async.callback(req);
804 memcpy(req->payload.data+req->payload.length,
805 pkt.u.response.stub_and_verifier.data, length);
806 req->payload.length += length;
809 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
810 p->transport.send_read(p);
814 /* we've got the full payload */
815 req->state = RPC_REQUEST_DONE;
816 DLIST_REMOVE(p->pending, req);
818 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
819 req->flags |= DCERPC_PULL_BIGENDIAN;
821 req->flags &= ~DCERPC_PULL_BIGENDIAN;
824 if (req->async.callback) {
825 req->async.callback(req);
831 make sure requests are cleaned up
833 static int dcerpc_req_destructor(void *ptr)
835 struct rpc_request *req = ptr;
836 DLIST_REMOVE(req->p->pending, req);
841 perform the send size of a async dcerpc request
843 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
847 DATA_BLOB *stub_data)
849 struct rpc_request *req;
850 struct dcerpc_packet pkt;
852 uint32_t remaining, chunk_size;
853 BOOL first_packet = True;
855 p->transport.recv_data = dcerpc_request_recv_data;
857 req = talloc_p(mem_ctx, struct rpc_request);
863 req->call_id = next_call_id(p);
864 req->status = NT_STATUS_OK;
865 req->state = RPC_REQUEST_PENDING;
866 req->payload = data_blob(NULL, 0);
869 req->async.callback = NULL;
871 init_dcerpc_hdr(p, &pkt);
873 remaining = stub_data->length;
875 /* we can write a full max_recv_frag size, minus the dcerpc
876 request header size */
877 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
879 pkt.ptype = DCERPC_PKT_REQUEST;
880 pkt.call_id = req->call_id;
882 pkt.u.request.alloc_hint = remaining;
883 pkt.u.request.context_id = 0;
884 pkt.u.request.opnum = opnum;
886 pkt.object.object = *object;
887 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
888 /* FIXME: pfc_cflags is reset below! */
891 DLIST_ADD(p->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;
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, &blob, mem_ctx, &pkt);
914 if (!NT_STATUS_IS_OK(req->status)) {
915 req->state = RPC_REQUEST_DONE;
916 DLIST_REMOVE(p->pending, req);
920 req->status = p->transport.send_request(p, &blob, last_frag);
921 if (!NT_STATUS_IS_OK(req->status)) {
922 req->state = RPC_REQUEST_DONE;
923 DLIST_REMOVE(p->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->transport.event_context(p);
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,
977 struct OBJREF *object,
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_pipe *p,
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(mem_ctx, struct_size);
1015 return NT_STATUS_NO_MEMORY;
1018 pull = ndr_pull_init_flags(p, &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_pipe *p,
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(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(p, &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 with a given set of ndr helper functions
1141 call dcerpc_ndr_request_recv() to receive the answer
1143 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1144 struct OBJREF *object,
1146 TALLOC_CTX *mem_ctx,
1147 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1148 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1152 struct ndr_push *push;
1155 struct rpc_request *req;
1157 /* setup for a ndr_push_* call */
1158 push = ndr_push_init();
1163 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1164 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1167 /* push the structure into a blob */
1168 status = ndr_push(push, NDR_IN, struct_ptr);
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->flags & DCERPC_DEBUG_VALIDATE_IN) {
1180 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size,
1181 ndr_push, 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.ndr_push = ndr_push;
1198 req->ndr.ndr_pull = ndr_pull;
1199 req->ndr.struct_ptr = struct_ptr;
1200 req->ndr.struct_size = struct_size;
1201 req->ndr.mem_ctx = mem_ctx;
1204 ndr_push_free(push);
1210 receive the answer from a dcerpc_ndr_request_send()
1212 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1214 struct dcerpc_pipe *p = req->p;
1217 struct ndr_pull *pull;
1218 struct rpc_request_ndr ndr = req->ndr;
1221 /* make sure the recv code doesn't free the request, as we
1222 need to grab the flags element before it is freed */
1223 talloc_increase_ref_count(req);
1225 status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1226 if (!NT_STATUS_IS_OK(status)) {
1233 /* prepare for ndr_pull_* */
1234 pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1236 return NT_STATUS_NO_MEMORY;
1239 if (flags & DCERPC_PULL_BIGENDIAN) {
1240 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1243 DEBUG(10,("rpc reply data:\n"));
1244 dump_data(10, pull->data, pull->data_size);
1246 /* pull the structure from the blob */
1247 status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1248 if (!NT_STATUS_IS_OK(status)) {
1252 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1253 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
1254 ndr.ndr_push, ndr.ndr_pull);
1255 if (!NT_STATUS_IS_OK(status)) {
1260 if (pull->offset != pull->data_size) {
1261 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1262 pull->data_size - pull->offset));
1263 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1264 but it turns out that early versions of NT
1265 (specifically NT3.1) add junk onto the end of rpc
1266 packets, so if we want to interoperate at all with
1267 those versions then we need to ignore this error */
1270 return NT_STATUS_OK;
1275 a useful helper function for synchronous rpc requests
1277 this can be used when you have ndr push/pull functions in the
1280 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1281 struct OBJREF *object,
1283 TALLOC_CTX *mem_ctx,
1284 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1285 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1289 struct rpc_request *req;
1291 req = dcerpc_ndr_request_send(p, object, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1293 return NT_STATUS_NO_MEMORY;
1296 return dcerpc_ndr_request_recv(req);
1301 a useful function for retrieving the server name we connected to
1303 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1305 if (!p->transport.peer_name) {
1308 return p->transport.peer_name(p);
1312 a useful function to get the auth_level
1315 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1319 if (p->flags & DCERPC_SEAL) {
1320 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1321 } else if (p->flags & DCERPC_SIGN) {
1322 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1323 } else if (p->flags & DCERPC_CONNECT) {
1324 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1326 auth_level = DCERPC_AUTH_LEVEL_NONE;