2 Unix SMB/CIFS implementation.
5 Copyright (C) Tim Potter 2003
6 Copyright (C) Andrew Tridgell 2003
7 Copyright (C) Jelmer Vernooij 2004
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "dlinklist.h"
26 #include "librpc/gen_ndr/ndr_epmapper.h"
28 struct dcerpc_interface_list *dcerpc_pipes = NULL;
30 NTSTATUS librpc_register_interface (const struct dcerpc_interface_table *interface)
32 struct dcerpc_interface_list *l = talloc_p(NULL, struct dcerpc_interface_list);
34 if (idl_iface_by_name (interface->name) != NULL) {
35 DEBUG(0, ("Attempt to register interface %s twice\n", interface->name));
36 return NT_STATUS_OBJECT_NAME_COLLISION;
40 DLIST_ADD(dcerpc_pipes, l);
45 /* initialise a dcerpc pipe. */
46 struct dcerpc_pipe *dcerpc_pipe_init(void)
48 struct dcerpc_pipe *p;
50 p = talloc_p(NULL, struct dcerpc_pipe);
55 p->reference_count = 0;
57 p->security_state.auth_info = NULL;
58 p->security_state.session_key = dcerpc_generic_session_key;
59 p->security_state.generic_state = NULL;
60 p->binding_string = NULL;
62 p->srv_max_xmit_frag = 0;
63 p->srv_max_recv_frag = 0;
64 p->last_fault_code = 0;
71 choose the next call id to use
73 static uint32_t next_call_id(struct dcerpc_pipe *p)
76 if (p->call_id == 0) {
82 /* close down a dcerpc over SMB pipe */
83 void dcerpc_pipe_close(struct dcerpc_pipe *p)
87 if (p->reference_count <= 0) {
88 if (p->security_state.generic_state) {
89 gensec_end(&p->security_state.generic_state);
91 p->transport.shutdown_pipe(p);
96 /* we need to be able to get/set the fragment length without doing a full
98 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16_t v)
100 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
101 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
103 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
107 uint16_t dcerpc_get_frag_length(const DATA_BLOB *blob)
109 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
110 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
112 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
116 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16_t v)
118 if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
119 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
121 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
127 setup for a ndr pull, also setting up any flags from the binding string
129 static struct ndr_pull *ndr_pull_init_flags(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx)
131 struct ndr_pull *ndr = ndr_pull_init_blob(blob, mem_ctx);
133 if (ndr == NULL) return ndr;
135 if (p->flags & DCERPC_DEBUG_PAD_CHECK) {
136 ndr->flags |= LIBNDR_FLAG_PAD_CHECK;
139 if (p->flags & DCERPC_NDR_REF_ALLOC) {
140 ndr->flags |= LIBNDR_FLAG_REF_ALLOC;
147 parse a data blob into a dcerpc_packet structure. This handles both
148 input and output packets
150 static NTSTATUS dcerpc_pull(struct dcerpc_pipe *p, DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
151 struct dcerpc_packet *pkt)
153 struct ndr_pull *ndr;
155 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
157 return NT_STATUS_NO_MEMORY;
160 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
161 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
164 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
168 generate a CONNECT level verifier
170 static NTSTATUS dcerpc_connect_verifier(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
172 *blob = data_blob_talloc(mem_ctx, NULL, 16);
173 if (blob->data == NULL) {
174 return NT_STATUS_NO_MEMORY;
176 SIVAL(blob->data, 0, 1);
177 memset(blob->data+4, 0, 12);
182 generate a CONNECT level verifier
184 static NTSTATUS dcerpc_check_connect_verifier(DATA_BLOB *blob)
186 if (blob->length != 16 ||
187 IVAL(blob->data, 0) != 1) {
188 return NT_STATUS_ACCESS_DENIED;
194 parse a possibly signed blob into a dcerpc request packet structure
196 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
197 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
198 struct dcerpc_packet *pkt)
200 struct ndr_pull *ndr;
202 struct dcerpc_auth auth;
205 /* non-signed packets are simpler */
206 if (!p->security_state.auth_info ||
207 !p->security_state.generic_state) {
208 return dcerpc_pull(p, blob, mem_ctx, pkt);
211 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
213 return NT_STATUS_NO_MEMORY;
216 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
217 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
220 /* pull the basic packet */
221 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
222 if (!NT_STATUS_IS_OK(status)) {
226 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
230 if (pkt->auth_length == 0 &&
231 p->security_state.auth_info->auth_level == DCERPC_AUTH_LEVEL_CONNECT) {
235 auth_blob.length = 8 + pkt->auth_length;
237 /* check for a valid length */
238 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
239 return NT_STATUS_INFO_LENGTH_MISMATCH;
243 pkt->u.response.stub_and_verifier.data +
244 pkt->u.response.stub_and_verifier.length - auth_blob.length;
245 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
247 /* pull the auth structure */
248 ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
250 return NT_STATUS_NO_MEMORY;
253 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
254 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
257 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
258 if (!NT_STATUS_IS_OK(status)) {
263 /* check signature or unseal the packet */
264 switch (p->security_state.auth_info->auth_level) {
265 case DCERPC_AUTH_LEVEL_PRIVACY:
266 status = gensec_unseal_packet(p->security_state.generic_state,
268 blob->data + DCERPC_REQUEST_LENGTH,
269 pkt->u.response.stub_and_verifier.length,
271 blob->length - auth.credentials.length,
273 memcpy(pkt->u.response.stub_and_verifier.data,
274 blob->data + DCERPC_REQUEST_LENGTH,
275 pkt->u.response.stub_and_verifier.length);
278 case DCERPC_AUTH_LEVEL_INTEGRITY:
279 status = gensec_check_packet(p->security_state.generic_state,
281 pkt->u.response.stub_and_verifier.data,
282 pkt->u.response.stub_and_verifier.length,
284 blob->length - auth.credentials.length,
288 case DCERPC_AUTH_LEVEL_CONNECT:
289 status = dcerpc_check_connect_verifier(&auth.credentials);
292 case DCERPC_AUTH_LEVEL_NONE:
296 status = NT_STATUS_INVALID_LEVEL;
300 /* remove the indicated amount of paddiing */
301 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
302 return NT_STATUS_INFO_LENGTH_MISMATCH;
304 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
311 push a dcerpc request packet into a blob, possibly signing it.
313 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
314 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
315 struct dcerpc_packet *pkt)
318 struct ndr_push *ndr;
321 /* non-signed packets are simpler */
322 if (!p->security_state.auth_info ||
323 !p->security_state.generic_state) {
324 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
327 ndr = ndr_push_init_ctx(mem_ctx);
329 return NT_STATUS_NO_MEMORY;
332 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
333 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
336 if (pkt->pfc_flags & DCERPC_PFC_FLAG_ORPC) {
337 ndr->flags |= LIBNDR_FLAG_OBJECT_PRESENT;
340 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
341 if (!NT_STATUS_IS_OK(status)) {
345 /* pad to 16 byte multiple in the payload portion of the
346 packet. This matches what w2k3 does */
347 p->security_state.auth_info->auth_pad_length =
348 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
349 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
351 /* sign or seal the packet */
352 switch (p->security_state.auth_info->auth_level) {
353 case DCERPC_AUTH_LEVEL_PRIVACY:
354 case DCERPC_AUTH_LEVEL_INTEGRITY:
355 p->security_state.auth_info->credentials
356 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
357 data_blob_clear(&p->security_state.auth_info->credentials);
360 case DCERPC_AUTH_LEVEL_CONNECT:
361 status = dcerpc_connect_verifier(mem_ctx, &p->security_state.auth_info->credentials);
364 case DCERPC_AUTH_LEVEL_NONE:
365 p->security_state.auth_info->credentials = data_blob(NULL, 0);
369 status = NT_STATUS_INVALID_LEVEL;
373 if (!NT_STATUS_IS_OK(status)) {
377 /* add the auth verifier */
378 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
379 if (!NT_STATUS_IS_OK(status)) {
383 /* extract the whole packet as a blob */
384 *blob = ndr_push_blob(ndr);
386 /* fill in the fragment length and auth_length, we can't fill
387 in these earlier as we don't know the signature length (it
388 could be variable length) */
389 dcerpc_set_frag_length(blob, blob->length);
390 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
392 /* sign or seal the packet */
393 switch (p->security_state.auth_info->auth_level) {
394 case DCERPC_AUTH_LEVEL_PRIVACY:
395 status = gensec_seal_packet(p->security_state.generic_state,
397 blob->data + DCERPC_REQUEST_LENGTH,
398 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
401 p->security_state.auth_info->credentials.length,
403 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
406 case DCERPC_AUTH_LEVEL_INTEGRITY:
407 status = gensec_sign_packet(p->security_state.generic_state,
409 blob->data + DCERPC_REQUEST_LENGTH,
410 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
413 p->security_state.auth_info->credentials.length,
415 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
418 case DCERPC_AUTH_LEVEL_CONNECT:
421 case DCERPC_AUTH_LEVEL_NONE:
422 p->security_state.auth_info->credentials = data_blob(NULL, 0);
426 status = NT_STATUS_INVALID_LEVEL;
430 data_blob_free(&p->security_state.auth_info->credentials);
437 fill in the fixed values in a dcerpc header
439 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
442 pkt->rpc_vers_minor = 0;
443 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
446 pkt->drep[0] = DCERPC_DREP_LE;
454 hold the state of pending full requests
456 struct full_request_state {
457 DATA_BLOB *reply_blob;
462 receive a reply to a full request
464 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
467 struct full_request_state *state = p->full_request_private;
469 if (!NT_STATUS_IS_OK(status)) {
470 state->status = status;
473 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
474 state->reply_blob = NULL;
478 perform a single pdu synchronous request - used for the bind code
479 this cannot be mixed with normal async requests
481 static NTSTATUS full_request(struct dcerpc_pipe *p,
483 DATA_BLOB *request_blob,
484 DATA_BLOB *reply_blob)
486 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
490 return NT_STATUS_NO_MEMORY;
493 state->reply_blob = reply_blob;
494 state->status = NT_STATUS_OK;
496 p->transport.recv_data = full_request_recv;
497 p->full_request_private = state;
499 status = p->transport.send_request(p, request_blob, True);
500 if (!NT_STATUS_IS_OK(status)) {
504 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
505 struct event_context *ctx = p->transport.event_context(p);
506 if (event_loop_once(ctx) != 0) {
507 return NT_STATUS_CONNECTION_DISCONNECTED;
511 return state->status;
516 perform a bind using the given syntax
518 the auth_info structure is updated with the reply authentication info
521 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
523 const struct dcerpc_syntax_id *syntax,
524 const struct dcerpc_syntax_id *transfer_syntax)
526 struct dcerpc_packet pkt;
531 p->transfer_syntax = *transfer_syntax;
533 init_dcerpc_hdr(p, &pkt);
535 pkt.ptype = DCERPC_PKT_BIND;
536 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
537 pkt.call_id = p->call_id;
540 pkt.u.bind.max_xmit_frag = 5840;
541 pkt.u.bind.max_recv_frag = 5840;
542 pkt.u.bind.assoc_group_id = 0;
543 pkt.u.bind.num_contexts = 1;
544 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
545 if (!pkt.u.bind.ctx_list) {
546 return NT_STATUS_NO_MEMORY;
548 pkt.u.bind.ctx_list[0].context_id = 0;
549 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
550 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
551 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
552 pkt.u.bind.auth_info = data_blob(NULL, 0);
554 /* construct the NDR form of the packet */
555 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
556 if (!NT_STATUS_IS_OK(status)) {
560 /* send it on its way */
561 status = full_request(p, mem_ctx, &blob, &blob);
562 if (!NT_STATUS_IS_OK(status)) {
566 /* unmarshall the NDR */
567 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
568 if (!NT_STATUS_IS_OK(status)) {
572 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
573 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
574 return NT_STATUS_ACCESS_DENIED;
577 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
578 pkt.u.bind_ack.num_results == 0 ||
579 pkt.u.bind_ack.ctx_list[0].result != 0) {
580 return NT_STATUS_UNSUCCESSFUL;
583 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
584 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
585 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
588 /* the bind_ack might contain a reply set of credentials */
589 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
590 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
592 p->security_state.auth_info,
593 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
600 perform a alter context using the given syntax
602 the auth_info structure is updated with the reply authentication info
605 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
608 struct dcerpc_packet pkt;
612 init_dcerpc_hdr(p, &pkt);
614 pkt.ptype = DCERPC_PKT_ALTER;
615 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
616 pkt.call_id = p->call_id;
619 pkt.u.alter.max_xmit_frag = 0x2000;
620 pkt.u.alter.max_recv_frag = 0x2000;
621 pkt.u.alter.assoc_group_id = 0;
622 pkt.u.alter.num_contexts = 1;
623 pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
624 if (!pkt.u.alter.ctx_list) {
625 return NT_STATUS_NO_MEMORY;
627 pkt.u.alter.ctx_list[0].context_id = 0;
628 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
629 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
630 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
631 pkt.u.alter.auth_info = data_blob(NULL, 0);
633 /* construct the NDR form of the packet */
634 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
635 if (!NT_STATUS_IS_OK(status)) {
639 /* send it on its way */
640 status = full_request(p, mem_ctx, &blob, &blob);
641 if (!NT_STATUS_IS_OK(status)) {
645 /* unmarshall the NDR */
646 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
647 if (!NT_STATUS_IS_OK(status)) {
651 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
652 pkt.u.alter_ack.num_results == 0 ||
653 pkt.u.alter_ack.ctx_list[0].result != 0) {
654 status = NT_STATUS_UNSUCCESSFUL;
657 /* the bind_ack might contain a reply set of credentials */
658 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
659 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
661 p->security_state.auth_info,
662 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
669 perform a continued bind (and auth3)
671 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
674 struct dcerpc_packet pkt;
678 init_dcerpc_hdr(p, &pkt);
680 pkt.ptype = DCERPC_PKT_AUTH3;
681 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
682 pkt.call_id = next_call_id(p);
685 pkt.u.auth.auth_info = data_blob(NULL, 0);
687 /* construct the NDR form of the packet */
688 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
689 if (!NT_STATUS_IS_OK(status)) {
693 /* send it on its way */
694 status = p->transport.send_request(p, &blob, False);
695 if (!NT_STATUS_IS_OK(status)) {
703 /* perform a dcerpc bind, using the uuid as the key */
704 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
706 const char *uuid, uint_t version)
708 struct dcerpc_syntax_id syntax;
709 struct dcerpc_syntax_id transfer_syntax;
712 status = GUID_from_string(uuid, &syntax.uuid);
713 if (!NT_STATUS_IS_OK(status)) {
714 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
717 syntax.if_version = version;
719 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
720 if (!NT_STATUS_IS_OK(status)) {
723 transfer_syntax.if_version = NDR_GUID_VERSION;
725 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
729 process a fragment received from the transport layer during a
732 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
736 struct dcerpc_packet pkt;
737 struct rpc_request *req;
740 if (!NT_STATUS_IS_OK(status)) {
741 /* all pending requests get the error */
744 req->state = RPC_REQUEST_DONE;
745 req->status = status;
746 DLIST_REMOVE(p->pending, req);
747 if (req->async.callback) {
748 req->async.callback(req);
756 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
758 /* find the matching request. Notice we match before we check
759 the status. this is ok as a pending call_id can never be
761 for (req=p->pending;req;req=req->next) {
762 if (pkt.call_id == req->call_id) break;
766 DEBUG(2,("dcerpc_request: unmatched call_id %u in response packet\n", pkt.call_id));
770 if (!NT_STATUS_IS_OK(status)) {
771 req->status = status;
772 req->state = RPC_REQUEST_DONE;
773 DLIST_REMOVE(p->pending, req);
774 if (req->async.callback) {
775 req->async.callback(req);
780 if (pkt.ptype == DCERPC_PKT_FAULT) {
781 DEBUG(5,("rpc fault: %s\n", dcerpc_errstr(p, pkt.u.fault.status)));
782 req->fault_code = pkt.u.fault.status;
783 req->status = NT_STATUS_NET_WRITE_FAULT;
784 req->state = RPC_REQUEST_DONE;
785 DLIST_REMOVE(p->pending, req);
786 if (req->async.callback) {
787 req->async.callback(req);
792 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
793 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
795 req->fault_code = DCERPC_FAULT_OTHER;
796 req->status = NT_STATUS_NET_WRITE_FAULT;
797 req->state = RPC_REQUEST_DONE;
798 DLIST_REMOVE(p->pending, req);
799 if (req->async.callback) {
800 req->async.callback(req);
805 length = pkt.u.response.stub_and_verifier.length;
808 req->payload.data = talloc_realloc(req,
810 req->payload.length + length);
811 if (!req->payload.data) {
812 req->status = NT_STATUS_NO_MEMORY;
813 req->state = RPC_REQUEST_DONE;
814 DLIST_REMOVE(p->pending, req);
815 if (req->async.callback) {
816 req->async.callback(req);
820 memcpy(req->payload.data+req->payload.length,
821 pkt.u.response.stub_and_verifier.data, length);
822 req->payload.length += length;
825 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
826 p->transport.send_read(p);
830 /* we've got the full payload */
831 req->state = RPC_REQUEST_DONE;
832 DLIST_REMOVE(p->pending, req);
834 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
835 req->flags |= DCERPC_PULL_BIGENDIAN;
837 req->flags &= ~DCERPC_PULL_BIGENDIAN;
840 if (req->async.callback) {
841 req->async.callback(req);
847 make sure requests are cleaned up
849 static int dcerpc_req_destructor(void *ptr)
851 struct rpc_request *req = ptr;
852 DLIST_REMOVE(req->p->pending, req);
857 perform the send size of a async dcerpc request
859 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
860 const struct GUID *object,
863 DATA_BLOB *stub_data)
865 struct rpc_request *req;
866 struct dcerpc_packet pkt;
868 uint32_t remaining, chunk_size;
869 BOOL first_packet = True;
871 p->transport.recv_data = dcerpc_request_recv_data;
873 req = talloc_p(mem_ctx, struct rpc_request);
879 req->call_id = next_call_id(p);
880 req->status = NT_STATUS_OK;
881 req->state = RPC_REQUEST_PENDING;
882 req->payload = data_blob(NULL, 0);
885 req->async.callback = NULL;
887 init_dcerpc_hdr(p, &pkt);
889 remaining = stub_data->length;
891 /* we can write a full max_recv_frag size, minus the dcerpc
892 request header size */
893 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
895 pkt.ptype = DCERPC_PKT_REQUEST;
896 pkt.call_id = req->call_id;
899 pkt.u.request.alloc_hint = remaining;
900 pkt.u.request.context_id = 0;
901 pkt.u.request.opnum = opnum;
904 pkt.u.request.object.object = *object;
905 pkt.pfc_flags |= DCERPC_PFC_FLAG_ORPC;
906 chunk_size -= ndr_size_GUID(0,object,0);
909 DLIST_ADD(p->pending, req);
911 /* we send a series of pdus without waiting for a reply */
912 while (remaining > 0 || first_packet) {
913 uint32_t chunk = MIN(chunk_size, remaining);
914 BOOL last_frag = False;
916 first_packet = False;
917 pkt.pfc_flags &= ~(DCERPC_PFC_FLAG_FIRST |DCERPC_PFC_FLAG_LAST);
919 if (remaining == stub_data->length) {
920 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
922 if (chunk == remaining) {
923 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
927 pkt.u.request.stub_and_verifier.data = stub_data->data +
928 (stub_data->length - remaining);
929 pkt.u.request.stub_and_verifier.length = chunk;
931 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
932 if (!NT_STATUS_IS_OK(req->status)) {
933 req->state = RPC_REQUEST_DONE;
934 DLIST_REMOVE(p->pending, req);
938 req->status = p->transport.send_request(p, &blob, last_frag);
939 if (!NT_STATUS_IS_OK(req->status)) {
940 req->state = RPC_REQUEST_DONE;
941 DLIST_REMOVE(p->pending, req);
948 talloc_set_destructor(req, dcerpc_req_destructor);
954 return the event context for a dcerpc pipe
955 used by callers who wish to operate asynchronously
957 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
959 return p->transport.event_context(p);
965 perform the receive side of a async dcerpc request
967 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
969 DATA_BLOB *stub_data)
973 while (req->state == RPC_REQUEST_PENDING) {
974 struct event_context *ctx = dcerpc_event_context(req->p);
975 if (event_loop_once(ctx) != 0) {
976 return NT_STATUS_CONNECTION_DISCONNECTED;
979 *stub_data = req->payload;
980 status = req->status;
981 if (stub_data->data) {
982 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
984 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
985 req->p->last_fault_code = req->fault_code;
992 perform a full request/response pair on a dcerpc pipe
994 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
998 DATA_BLOB *stub_data_in,
999 DATA_BLOB *stub_data_out)
1001 struct rpc_request *req;
1003 req = dcerpc_request_send(p, object, opnum, mem_ctx, stub_data_in);
1005 return NT_STATUS_NO_MEMORY;
1008 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
1013 this is a paranoid NDR validator. For every packet we push onto the wire
1014 we pull it back again, then push it again. Then we compare the raw NDR data
1015 for that to the NDR we initially generated. If they don't match then we know
1016 we must have a bug in either the pull or push side of our code
1018 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
1019 TALLOC_CTX *mem_ctx,
1022 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1023 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1026 struct ndr_pull *pull;
1027 struct ndr_push *push;
1031 st = talloc(mem_ctx, struct_size);
1033 return NT_STATUS_NO_MEMORY;
1036 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1038 return NT_STATUS_NO_MEMORY;
1041 status = ndr_pull(pull, NDR_IN, st);
1042 if (!NT_STATUS_IS_OK(status)) {
1043 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1044 "failed input validation pull - %s",
1048 push = ndr_push_init_ctx(mem_ctx);
1050 return NT_STATUS_NO_MEMORY;
1053 status = ndr_push(push, NDR_IN, st);
1054 if (!NT_STATUS_IS_OK(status)) {
1055 return ndr_push_error(push, NDR_ERR_VALIDATE,
1056 "failed input validation push - %s",
1060 blob2 = ndr_push_blob(push);
1062 if (!data_blob_equal(&blob, &blob2)) {
1063 DEBUG(3,("original:\n"));
1064 dump_data(3, blob.data, blob.length);
1065 DEBUG(3,("secondary:\n"));
1066 dump_data(3, blob2.data, blob2.length);
1067 return ndr_push_error(push, NDR_ERR_VALIDATE,
1068 "failed input validation data - %s",
1072 return NT_STATUS_OK;
1076 this is a paranoid NDR input validator. For every packet we pull
1077 from the wire we push it back again then pull and push it
1078 again. Then we compare the raw NDR data for that to the NDR we
1079 initially generated. If they don't match then we know we must have a
1080 bug in either the pull or push side of our code
1082 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
1083 TALLOC_CTX *mem_ctx,
1086 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1087 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
1090 struct ndr_pull *pull;
1091 struct ndr_push *push;
1093 DATA_BLOB blob, blob2;
1095 st = talloc(mem_ctx, struct_size);
1097 return NT_STATUS_NO_MEMORY;
1099 memcpy(st, struct_ptr, struct_size);
1101 push = ndr_push_init_ctx(mem_ctx);
1103 return NT_STATUS_NO_MEMORY;
1106 status = ndr_push(push, NDR_OUT, struct_ptr);
1107 if (!NT_STATUS_IS_OK(status)) {
1108 return ndr_push_error(push, NDR_ERR_VALIDATE,
1109 "failed output validation push - %s",
1113 blob = ndr_push_blob(push);
1115 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1117 return NT_STATUS_NO_MEMORY;
1120 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1121 status = ndr_pull(pull, NDR_OUT, st);
1122 if (!NT_STATUS_IS_OK(status)) {
1123 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1124 "failed output validation pull - %s",
1128 push = ndr_push_init_ctx(mem_ctx);
1130 return NT_STATUS_NO_MEMORY;
1133 status = ndr_push(push, NDR_OUT, st);
1134 if (!NT_STATUS_IS_OK(status)) {
1135 return ndr_push_error(push, NDR_ERR_VALIDATE,
1136 "failed output validation push2 - %s",
1140 blob2 = ndr_push_blob(push);
1142 if (!data_blob_equal(&blob, &blob2)) {
1143 DEBUG(3,("original:\n"));
1144 dump_data(3, blob.data, blob.length);
1145 DEBUG(3,("secondary:\n"));
1146 dump_data(3, blob2.data, blob2.length);
1147 return ndr_push_error(push, NDR_ERR_VALIDATE,
1148 "failed output validation data - %s",
1152 return NT_STATUS_OK;
1157 send a rpc request given a dcerpc_call structure
1159 struct rpc_request *dcerpc_ndr_request_table_send(struct dcerpc_pipe *p,
1160 const struct GUID *object,
1161 const struct dcerpc_interface_table *table,
1163 TALLOC_CTX *mem_ctx,
1166 const struct dcerpc_interface_call *call = &table->calls[opnum];
1168 return dcerpc_ndr_request_send(p, object, opnum, mem_ctx, call->ndr_push, call->ndr_pull, r, call->struct_size);
1173 send a rpc request with a given set of ndr helper functions
1175 call dcerpc_ndr_request_recv() to receive the answer
1177 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1178 const struct GUID *object,
1180 TALLOC_CTX *mem_ctx,
1181 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1182 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1186 struct ndr_push *push;
1189 struct rpc_request *req;
1191 /* setup for a ndr_push_* call */
1192 push = ndr_push_init();
1197 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1198 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1201 /* push the structure into a blob */
1202 status = ndr_push(push, NDR_IN, struct_ptr);
1203 if (!NT_STATUS_IS_OK(status)) {
1204 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1205 nt_errstr(status)));
1206 ndr_push_free(push);
1210 /* retrieve the blob */
1211 request = ndr_push_blob(push);
1213 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1214 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size,
1215 ndr_push, ndr_pull);
1216 if (!NT_STATUS_IS_OK(status)) {
1217 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1218 nt_errstr(status)));
1219 ndr_push_free(push);
1224 DEBUG(10,("rpc request data:\n"));
1225 dump_data(10, request.data, request.length);
1227 /* make the actual dcerpc request */
1228 req = dcerpc_request_send(p, object, opnum, mem_ctx, &request);
1231 req->ndr.ndr_push = ndr_push;
1232 req->ndr.ndr_pull = ndr_pull;
1233 req->ndr.struct_ptr = struct_ptr;
1234 req->ndr.struct_size = struct_size;
1235 req->ndr.mem_ctx = mem_ctx;
1238 ndr_push_free(push);
1244 receive the answer from a dcerpc_ndr_request_send()
1246 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1248 struct dcerpc_pipe *p = req->p;
1251 struct ndr_pull *pull;
1252 struct rpc_request_ndr ndr = req->ndr;
1255 /* make sure the recv code doesn't free the request, as we
1256 need to grab the flags element before it is freed */
1257 talloc_increase_ref_count(req);
1259 status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1260 if (!NT_STATUS_IS_OK(status)) {
1267 /* prepare for ndr_pull_* */
1268 pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1270 return NT_STATUS_NO_MEMORY;
1273 if (flags & DCERPC_PULL_BIGENDIAN) {
1274 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1277 DEBUG(10,("rpc reply data:\n"));
1278 dump_data(10, pull->data, pull->data_size);
1280 /* pull the structure from the blob */
1281 status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1282 if (!NT_STATUS_IS_OK(status)) {
1286 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1287 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
1288 ndr.ndr_push, ndr.ndr_pull);
1289 if (!NT_STATUS_IS_OK(status)) {
1294 if (pull->offset != pull->data_size) {
1295 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1296 pull->data_size - pull->offset));
1297 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1298 but it turns out that early versions of NT
1299 (specifically NT3.1) add junk onto the end of rpc
1300 packets, so if we want to interoperate at all with
1301 those versions then we need to ignore this error */
1304 return NT_STATUS_OK;
1309 a useful helper function for synchronous rpc requests
1311 this can be used when you have ndr push/pull functions in the
1314 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1315 struct GUID *object,
1317 TALLOC_CTX *mem_ctx,
1318 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1319 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1323 struct rpc_request *req;
1325 req = dcerpc_ndr_request_send(p, object, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1327 return NT_STATUS_NO_MEMORY;
1330 return dcerpc_ndr_request_recv(req);
1335 a useful function for retrieving the server name we connected to
1337 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1339 if (!p->transport.peer_name) {
1342 return p->transport.peer_name(p);
1346 a useful function to get the auth_level
1349 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1353 if (p->flags & DCERPC_SEAL) {
1354 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1355 } else if (p->flags & DCERPC_SIGN) {
1356 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1357 } else if (p->flags & DCERPC_CONNECT) {
1358 auth_level = DCERPC_AUTH_LEVEL_CONNECT;
1360 auth_level = DCERPC_AUTH_LEVEL_NONE;