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.
25 /* initialise a dcerpc pipe. */
26 struct dcerpc_pipe *dcerpc_pipe_init(void)
28 struct dcerpc_pipe *p;
30 p = talloc_p(NULL, struct dcerpc_pipe);
35 p->reference_count = 0;
37 p->security_state.auth_info = NULL;
38 p->security_state.session_key = dcerpc_generic_session_key;
39 p->security_state.generic_state = NULL;
40 p->binding_string = NULL;
42 p->srv_max_xmit_frag = 0;
43 p->srv_max_recv_frag = 0;
44 p->last_fault_code = 0;
51 choose the next call id to use
53 static uint32_t next_call_id(struct dcerpc_pipe *p)
56 if (p->call_id == 0) {
62 /* close down a dcerpc over SMB pipe */
63 void dcerpc_pipe_close(struct dcerpc_pipe *p)
67 if (p->reference_count <= 0) {
68 if (p->security_state.generic_state) {
69 gensec_end(&p->security_state.generic_state);
71 p->transport.shutdown_pipe(p);
76 /* we need to be able to get/set the fragment length without doing a full
78 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
80 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
81 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
83 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
87 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
89 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
90 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
92 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
96 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
98 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
99 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
101 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
107 setup for a ndr pull, also setting up any flags from the binding string
109 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
111 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
113 if (ndr == NULL) return ndr;
115 if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
116 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
119 if (p->flags & DCERPC_NDR_REF_ALLOC) {
120 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
127 parse a data blob into a dcerpc_packet structure. This handles both
128 input and output packets
130 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
131 struct dcerpc_packet *pkt)
133 struct ndr_pull *ndr;
135 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
137 return NT_STATUS_NO_MEMORY;
140 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
141 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
144 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
148 generate a CONNECT level verifier
150 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
152 *blob = data_blob_talloc(mem_ctx, NULL, 16);
153 if (blob->data == NULL) {
154 return NT_STATUS_NO_MEMORY;
156 SIVAL(blob->data, 0, 1);
157 memset(blob->data+4, 0, 12);
162 generate a CONNECT level verifier
164 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
166 if (blob->length != 16 ||
167 IVAL(blob->data, 0) != 1) {
168 return NT_STATUS_ACCESS_DENIED;
174 parse a possibly signed blob into a dcerpc request packet structure
176 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
177 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
178 struct dcerpc_packet *pkt)
180 struct ndr_pull *ndr;
182 struct dcerpc_auth auth;
185 /* non-signed packets are simpler */
186 if (!p->security_state.auth_info ||
187 !p->security_state.generic_state) {
188 return dcerpc_pull(p, blob, mem_ctx, pkt);
191 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
193 return NT_STATUS_NO_MEMORY;
196 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
197 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
200 /* pull the basic packet */
201 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
202 if (!NT_STATUS_IS_OK(status)) {
206 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
210 if (pkt->auth_length == 0 &&
211 p->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
215 auth_blob.length = 8 + pkt->auth_length;
217 /* check for a valid length */
218 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
219 return NT_STATUS_INFO_LENGTH_MISMATCH;
223 pkt->u.response.stub_and_verifier.data +
224 pkt->u.response.stub_and_verifier.length - auth_blob.length;
225 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
227 /* pull the auth structure */
228 ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
230 return NT_STATUS_NO_MEMORY;
233 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
234 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
237 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
238 if (!NT_STATUS_IS_OK(status)) {
243 /* check signature or unseal the packet */
244 switch (p->security_state.auth_info->auth_level) {
245 case DCERPC_AUTH_LEVEL_PRIVACY:
246 status = gensec_unseal_packet(p->security_state.generic_state,
248 blob->data + DCERPC_REQUEST_LENGTH,
249 pkt->u.response.stub_and_verifier.length,
251 blob->length - auth.credentials.length,
253 memcpy(pkt->u.response.stub_and_verifier.data,
254 blob->data + DCERPC_REQUEST_LENGTH,
255 pkt->u.response.stub_and_verifier.length);
258 case DCERPC_AUTH_LEVEL_INTEGRITY:
259 status = gensec_check_packet(p->security_state.generic_state,
261 pkt->u.response.stub_and_verifier.data,
262 pkt->u.response.stub_and_verifier.length,
264 blob->length - auth.credentials.length,
268 case DCERPC_AUTH_LEVEL_CONNECT:
269 status = dcerpc_check_connect_verifier(&auth.credentials);
272 case DCERPC_AUTH_LEVEL_NONE:
276 status = NT_STATUS_INVALID_LEVEL;
280 /* remove the indicated amount of paddiing */
281 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
282 return NT_STATUS_INFO_LENGTH_MISMATCH;
284 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
291 push a dcerpc request packet into a blob, possibly signing it.
293 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
294 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
295 struct dcerpc_packet *pkt)
298 struct ndr_push *ndr;
301 /* non-signed packets are simpler */
302 if (!p->security_state.auth_info ||
303 !p->security_state.generic_state) {
304 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
307 ndr = ndr_push_init_ctx(mem_ctx);
309 return NT_STATUS_NO_MEMORY;
312 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
313 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
316 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
317 if (!NT_STATUS_IS_OK(status)) {
321 /* pad to 16 byte multiple in the payload portion of the
322 packet. This matches what w2k3 does */
323 p->security_state.auth_info->auth_pad_length =
324 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
325 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
327 /* sign or seal the packet */
328 switch (p->security_state.auth_info->auth_level) {
329 case DCERPC_AUTH_LEVEL_PRIVACY:
330 case DCERPC_AUTH_LEVEL_INTEGRITY:
331 p->security_state.auth_info->credentials
332 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
333 data_blob_clear(&p->security_state.auth_info->credentials);
336 case DCERPC_AUTH_LEVEL_CONNECT:
337 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
340 case DCERPC_AUTH_LEVEL_NONE:
341 p->security_state.auth_info->credentials = data_blob(NULL, 0);
345 status = NT_STATUS_INVALID_LEVEL;
349 if (!NT_STATUS_IS_OK(status)) {
353 /* add the auth verifier */
354 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
355 if (!NT_STATUS_IS_OK(status)) {
359 /* extract the whole packet as a blob */
360 *blob = ndr_push_blob(ndr);
362 /* fill in the fragment length and auth_length, we can't fill
363 in these earlier as we don't know the signature length (it
364 could be variable length) */
365 dcerpc_set_frag_length(blob, blob->length);
366 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
368 /* sign or seal the packet */
369 switch (p->security_state.auth_info->auth_level) {
370 case DCERPC_AUTH_LEVEL_PRIVACY:
371 status = gensec_seal_packet(p->security_state.generic_state,
373 blob->data + DCERPC_REQUEST_LENGTH,
374 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
377 p->security_state.auth_info->credentials.length,
379 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
382 case DCERPC_AUTH_LEVEL_INTEGRITY:
383 status = gensec_sign_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_CONNECT:
397 case DCERPC_AUTH_LEVEL_NONE:
398 p->security_state.auth_info->credentials = data_blob(NULL, 0);
402 status = NT_STATUS_INVALID_LEVEL;
406 data_blob_free(&p->security_state.auth_info->credentials);
413 fill in the fixed values in a dcerpc header
415 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
418 pkt->rpc_vers_minor = 0;
419 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
422 pkt->drep[0] = DCERPC_DREP_LE;
430 hold the state of pending full requests
432 struct full_request_state {
433 DATA_BLOB *reply_blob;
438 receive a reply to a full request
440 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
443 struct full_request_state *state = p->full_request_private;
445 if (!NT_STATUS_IS_OK(status)) {
446 state->status = status;
449 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
450 state->reply_blob = NULL;
454 perform a single pdu synchronous request - used for the bind code
455 this cannot be mixed with normal async requests
457 static NTSTATUS full_request(struct dcerpc_pipe *p,
459 DATA_BLOB *request_blob,
460 DATA_BLOB *reply_blob)
462 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
466 return NT_STATUS_NO_MEMORY;
469 state->reply_blob = reply_blob;
470 state->status = NT_STATUS_OK;
472 p->transport.recv_data = full_request_recv;
473 p->full_request_private = state;
475 status = p->transport.send_request(p, request_blob, True);
476 if (!NT_STATUS_IS_OK(status)) {
480 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
481 struct event_context *ctx = p->transport.event_context(p);
482 if (event_loop_once(ctx) != 0) {
483 return NT_STATUS_CONNECTION_DISCONNECTED;
487 return state->status;
492 perform a bind using the given syntax
494 the auth_info structure is updated with the reply authentication info
497 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
499 const struct dcerpc_syntax_id *syntax,
500 const struct dcerpc_syntax_id *transfer_syntax)
502 struct dcerpc_packet pkt;
507 p->transfer_syntax = *transfer_syntax;
509 init_dcerpc_hdr(p, &pkt);
511 pkt.ptype = DCERPC_PKT_BIND;
512 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
513 pkt.call_id = p->call_id;
516 pkt.u.bind.max_xmit_frag = 5840;
517 pkt.u.bind.max_recv_frag = 5840;
518 pkt.u.bind.assoc_group_id = 0;
519 pkt.u.bind.num_contexts = 1;
520 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
521 if (!pkt.u.bind.ctx_list) {
522 return NT_STATUS_NO_MEMORY;
524 pkt.u.bind.ctx_list[0].context_id = 0;
525 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
526 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
527 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
528 pkt.u.bind.auth_info = data_blob(NULL, 0);
530 /* construct the NDR form of the packet */
531 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
532 if (!NT_STATUS_IS_OK(status)) {
536 /* send it on its way */
537 status = full_request(p, mem_ctx, &blob, &blob);
538 if (!NT_STATUS_IS_OK(status)) {
542 /* unmarshall the NDR */
543 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
544 if (!NT_STATUS_IS_OK(status)) {
548 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
549 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
550 return NT_STATUS_ACCESS_DENIED;
553 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
554 pkt.u.bind_ack.num_results == 0 ||
555 pkt.u.bind_ack.ctx_list[0].result != 0) {
556 return NT_STATUS_UNSUCCESSFUL;
559 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
560 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
561 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
564 /* the bind_ack might contain a reply set of credentials */
565 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
566 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
568 p->security_state.auth_info,
569 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
576 perform a alter context using the given syntax
578 the auth_info structure is updated with the reply authentication info
581 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
584 struct dcerpc_packet pkt;
588 init_dcerpc_hdr(p, &pkt);
590 pkt.ptype = DCERPC_PKT_ALTER;
591 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
592 pkt.call_id = p->call_id;
595 pkt.u.alter.max_xmit_frag = 0x2000;
596 pkt.u.alter.max_recv_frag = 0x2000;
597 pkt.u.alter.assoc_group_id = 0;
598 pkt.u.alter.num_contexts = 1;
599 pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
600 if (!pkt.u.alter.ctx_list) {
601 return NT_STATUS_NO_MEMORY;
603 pkt.u.alter.ctx_list[0].context_id = 0;
604 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
605 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
606 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
607 pkt.u.alter.auth_info = data_blob(NULL, 0);
609 /* construct the NDR form of the packet */
610 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
611 if (!NT_STATUS_IS_OK(status)) {
615 /* send it on its way */
616 status = full_request(p, mem_ctx, &blob, &blob);
617 if (!NT_STATUS_IS_OK(status)) {
621 /* unmarshall the NDR */
622 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
623 if (!NT_STATUS_IS_OK(status)) {
627 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
628 pkt.u.alter_ack.num_results == 0 ||
629 pkt.u.alter_ack.ctx_list[0].result != 0) {
630 status = NT_STATUS_UNSUCCESSFUL;
633 /* the bind_ack might contain a reply set of credentials */
634 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
635 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
637 p->security_state.auth_info,
638 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
645 perform a continued bind (and auth3)
647 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
650 struct dcerpc_packet pkt;
654 init_dcerpc_hdr(p, &pkt);
656 pkt.ptype = DCERPC_PKT_AUTH3;
657 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
658 pkt.call_id = next_call_id(p);
661 pkt.u.auth.auth_info = data_blob(NULL, 0);
663 /* construct the NDR form of the packet */
664 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
665 if (!NT_STATUS_IS_OK(status)) {
669 /* send it on its way */
670 status = p->transport.send_request(p, &blob, False);
671 if (!NT_STATUS_IS_OK(status)) {
679 /* perform a dcerpc bind, using the uuid as the key */
680 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
682 const char *uuid, uint_t version)
684 struct dcerpc_syntax_id syntax;
685 struct dcerpc_syntax_id transfer_syntax;
688 status = GUID_from_string(uuid, &syntax.uuid);
689 if (!NT_STATUS_IS_OK(status)) {
690 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
693 syntax.if_version = version;
695 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
696 if (!NT_STATUS_IS_OK(status)) {
699 transfer_syntax.if_version = NDR_GUID_VERSION;
701 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
705 process a fragment received from the transport layer during a
708 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
712 struct dcerpc_packet pkt;
713 struct rpc_request *req;
716 if (!NT_STATUS_IS_OK(status)) {
717 /* all pending requests get the error */
720 req->state = RPC_REQUEST_DONE;
721 req->status = status;
722 DLIST_REMOVE(p->pending, req);
723 if (req->async.callback) {
724 req->async.callback(req);
732 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
734 /* find the matching request. Notice we match before we check
735 the status. this is ok as a pending call_id can never be
737 for (req=p->pending;req;req=req->next) {
738 if (pkt.call_id == req->call_id) break;
742 DEBUG(2,("dcerpc_request: unmatched call_id in response packet\n"));
746 if (!NT_STATUS_IS_OK(status)) {
747 req->status = status;
748 req->state = RPC_REQUEST_DONE;
749 DLIST_REMOVE(p->pending, req);
750 if (req->async.callback) {
751 req->async.callback(req);
756 if (pkt.ptype == DCERPC_PKT_FAULT) {
757 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
758 req->fault_code = pkt.u.fault.status;
759 req->status = NT_STATUS_NET_WRITE_FAULT;
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_RESPONSE) {
769 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
771 req->fault_code = DCERPC_FAULT_OTHER;
772 req->status = NT_STATUS_NET_WRITE_FAULT;
773 req->state = RPC_REQUEST_DONE;
774 DLIST_REMOVE(p->pending, req);
775 if (req->async.callback) {
776 req->async.callback(req);
781 length = pkt.u.response.stub_and_verifier.length;
784 req->payload.data = talloc_realloc(req,
786 req->payload.length + length);
787 if (!req->payload.data) {
788 req->status = NT_STATUS_NO_MEMORY;
789 req->state = RPC_REQUEST_DONE;
790 DLIST_REMOVE(p->pending, req);
791 if (req->async.callback) {
792 req->async.callback(req);
796 memcpy(req->payload.data+req->payload.length,
797 pkt.u.response.stub_and_verifier.data, length);
798 req->payload.length += length;
801 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
802 p->transport.send_read(p);
806 /* we've got the full payload */
807 req->state = RPC_REQUEST_DONE;
808 DLIST_REMOVE(p->pending, req);
810 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
811 req->flags |= DCERPC_PULL_BIGENDIAN;
813 req->flags &= ~DCERPC_PULL_BIGENDIAN;
816 if (req->async.callback) {
817 req->async.callback(req);
823 perform the send size of a async dcerpc request
825 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
828 DATA_BLOB *stub_data)
830 struct rpc_request *req;
831 struct dcerpc_packet pkt;
833 uint32_t remaining, chunk_size;
834 BOOL first_packet = True;
836 p->transport.recv_data = dcerpc_request_recv_data;
838 req = talloc_p(mem_ctx, struct rpc_request);
844 req->call_id = next_call_id(p);
845 req->status = NT_STATUS_OK;
846 req->state = RPC_REQUEST_PENDING;
847 req->payload = data_blob(NULL, 0);
850 req->async.callback = NULL;
852 init_dcerpc_hdr(p, &pkt);
854 remaining = stub_data->length;
856 /* we can write a full max_recv_frag size, minus the dcerpc
857 request header size */
858 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
860 pkt.ptype = DCERPC_PKT_REQUEST;
861 pkt.call_id = req->call_id;
863 pkt.u.request.alloc_hint = remaining;
864 pkt.u.request.context_id = 0;
865 pkt.u.request.opnum = opnum;
867 DLIST_ADD(p->pending, req);
869 /* we send a series of pdus without waiting for a reply */
870 while (remaining > 0 || first_packet) {
871 uint32_t chunk = MIN(chunk_size, remaining);
872 BOOL last_frag = False;
874 first_packet = False;
877 if (remaining == stub_data->length) {
878 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
880 if (chunk == remaining) {
881 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
885 pkt.u.request.stub_and_verifier.data = stub_data->data +
886 (stub_data->length - remaining);
887 pkt.u.request.stub_and_verifier.length = chunk;
889 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
890 if (!NT_STATUS_IS_OK(req->status)) {
891 req->state = RPC_REQUEST_DONE;
892 DLIST_REMOVE(p->pending, req);
896 req->status = p->transport.send_request(p, &blob, last_frag);
897 if (!NT_STATUS_IS_OK(req->status)) {
898 req->state = RPC_REQUEST_DONE;
899 DLIST_REMOVE(p->pending, req);
910 return the event context for a dcerpc pipe
911 used by callers who wish to operate asynchronously
913 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
915 return p->transport.event_context(p);
921 perform the receive side of a async dcerpc request
923 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
925 DATA_BLOB *stub_data)
929 while (req->state == RPC_REQUEST_PENDING) {
930 struct event_context *ctx = dcerpc_event_context(req->p);
931 if (event_loop_once(ctx) != 0) {
932 return NT_STATUS_CONNECTION_DISCONNECTED;
935 *stub_data = req->payload;
936 status = req->status;
937 if (stub_data->data) {
938 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
940 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
941 req->p->last_fault_code = req->fault_code;
948 perform a full request/response pair on a dcerpc pipe
950 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
953 DATA_BLOB *stub_data_in,
954 DATA_BLOB *stub_data_out)
956 struct rpc_request *req;
958 req = dcerpc_request_send(p, opnum, mem_ctx, stub_data_in);
960 return NT_STATUS_NO_MEMORY;
963 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
968 this is a paranoid NDR validator. For every packet we push onto the wire
969 we pull it back again, then push it again. Then we compare the raw NDR data
970 for that to the NDR we initially generated. If they don't match then we know
971 we must have a bug in either the pull or push side of our code
973 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
977 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
978 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
981 struct ndr_pull *pull;
982 struct ndr_push *push;
986 st = talloc(mem_ctx, struct_size);
988 return NT_STATUS_NO_MEMORY;
991 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
993 return NT_STATUS_NO_MEMORY;
996 status = ndr_pull(pull, NDR_IN, st);
997 if (!NT_STATUS_IS_OK(status)) {
998 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
999 "failed input validation pull - %s",
1003 push = ndr_push_init_ctx(mem_ctx);
1005 return NT_STATUS_NO_MEMORY;
1008 status = ndr_push(push, NDR_IN, st);
1009 if (!NT_STATUS_IS_OK(status)) {
1010 return ndr_push_error(push, NDR_ERR_VALIDATE,
1011 "failed input validation push - %s",
1015 blob2 = ndr_push_blob(push);
1017 if (!data_blob_equal(&blob, &blob2)) {
1018 DEBUG(3,("original:\n"));
1019 dump_data(3, blob.data, blob.length);
1020 DEBUG(3,("secondary:\n"));
1021 dump_data(3, blob2.data, blob2.length);
1022 return ndr_push_error(push, NDR_ERR_VALIDATE,
1023 "failed input validation data - %s",
1027 return NT_STATUS_OK;
1031 this is a paranoid NDR input validator. For every packet we pull
1032 from the wire we push it back again then pull and push it
1033 again. Then we compare the raw NDR data for that to the NDR we
1034 initially generated. If they don't match then we know we must have a
1035 bug in either the pull or push side of our code
1037 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1038 TALLOC_CTX *mem_ctx,
1041 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1042 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1045 struct ndr_pull *pull;
1046 struct ndr_push *push;
1048 DATA_BLOB blob, blob2;
1050 st = talloc(mem_ctx, struct_size);
1052 return NT_STATUS_NO_MEMORY;
1054 memcpy(st, struct_ptr, struct_size);
1056 push = ndr_push_init_ctx(mem_ctx);
1058 return NT_STATUS_NO_MEMORY;
1061 status = ndr_push(push, NDR_OUT, struct_ptr);
1062 if (!NT_STATUS_IS_OK(status)) {
1063 return ndr_push_error(push, NDR_ERR_VALIDATE,
1064 "failed output validation push - %s",
1068 blob = ndr_push_blob(push);
1070 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1072 return NT_STATUS_NO_MEMORY;
1075 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1076 status = ndr_pull(pull, NDR_OUT, st);
1077 if (!NT_STATUS_IS_OK(status)) {
1078 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1079 "failed output validation pull - %s",
1083 push = ndr_push_init_ctx(mem_ctx);
1085 return NT_STATUS_NO_MEMORY;
1088 status = ndr_push(push, NDR_OUT, st);
1089 if (!NT_STATUS_IS_OK(status)) {
1090 return ndr_push_error(push, NDR_ERR_VALIDATE,
1091 "failed output validation push2 - %s",
1095 blob2 = ndr_push_blob(push);
1097 if (!data_blob_equal(&blob, &blob2)) {
1098 DEBUG(3,("original:\n"));
1099 dump_data(3, blob.data, blob.length);
1100 DEBUG(3,("secondary:\n"));
1101 dump_data(3, blob2.data, blob2.length);
1102 return ndr_push_error(push, NDR_ERR_VALIDATE,
1103 "failed output validation data - %s",
1107 return NT_STATUS_OK;
1112 send a rpc request with a given set of ndr helper functions
1114 call dcerpc_ndr_request_recv() to receive the answer
1116 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1118 TALLOC_CTX *mem_ctx,
1119 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1120 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1124 struct ndr_push *push;
1127 struct rpc_request *req;
1129 /* setup for a ndr_push_* call */
1130 push = ndr_push_init();
1135 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1136 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1139 /* push the structure into a blob */
1140 status = ndr_push(push, NDR_IN, struct_ptr);
1141 if (!NT_STATUS_IS_OK(status)) {
1142 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1143 nt_errstr(status)));
1144 ndr_push_free(push);
1148 /* retrieve the blob */
1149 request = ndr_push_blob(push);
1151 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1152 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size,
1153 ndr_push, ndr_pull);
1154 if (!NT_STATUS_IS_OK(status)) {
1155 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1156 nt_errstr(status)));
1157 ndr_push_free(push);
1162 DEBUG(10,("rpc request data:\n"));
1163 dump_data(10, request.data, request.length);
1165 /* make the actual dcerpc request */
1166 req = dcerpc_request_send(p, opnum, mem_ctx, &request);
1169 req->ndr.ndr_push = ndr_push;
1170 req->ndr.ndr_pull = ndr_pull;
1171 req->ndr.struct_ptr = struct_ptr;
1172 req->ndr.struct_size = struct_size;
1173 req->ndr.mem_ctx = mem_ctx;
1176 ndr_push_free(push);
1182 receive the answer from a dcerpc_ndr_request_send()
1184 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1186 struct dcerpc_pipe *p = req->p;
1189 struct ndr_pull *pull;
1190 struct rpc_request_ndr ndr = req->ndr;
1193 /* make sure the recv code doesn't free the request, as we
1194 need to grab the flags element before it is freed */
1195 talloc_increase_ref_count(req);
1197 status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1198 if (!NT_STATUS_IS_OK(status)) {
1205 /* prepare for ndr_pull_* */
1206 pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1208 return NT_STATUS_NO_MEMORY;
1211 if (flags & DCERPC_PULL_BIGENDIAN) {
1212 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1215 DEBUG(10,("rpc reply data:\n"));
1216 dump_data(10, pull->data, pull->data_size);
1218 /* pull the structure from the blob */
1219 status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1220 if (!NT_STATUS_IS_OK(status)) {
1224 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1225 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
1226 ndr.ndr_push, ndr.ndr_pull);
1227 if (!NT_STATUS_IS_OK(status)) {
1232 if (pull->offset != pull->data_size) {
1233 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1234 pull->data_size - pull->offset));
1235 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1236 but it turns out that early versions of NT
1237 (specifically NT3.1) add junk onto the end of rpc
1238 packets, so if we want to interoperate at all with
1239 those versions then we need to ignore this error */
1242 return NT_STATUS_OK;
1247 a useful helper function for synchronous rpc requests
1249 this can be used when you have ndr push/pull functions in the
1252 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1254 TALLOC_CTX *mem_ctx,
1255 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1256 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1260 struct rpc_request *req;
1262 req = dcerpc_ndr_request_send(p, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1264 return NT_STATUS_NO_MEMORY;
1267 return dcerpc_ndr_request_recv(req);
1272 a useful function for retrieving the server name we connected to
1274 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1276 if (!p->transport.peer_name) {
1279 return p->transport.peer_name(p);
1283 a useful function to get the auth_level
1286 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1290 if (p->flags & DCERPC_SEAL) {
1291 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1292 } else if (p->flags & DCERPC_SIGN) {
1293 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1294 } else if (p->flags & DCERPC_CONNECT) {
1295 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1297 auth_level = DCERPC_AUTH_LEVEL_NONE;