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 "librpc/gen_ndr/ndr_epmapper.h"
26 /* initialise a dcerpc pipe. */
27 struct dcerpc_pipe *dcerpc_pipe_init(void)
29 struct dcerpc_pipe *p;
31 p = talloc_p(NULL, struct dcerpc_pipe);
36 p->reference_count = 0;
38 p->security_state.auth_info = NULL;
39 p->security_state.session_key = dcerpc_generic_session_key;
40 p->security_state.generic_state = NULL;
41 p->binding_string = NULL;
43 p->srv_max_xmit_frag = 0;
44 p->srv_max_recv_frag = 0;
45 p->last_fault_code = 0;
52 choose the next call id to use
54 static uint32_t next_call_id(struct dcerpc_pipe *p)
57 if (p->call_id == 0) {
63 /* close down a dcerpc over SMB pipe */
64 void dcerpc_pipe_close(struct dcerpc_pipe *p)
68 if (p->reference_count <= 0) {
69 if (p->security_state.generic_state) {
70 gensec_end(&p->security_state.generic_state);
72 p->transport.shutdown_pipe(p);
77 /* we need to be able to get/set the fragment length without doing a full
79 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
81 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
82 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
84 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
88 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
90 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
91 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
93 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
97 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
99 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
100 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
102 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
108 setup for a ndr pull, also setting up any flags from the binding string
110 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
112 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
114 if (ndr == NULL) return ndr;
116 if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
117 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
120 if (p->flags & DCERPC_NDR_REF_ALLOC) {
121 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
128 parse a data blob into a dcerpc_packet structure. This handles both
129 input and output packets
131 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
132 struct dcerpc_packet *pkt)
134 struct ndr_pull *ndr;
136 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
138 return NT_STATUS_NO_MEMORY;
141 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
142 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
145 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
149 generate a CONNECT level verifier
151 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
153 *blob = data_blob_talloc(mem_ctx, NULL, 16);
154 if (blob->data == NULL) {
155 return NT_STATUS_NO_MEMORY;
157 SIVAL(blob->data, 0, 1);
158 memset(blob->data+4, 0, 12);
163 generate a CONNECT level verifier
165 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
167 if (blob->length != 16 ||
168 IVAL(blob->data, 0) != 1) {
169 return NT_STATUS_ACCESS_DENIED;
175 parse a possibly signed blob into a dcerpc request packet structure
177 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
178 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
179 struct dcerpc_packet *pkt)
181 struct ndr_pull *ndr;
183 struct dcerpc_auth auth;
186 /* non-signed packets are simpler */
187 if (!p->security_state.auth_info ||
188 !p->security_state.generic_state) {
189 return dcerpc_pull(p, blob, mem_ctx, pkt);
192 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
194 return NT_STATUS_NO_MEMORY;
197 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
198 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
201 /* pull the basic packet */
202 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
203 if (!NT_STATUS_IS_OK(status)) {
207 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
211 if (pkt->auth_length == 0 &&
212 p->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
216 auth_blob.length = 8 + pkt->auth_length;
218 /* check for a valid length */
219 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
220 return NT_STATUS_INFO_LENGTH_MISMATCH;
224 pkt->u.response.stub_and_verifier.data +
225 pkt->u.response.stub_and_verifier.length - auth_blob.length;
226 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
228 /* pull the auth structure */
229 ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
231 return NT_STATUS_NO_MEMORY;
234 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
235 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
238 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
239 if (!NT_STATUS_IS_OK(status)) {
244 /* check signature or unseal the packet */
245 switch (p->security_state.auth_info->auth_level) {
246 case DCERPC_AUTH_LEVEL_PRIVACY:
247 status = gensec_unseal_packet(p->security_state.generic_state,
249 blob->data + DCERPC_REQUEST_LENGTH,
250 pkt->u.response.stub_and_verifier.length,
252 blob->length - auth.credentials.length,
254 memcpy(pkt->u.response.stub_and_verifier.data,
255 blob->data + DCERPC_REQUEST_LENGTH,
256 pkt->u.response.stub_and_verifier.length);
259 case DCERPC_AUTH_LEVEL_INTEGRITY:
260 status = gensec_check_packet(p->security_state.generic_state,
262 pkt->u.response.stub_and_verifier.data,
263 pkt->u.response.stub_and_verifier.length,
265 blob->length - auth.credentials.length,
269 case DCERPC_AUTH_LEVEL_CONNECT:
270 status = dcerpc_check_connect_verifier(&auth.credentials);
273 case DCERPC_AUTH_LEVEL_NONE:
277 status = NT_STATUS_INVALID_LEVEL;
281 /* remove the indicated amount of paddiing */
282 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
283 return NT_STATUS_INFO_LENGTH_MISMATCH;
285 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
292 push a dcerpc request packet into a blob, possibly signing it.
294 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
295 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
296 struct dcerpc_packet *pkt)
299 struct ndr_push *ndr;
302 /* non-signed packets are simpler */
303 if (!p->security_state.auth_info ||
304 !p->security_state.generic_state) {
305 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
308 ndr = ndr_push_init_ctx(mem_ctx);
310 return NT_STATUS_NO_MEMORY;
313 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
314 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
317 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
318 if (!NT_STATUS_IS_OK(status)) {
322 /* pad to 16 byte multiple in the payload portion of the
323 packet. This matches what w2k3 does */
324 p->security_state.auth_info->auth_pad_length =
325 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
326 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
328 /* sign or seal the packet */
329 switch (p->security_state.auth_info->auth_level) {
330 case DCERPC_AUTH_LEVEL_PRIVACY:
331 case DCERPC_AUTH_LEVEL_INTEGRITY:
332 p->security_state.auth_info->credentials
333 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
334 data_blob_clear(&p->security_state.auth_info->credentials);
337 case DCERPC_AUTH_LEVEL_CONNECT:
338 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
341 case DCERPC_AUTH_LEVEL_NONE:
342 p->security_state.auth_info->credentials = data_blob(NULL, 0);
346 status = NT_STATUS_INVALID_LEVEL;
350 if (!NT_STATUS_IS_OK(status)) {
354 /* add the auth verifier */
355 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
356 if (!NT_STATUS_IS_OK(status)) {
360 /* extract the whole packet as a blob */
361 *blob = ndr_push_blob(ndr);
363 /* fill in the fragment length and auth_length, we can't fill
364 in these earlier as we don't know the signature length (it
365 could be variable length) */
366 dcerpc_set_frag_length(blob, blob->length);
367 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
369 /* sign or seal the packet */
370 switch (p->security_state.auth_info->auth_level) {
371 case DCERPC_AUTH_LEVEL_PRIVACY:
372 status = gensec_seal_packet(p->security_state.generic_state,
374 blob->data + DCERPC_REQUEST_LENGTH,
375 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
378 p->security_state.auth_info->credentials.length,
380 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
383 case DCERPC_AUTH_LEVEL_INTEGRITY:
384 status = gensec_sign_packet(p->security_state.generic_state,
386 blob->data + DCERPC_REQUEST_LENGTH,
387 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
390 p->security_state.auth_info->credentials.length,
392 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
395 case DCERPC_AUTH_LEVEL_CONNECT:
398 case DCERPC_AUTH_LEVEL_NONE:
399 p->security_state.auth_info->credentials = data_blob(NULL, 0);
403 status = NT_STATUS_INVALID_LEVEL;
407 data_blob_free(&p->security_state.auth_info->credentials);
414 fill in the fixed values in a dcerpc header
416 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
419 pkt->rpc_vers_minor = 0;
420 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
423 pkt->drep[0] = DCERPC_DREP_LE;
431 hold the state of pending full requests
433 struct full_request_state {
434 DATA_BLOB *reply_blob;
439 receive a reply to a full request
441 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
444 struct full_request_state *state = p->full_request_private;
446 if (!NT_STATUS_IS_OK(status)) {
447 state->status = status;
450 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
451 state->reply_blob = NULL;
455 perform a single pdu synchronous request - used for the bind code
456 this cannot be mixed with normal async requests
458 static NTSTATUS full_request(struct dcerpc_pipe *p,
460 DATA_BLOB *request_blob,
461 DATA_BLOB *reply_blob)
463 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
467 return NT_STATUS_NO_MEMORY;
470 state->reply_blob = reply_blob;
471 state->status = NT_STATUS_OK;
473 p->transport.recv_data = full_request_recv;
474 p->full_request_private = state;
476 status = p->transport.send_request(p, request_blob, True);
477 if (!NT_STATUS_IS_OK(status)) {
481 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
482 struct event_context *ctx = p->transport.event_context(p);
483 if (event_loop_once(ctx) != 0) {
484 return NT_STATUS_CONNECTION_DISCONNECTED;
488 return state->status;
493 perform a bind using the given syntax
495 the auth_info structure is updated with the reply authentication info
498 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
500 const struct dcerpc_syntax_id *syntax,
501 const struct dcerpc_syntax_id *transfer_syntax)
503 struct dcerpc_packet pkt;
508 p->transfer_syntax = *transfer_syntax;
510 init_dcerpc_hdr(p, &pkt);
512 pkt.ptype = DCERPC_PKT_BIND;
513 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
514 pkt.call_id = p->call_id;
517 pkt.u.bind.max_xmit_frag = 5840;
518 pkt.u.bind.max_recv_frag = 5840;
519 pkt.u.bind.assoc_group_id = 0;
520 pkt.u.bind.num_contexts = 1;
521 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
522 if (!pkt.u.bind.ctx_list) {
523 return NT_STATUS_NO_MEMORY;
525 pkt.u.bind.ctx_list[0].context_id = 0;
526 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
527 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
528 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
529 pkt.u.bind.auth_info = data_blob(NULL, 0);
531 /* construct the NDR form of the packet */
532 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
533 if (!NT_STATUS_IS_OK(status)) {
537 /* send it on its way */
538 status = full_request(p, mem_ctx, &blob, &blob);
539 if (!NT_STATUS_IS_OK(status)) {
543 /* unmarshall the NDR */
544 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
545 if (!NT_STATUS_IS_OK(status)) {
549 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
550 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
551 return NT_STATUS_ACCESS_DENIED;
554 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
555 pkt.u.bind_ack.num_results == 0 ||
556 pkt.u.bind_ack.ctx_list[0].result != 0) {
557 return NT_STATUS_UNSUCCESSFUL;
560 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
561 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
562 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
565 /* the bind_ack might contain a reply set of credentials */
566 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
567 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
569 p->security_state.auth_info,
570 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
577 perform a alter context using the given syntax
579 the auth_info structure is updated with the reply authentication info
582 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
585 struct dcerpc_packet pkt;
589 init_dcerpc_hdr(p, &pkt);
591 pkt.ptype = DCERPC_PKT_ALTER;
592 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
593 pkt.call_id = p->call_id;
596 pkt.u.alter.max_xmit_frag = 0x2000;
597 pkt.u.alter.max_recv_frag = 0x2000;
598 pkt.u.alter.assoc_group_id = 0;
599 pkt.u.alter.num_contexts = 1;
600 pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
601 if (!pkt.u.alter.ctx_list) {
602 return NT_STATUS_NO_MEMORY;
604 pkt.u.alter.ctx_list[0].context_id = 0;
605 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
606 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
607 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
608 pkt.u.alter.auth_info = data_blob(NULL, 0);
610 /* construct the NDR form of the packet */
611 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
612 if (!NT_STATUS_IS_OK(status)) {
616 /* send it on its way */
617 status = full_request(p, mem_ctx, &blob, &blob);
618 if (!NT_STATUS_IS_OK(status)) {
622 /* unmarshall the NDR */
623 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
624 if (!NT_STATUS_IS_OK(status)) {
628 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
629 pkt.u.alter_ack.num_results == 0 ||
630 pkt.u.alter_ack.ctx_list[0].result != 0) {
631 status = NT_STATUS_UNSUCCESSFUL;
634 /* the bind_ack might contain a reply set of credentials */
635 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
636 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
638 p->security_state.auth_info,
639 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
646 perform a continued bind (and auth3)
648 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
651 struct dcerpc_packet pkt;
655 init_dcerpc_hdr(p, &pkt);
657 pkt.ptype = DCERPC_PKT_AUTH3;
658 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
659 pkt.call_id = next_call_id(p);
662 pkt.u.auth.auth_info = data_blob(NULL, 0);
664 /* construct the NDR form of the packet */
665 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
666 if (!NT_STATUS_IS_OK(status)) {
670 /* send it on its way */
671 status = p->transport.send_request(p, &blob, False);
672 if (!NT_STATUS_IS_OK(status)) {
680 /* perform a dcerpc bind, using the uuid as the key */
681 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
683 const char *uuid, uint_t version)
685 struct dcerpc_syntax_id syntax;
686 struct dcerpc_syntax_id transfer_syntax;
689 status = GUID_from_string(uuid, &syntax.uuid);
690 if (!NT_STATUS_IS_OK(status)) {
691 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
694 syntax.if_version = version;
696 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
697 if (!NT_STATUS_IS_OK(status)) {
700 transfer_syntax.if_version = NDR_GUID_VERSION;
702 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
706 process a fragment received from the transport layer during a
709 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
713 struct dcerpc_packet pkt;
714 struct rpc_request *req;
717 if (!NT_STATUS_IS_OK(status)) {
718 /* all pending requests get the error */
721 req->state = RPC_REQUEST_DONE;
722 req->status = status;
723 DLIST_REMOVE(p->pending, req);
724 if (req->async.callback) {
725 req->async.callback(req);
733 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
735 /* find the matching request. Notice we match before we check
736 the status. this is ok as a pending call_id can never be
738 for (req=p->pending;req;req=req->next) {
739 if (pkt.call_id == req->call_id) break;
743 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
747 if (!NT_STATUS_IS_OK(status)) {
748 req->status = status;
749 req->state = RPC_REQUEST_DONE;
750 DLIST_REMOVE(p->pending, req);
751 if (req->async.callback) {
752 req->async.callback(req);
757 if (pkt.ptype == DCERPC_PKT_FAULT) {
758 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
759 req->fault_code = pkt.u.fault.status;
760 req->status = NT_STATUS_NET_WRITE_FAULT;
761 req->state = RPC_REQUEST_DONE;
762 DLIST_REMOVE(p->pending, req);
763 if (req->async.callback) {
764 req->async.callback(req);
769 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
770 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
772 req->fault_code = DCERPC_FAULT_OTHER;
773 req->status = NT_STATUS_NET_WRITE_FAULT;
774 req->state = RPC_REQUEST_DONE;
775 DLIST_REMOVE(p->pending, req);
776 if (req->async.callback) {
777 req->async.callback(req);
782 length = pkt.u.response.stub_and_verifier.length;
785 req->payload.data = talloc_realloc(req,
787 req->payload.length + length);
788 if (!req->payload.data) {
789 req->status = NT_STATUS_NO_MEMORY;
790 req->state = RPC_REQUEST_DONE;
791 DLIST_REMOVE(p->pending, req);
792 if (req->async.callback) {
793 req->async.callback(req);
797 memcpy(req->payload.data+req->payload.length,
798 pkt.u.response.stub_and_verifier.data, length);
799 req->payload.length += length;
802 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
803 p->transport.send_read(p);
807 /* we've got the full payload */
808 req->state = RPC_REQUEST_DONE;
809 DLIST_REMOVE(p->pending, req);
811 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
812 req->flags |= DCERPC_PULL_BIGENDIAN;
814 req->flags &= ~DCERPC_PULL_BIGENDIAN;
817 if (req->async.callback) {
818 req->async.callback(req);
824 make sure requests are cleaned up
826 static int dcerpc_req_destructor(void *ptr)
828 struct rpc_request *req = ptr;
829 DLIST_REMOVE(req->p->pending, req);
834 perform the send size of a async dcerpc request
836 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
839 DATA_BLOB *stub_data)
841 struct rpc_request *req;
842 struct dcerpc_packet pkt;
844 uint32_t remaining, chunk_size;
845 BOOL first_packet = True;
847 p->transport.recv_data = dcerpc_request_recv_data;
849 req = talloc_p(mem_ctx, struct rpc_request);
855 req->call_id = next_call_id(p);
856 req->status = NT_STATUS_OK;
857 req->state = RPC_REQUEST_PENDING;
858 req->payload = data_blob(NULL, 0);
861 req->async.callback = NULL;
863 init_dcerpc_hdr(p, &pkt);
865 remaining = stub_data->length;
867 /* we can write a full max_recv_frag size, minus the dcerpc
868 request header size */
869 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
871 pkt.ptype = DCERPC_PKT_REQUEST;
872 pkt.call_id = req->call_id;
874 pkt.u.request.alloc_hint = remaining;
875 pkt.u.request.context_id = 0;
876 pkt.u.request.opnum = opnum;
878 DLIST_ADD(p->pending, req);
880 /* we send a series of pdus without waiting for a reply */
881 while (remaining > 0 || first_packet) {
882 uint32_t chunk = MIN(chunk_size, remaining);
883 BOOL last_frag = False;
885 first_packet = False;
888 if (remaining == stub_data->length) {
889 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
891 if (chunk == remaining) {
892 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
896 pkt.u.request.stub_and_verifier.data = stub_data->data +
897 (stub_data->length - remaining);
898 pkt.u.request.stub_and_verifier.length = chunk;
900 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
901 if (!NT_STATUS_IS_OK(req->status)) {
902 req->state = RPC_REQUEST_DONE;
903 DLIST_REMOVE(p->pending, req);
907 req->status = p->transport.send_request(p, &blob, last_frag);
908 if (!NT_STATUS_IS_OK(req->status)) {
909 req->state = RPC_REQUEST_DONE;
910 DLIST_REMOVE(p->pending, req);
917 talloc_set_destructor(req, dcerpc_req_destructor);
923 return the event context for a dcerpc pipe
924 used by callers who wish to operate asynchronously
926 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
928 return p->transport.event_context(p);
934 perform the receive side of a async dcerpc request
936 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
938 DATA_BLOB *stub_data)
942 while (req->state == RPC_REQUEST_PENDING) {
943 struct event_context *ctx = dcerpc_event_context(req->p);
944 if (event_loop_once(ctx) != 0) {
945 return NT_STATUS_CONNECTION_DISCONNECTED;
948 *stub_data = req->payload;
949 status = req->status;
950 if (stub_data->data) {
951 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
953 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
954 req->p->last_fault_code = req->fault_code;
961 perform a full request/response pair on a dcerpc pipe
963 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
966 DATA_BLOB *stub_data_in,
967 DATA_BLOB *stub_data_out)
969 struct rpc_request *req;
971 req = dcerpc_request_send(p, opnum, mem_ctx, stub_data_in);
973 return NT_STATUS_NO_MEMORY;
976 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
981 this is a paranoid NDR validator. For every packet we push onto the wire
982 we pull it back again, then push it again. Then we compare the raw NDR data
983 for that to the NDR we initially generated. If they don't match then we know
984 we must have a bug in either the pull or push side of our code
986 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
990 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
991 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
994 struct ndr_pull *pull;
995 struct ndr_push *push;
999 st = talloc(mem_ctx, struct_size);
1001 return NT_STATUS_NO_MEMORY;
1004 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1006 return NT_STATUS_NO_MEMORY;
1009 status = ndr_pull(pull, NDR_IN, st);
1010 if (!NT_STATUS_IS_OK(status)) {
1011 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1012 "failed input validation pull - %s",
1016 push = ndr_push_init_ctx(mem_ctx);
1018 return NT_STATUS_NO_MEMORY;
1021 status = ndr_push(push, NDR_IN, st);
1022 if (!NT_STATUS_IS_OK(status)) {
1023 return ndr_push_error(push, NDR_ERR_VALIDATE,
1024 "failed input validation push - %s",
1028 blob2 = ndr_push_blob(push);
1030 if (!data_blob_equal(&blob, &blob2)) {
1031 DEBUG(3,("original:\n"));
1032 dump_data(3, blob.data, blob.length);
1033 DEBUG(3,("secondary:\n"));
1034 dump_data(3, blob2.data, blob2.length);
1035 return ndr_push_error(push, NDR_ERR_VALIDATE,
1036 "failed input validation data - %s",
1040 return NT_STATUS_OK;
1044 this is a paranoid NDR input validator. For every packet we pull
1045 from the wire we push it back again then pull and push it
1046 again. Then we compare the raw NDR data for that to the NDR we
1047 initially generated. If they don't match then we know we must have a
1048 bug in either the pull or push side of our code
1050 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1051 TALLOC_CTX *mem_ctx,
1054 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1055 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1058 struct ndr_pull *pull;
1059 struct ndr_push *push;
1061 DATA_BLOB blob, blob2;
1063 st = talloc(mem_ctx, struct_size);
1065 return NT_STATUS_NO_MEMORY;
1067 memcpy(st, struct_ptr, struct_size);
1069 push = ndr_push_init_ctx(mem_ctx);
1071 return NT_STATUS_NO_MEMORY;
1074 status = ndr_push(push, NDR_OUT, struct_ptr);
1075 if (!NT_STATUS_IS_OK(status)) {
1076 return ndr_push_error(push, NDR_ERR_VALIDATE,
1077 "failed output validation push - %s",
1081 blob = ndr_push_blob(push);
1083 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1085 return NT_STATUS_NO_MEMORY;
1088 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1089 status = ndr_pull(pull, NDR_OUT, st);
1090 if (!NT_STATUS_IS_OK(status)) {
1091 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1092 "failed output validation pull - %s",
1096 push = ndr_push_init_ctx(mem_ctx);
1098 return NT_STATUS_NO_MEMORY;
1101 status = ndr_push(push, NDR_OUT, st);
1102 if (!NT_STATUS_IS_OK(status)) {
1103 return ndr_push_error(push, NDR_ERR_VALIDATE,
1104 "failed output validation push2 - %s",
1108 blob2 = ndr_push_blob(push);
1110 if (!data_blob_equal(&blob, &blob2)) {
1111 DEBUG(3,("original:\n"));
1112 dump_data(3, blob.data, blob.length);
1113 DEBUG(3,("secondary:\n"));
1114 dump_data(3, blob2.data, blob2.length);
1115 return ndr_push_error(push, NDR_ERR_VALIDATE,
1116 "failed output validation data - %s",
1120 return NT_STATUS_OK;
1125 send a rpc request with a given set of ndr helper functions
1127 call dcerpc_ndr_request_recv() to receive the answer
1129 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1131 TALLOC_CTX *mem_ctx,
1132 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1133 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1137 struct ndr_push *push;
1140 struct rpc_request *req;
1142 /* setup for a ndr_push_* call */
1143 push = ndr_push_init();
1148 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1149 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1152 /* push the structure into a blob */
1153 status = ndr_push(push, NDR_IN, struct_ptr);
1154 if (!NT_STATUS_IS_OK(status)) {
1155 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1156 nt_errstr(status)));
1157 ndr_push_free(push);
1161 /* retrieve the blob */
1162 request = ndr_push_blob(push);
1164 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1165 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size,
1166 ndr_push, ndr_pull);
1167 if (!NT_STATUS_IS_OK(status)) {
1168 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1169 nt_errstr(status)));
1170 ndr_push_free(push);
1175 DEBUG(10,("rpc request data:\n"));
1176 dump_data(10, request.data, request.length);
1178 /* make the actual dcerpc request */
1179 req = dcerpc_request_send(p, opnum, mem_ctx, &request);
1182 req->ndr.ndr_push = ndr_push;
1183 req->ndr.ndr_pull = ndr_pull;
1184 req->ndr.struct_ptr = struct_ptr;
1185 req->ndr.struct_size = struct_size;
1186 req->ndr.mem_ctx = mem_ctx;
1189 ndr_push_free(push);
1195 receive the answer from a dcerpc_ndr_request_send()
1197 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1199 struct dcerpc_pipe *p = req->p;
1202 struct ndr_pull *pull;
1203 struct rpc_request_ndr ndr = req->ndr;
1206 /* make sure the recv code doesn't free the request, as we
1207 need to grab the flags element before it is freed */
1208 talloc_increase_ref_count(req);
1210 status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1211 if (!NT_STATUS_IS_OK(status)) {
1218 /* prepare for ndr_pull_* */
1219 pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1221 return NT_STATUS_NO_MEMORY;
1224 if (flags & DCERPC_PULL_BIGENDIAN) {
1225 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1228 DEBUG(10,("rpc reply data:\n"));
1229 dump_data(10, pull->data, pull->data_size);
1231 /* pull the structure from the blob */
1232 status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1233 if (!NT_STATUS_IS_OK(status)) {
1237 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1238 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
1239 ndr.ndr_push, ndr.ndr_pull);
1240 if (!NT_STATUS_IS_OK(status)) {
1245 if (pull->offset != pull->data_size) {
1246 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1247 pull->data_size - pull->offset));
1248 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1249 but it turns out that early versions of NT
1250 (specifically NT3.1) add junk onto the end of rpc
1251 packets, so if we want to interoperate at all with
1252 those versions then we need to ignore this error */
1255 return NT_STATUS_OK;
1260 a useful helper function for synchronous rpc requests
1262 this can be used when you have ndr push/pull functions in the
1265 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1267 TALLOC_CTX *mem_ctx,
1268 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1269 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1273 struct rpc_request *req;
1275 req = dcerpc_ndr_request_send(p, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1277 return NT_STATUS_NO_MEMORY;
1280 return dcerpc_ndr_request_recv(req);
1285 a useful function for retrieving the server name we connected to
1287 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1289 if (!p->transport.peer_name) {
1292 return p->transport.peer_name(p);
1296 a useful function to get the auth_level
1299 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1303 if (p->flags & DCERPC_SEAL) {
1304 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1305 } else if (p->flags & DCERPC_SIGN) {
1306 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1307 } else if (p->flags & DCERPC_CONNECT) {
1308 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1310 auth_level = DCERPC_AUTH_LEVEL_NONE;