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. This currently assumes a SMB named 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 parse a possibly signed blob into a dcerpc request packet structure
151 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
152 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
153 struct dcerpc_packet *pkt)
155 struct ndr_pull *ndr;
157 struct dcerpc_auth auth;
160 /* non-signed packets are simpler */
161 if (!p->security_state.auth_info || !p->security_state.generic_state) {
162 return dcerpc_pull(p, blob, mem_ctx, pkt);
165 ndr = ndr_pull_init_flags(p, blob, mem_ctx);
167 return NT_STATUS_NO_MEMORY;
170 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
171 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
174 /* pull the basic packet */
175 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
176 if (!NT_STATUS_IS_OK(status)) {
180 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
184 auth_blob.length = 8 + pkt->auth_length;
186 /* check for a valid length */
187 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
188 return NT_STATUS_INFO_LENGTH_MISMATCH;
192 pkt->u.response.stub_and_verifier.data +
193 pkt->u.response.stub_and_verifier.length - auth_blob.length;
194 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
196 /* pull the auth structure */
197 ndr = ndr_pull_init_flags(p, &auth_blob, mem_ctx);
199 return NT_STATUS_NO_MEMORY;
202 if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
203 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
206 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
207 if (!NT_STATUS_IS_OK(status)) {
212 /* check signature or unseal the packet */
213 switch (p->security_state.auth_info->auth_level) {
214 case DCERPC_AUTH_LEVEL_PRIVACY:
215 status = gensec_unseal_packet(p->security_state.generic_state,
217 blob->data + DCERPC_REQUEST_LENGTH,
218 pkt->u.response.stub_and_verifier.length,
220 blob->length - auth.credentials.length,
222 memcpy(pkt->u.response.stub_and_verifier.data,
223 blob->data + DCERPC_REQUEST_LENGTH,
224 pkt->u.response.stub_and_verifier.length);
227 case DCERPC_AUTH_LEVEL_INTEGRITY:
228 status = gensec_check_packet(p->security_state.generic_state,
230 pkt->u.response.stub_and_verifier.data,
231 pkt->u.response.stub_and_verifier.length,
233 blob->length - auth.credentials.length,
237 case DCERPC_AUTH_LEVEL_NONE:
241 status = NT_STATUS_INVALID_LEVEL;
245 /* remove the indicated amount of paddiing */
246 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
247 return NT_STATUS_INFO_LENGTH_MISMATCH;
249 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
256 push a dcerpc request packet into a blob, possibly signing it.
258 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
259 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
260 struct dcerpc_packet *pkt)
263 struct ndr_push *ndr;
266 /* non-signed packets are simpler */
267 if (!p->security_state.auth_info || !p->security_state.generic_state) {
268 return dcerpc_push_auth(blob, mem_ctx, pkt, p->security_state.auth_info);
271 ndr = ndr_push_init_ctx(mem_ctx);
273 return NT_STATUS_NO_MEMORY;
276 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
277 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
280 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
281 if (!NT_STATUS_IS_OK(status)) {
285 /* pad to 16 byte multiple in the payload portion of the
286 packet. This matches what w2k3 does */
287 p->security_state.auth_info->auth_pad_length =
288 (16 - (pkt->u.request.stub_and_verifier.length & 15)) & 15;
289 ndr_push_zero(ndr, p->security_state.auth_info->auth_pad_length);
291 /* sign or seal the packet */
292 switch (p->security_state.auth_info->auth_level) {
293 case DCERPC_AUTH_LEVEL_PRIVACY:
294 case DCERPC_AUTH_LEVEL_INTEGRITY:
295 p->security_state.auth_info->credentials
296 = data_blob_talloc(mem_ctx, NULL, gensec_sig_size(p->security_state.generic_state));
297 data_blob_clear(&p->security_state.auth_info->credentials);
300 case DCERPC_AUTH_LEVEL_NONE:
301 p->security_state.auth_info->credentials = data_blob(NULL, 0);
305 status = NT_STATUS_INVALID_LEVEL;
309 if (!NT_STATUS_IS_OK(status)) {
313 /* add the auth verifier */
314 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->security_state.auth_info);
315 if (!NT_STATUS_IS_OK(status)) {
319 /* extract the whole packet as a blob */
320 *blob = ndr_push_blob(ndr);
322 /* fill in the fragment length and auth_length, we can't fill
323 in these earlier as we don't know the signature length (it
324 could be variable length) */
325 dcerpc_set_frag_length(blob, blob->length);
326 dcerpc_set_auth_length(blob, p->security_state.auth_info->credentials.length);
328 /* sign or seal the packet */
329 switch (p->security_state.auth_info->auth_level) {
330 case DCERPC_AUTH_LEVEL_PRIVACY:
331 status = gensec_seal_packet(p->security_state.generic_state,
333 blob->data + DCERPC_REQUEST_LENGTH,
334 pkt->u.request.stub_and_verifier.length+p->security_state.auth_info->auth_pad_length,
337 p->security_state.auth_info->credentials.length,
339 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
342 case DCERPC_AUTH_LEVEL_INTEGRITY:
343 status = gensec_sign_packet(p->security_state.generic_state,
345 blob->data + DCERPC_REQUEST_LENGTH,
346 pkt->u.request.stub_and_verifier.length,
349 p->security_state.auth_info->credentials.length,
351 memcpy(blob->data + blob->length - creds2.length, creds2.data, creds2.length);
354 case DCERPC_AUTH_LEVEL_NONE:
355 p->security_state.auth_info->credentials = data_blob(NULL, 0);
359 status = NT_STATUS_INVALID_LEVEL;
363 data_blob_free(&p->security_state.auth_info->credentials);
370 fill in the fixed values in a dcerpc header
372 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
375 pkt->rpc_vers_minor = 0;
376 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
379 pkt->drep[0] = DCERPC_DREP_LE;
387 hold the state of pending full requests
389 struct full_request_state {
390 DATA_BLOB *reply_blob;
395 receive a reply to a full request
397 static void full_request_recv(struct dcerpc_pipe *p, DATA_BLOB *blob,
400 struct full_request_state *state = p->full_request_private;
402 if (!NT_STATUS_IS_OK(status)) {
403 state->status = status;
406 state->reply_blob[0] = data_blob_talloc(state, blob->data, blob->length);
407 state->reply_blob = NULL;
411 perform a single pdu synchronous request - used for the bind code
412 this cannot be mixed with normal async requests
414 static NTSTATUS full_request(struct dcerpc_pipe *p,
416 DATA_BLOB *request_blob,
417 DATA_BLOB *reply_blob)
419 struct full_request_state *state = talloc_p(mem_ctx, struct full_request_state);
423 return NT_STATUS_NO_MEMORY;
426 state->reply_blob = reply_blob;
427 state->status = NT_STATUS_OK;
429 p->transport.recv_data = full_request_recv;
430 p->full_request_private = state;
432 status = p->transport.send_request(p, request_blob, True);
433 if (!NT_STATUS_IS_OK(status)) {
437 while (NT_STATUS_IS_OK(state->status) && state->reply_blob) {
438 struct event_context *ctx = p->transport.event_context(p);
439 event_loop_once(ctx);
442 return state->status;
447 perform a bind using the given syntax
449 the auth_info structure is updated with the reply authentication info
452 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
454 const struct dcerpc_syntax_id *syntax,
455 const struct dcerpc_syntax_id *transfer_syntax)
457 struct dcerpc_packet pkt;
462 p->transfer_syntax = *transfer_syntax;
464 init_dcerpc_hdr(p, &pkt);
466 pkt.ptype = DCERPC_PKT_BIND;
467 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
468 pkt.call_id = p->call_id;
471 pkt.u.bind.max_xmit_frag = 5840;
472 pkt.u.bind.max_recv_frag = 5840;
473 pkt.u.bind.assoc_group_id = 0;
474 pkt.u.bind.num_contexts = 1;
475 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
476 if (!pkt.u.bind.ctx_list) {
477 return NT_STATUS_NO_MEMORY;
479 pkt.u.bind.ctx_list[0].context_id = 0;
480 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
481 pkt.u.bind.ctx_list[0].abstract_syntax = p->syntax;
482 pkt.u.bind.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
483 pkt.u.bind.auth_info = data_blob(NULL, 0);
485 /* construct the NDR form of the packet */
486 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
487 if (!NT_STATUS_IS_OK(status)) {
491 /* send it on its way */
492 status = full_request(p, mem_ctx, &blob, &blob);
493 if (!NT_STATUS_IS_OK(status)) {
497 /* unmarshall the NDR */
498 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
499 if (!NT_STATUS_IS_OK(status)) {
503 if (pkt.ptype == DCERPC_PKT_BIND_NAK) {
504 DEBUG(2,("dcerpc: bind_nak reason %d\n", pkt.u.bind_nak.reject_reason));
505 return NT_STATUS_ACCESS_DENIED;
508 if ((pkt.ptype != DCERPC_PKT_BIND_ACK) ||
509 pkt.u.bind_ack.num_results == 0 ||
510 pkt.u.bind_ack.ctx_list[0].result != 0) {
511 return NT_STATUS_UNSUCCESSFUL;
514 if (pkt.ptype == DCERPC_PKT_BIND_ACK) {
515 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
516 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
519 /* the bind_ack might contain a reply set of credentials */
520 if (p->security_state.auth_info && pkt.u.bind_ack.auth_info.length) {
521 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
523 p->security_state.auth_info,
524 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
531 perform a alter context using the given syntax
533 the auth_info structure is updated with the reply authentication info
536 NTSTATUS dcerpc_alter(struct dcerpc_pipe *p,
539 struct dcerpc_packet pkt;
543 init_dcerpc_hdr(p, &pkt);
545 pkt.ptype = DCERPC_PKT_ALTER;
546 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
547 pkt.call_id = p->call_id;
550 pkt.u.alter.max_xmit_frag = 0x2000;
551 pkt.u.alter.max_recv_frag = 0x2000;
552 pkt.u.alter.assoc_group_id = 0;
553 pkt.u.alter.num_contexts = 1;
554 pkt.u.alter.ctx_list = talloc(mem_ctx, sizeof(pkt.u.alter.ctx_list[0]));
555 if (!pkt.u.alter.ctx_list) {
556 return NT_STATUS_NO_MEMORY;
558 pkt.u.alter.ctx_list[0].context_id = 0;
559 pkt.u.alter.ctx_list[0].num_transfer_syntaxes = 1;
560 pkt.u.alter.ctx_list[0].abstract_syntax = p->syntax;
561 pkt.u.alter.ctx_list[0].transfer_syntaxes = &p->transfer_syntax;
562 pkt.u.alter.auth_info = data_blob(NULL, 0);
564 /* construct the NDR form of the packet */
565 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
566 if (!NT_STATUS_IS_OK(status)) {
570 /* send it on its way */
571 status = full_request(p, mem_ctx, &blob, &blob);
572 if (!NT_STATUS_IS_OK(status)) {
576 /* unmarshall the NDR */
577 status = dcerpc_pull(p, &blob, mem_ctx, &pkt);
578 if (!NT_STATUS_IS_OK(status)) {
582 if ((pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
583 pkt.u.alter_ack.num_results == 0 ||
584 pkt.u.alter_ack.ctx_list[0].result != 0) {
585 status = NT_STATUS_UNSUCCESSFUL;
588 /* the bind_ack might contain a reply set of credentials */
589 if (p->security_state.auth_info && pkt.u.alter_ack.auth_info.length) {
590 status = ndr_pull_struct_blob(&pkt.u.alter_ack.auth_info,
592 p->security_state.auth_info,
593 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
600 perform a continued bind (and auth3)
602 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
605 struct dcerpc_packet pkt;
609 init_dcerpc_hdr(p, &pkt);
611 pkt.ptype = DCERPC_PKT_AUTH3;
612 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
613 pkt.call_id = next_call_id(p);
616 pkt.u.auth.auth_info = data_blob(NULL, 0);
618 /* construct the NDR form of the packet */
619 status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->security_state.auth_info);
620 if (!NT_STATUS_IS_OK(status)) {
624 /* send it on its way */
625 status = p->transport.send_request(p, &blob, False);
626 if (!NT_STATUS_IS_OK(status)) {
634 /* perform a dcerpc bind, using the uuid as the key */
635 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
637 const char *uuid, uint_t version)
639 struct dcerpc_syntax_id syntax;
640 struct dcerpc_syntax_id transfer_syntax;
643 status = GUID_from_string(uuid, &syntax.uuid);
644 if (!NT_STATUS_IS_OK(status)) {
645 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
648 syntax.if_version = version;
650 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
651 if (!NT_STATUS_IS_OK(status)) {
654 transfer_syntax.if_version = NDR_GUID_VERSION;
656 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
660 process a fragment received from the transport layer during a
663 static void dcerpc_request_recv_data(struct dcerpc_pipe *p,
667 struct dcerpc_packet pkt;
668 struct rpc_request *req;
671 if (!NT_STATUS_IS_OK(status)) {
672 /* all pending requests get the error */
675 req->state = RPC_REQUEST_DONE;
676 req->status = status;
677 DLIST_REMOVE(p->pending, req);
678 if (req->async.callback) {
679 req->async.callback(req);
687 status = dcerpc_pull_request_sign(p, data, (TALLOC_CTX *)data->data, &pkt);
689 /* find the matching request. Notice we match before we check
690 the status. this is ok as a pending call_id can never be
692 for (req=p->pending;req;req=req->next) {
693 if (pkt.call_id == req->call_id) break;
697 DEBUG(2,("dcerpc_request: unmatched call_id in response packet\n"));
701 if (!NT_STATUS_IS_OK(status)) {
702 req->status = status;
703 req->state = RPC_REQUEST_DONE;
704 DLIST_REMOVE(p->pending, req);
705 if (req->async.callback) {
706 req->async.callback(req);
711 if (pkt.ptype == DCERPC_PKT_FAULT) {
712 DEBUG(5,("rpc fault 0x%x\n", pkt.u.fault.status));
713 req->fault_code = pkt.u.fault.status;
714 req->status = NT_STATUS_NET_WRITE_FAULT;
715 req->state = RPC_REQUEST_DONE;
716 DLIST_REMOVE(p->pending, req);
717 if (req->async.callback) {
718 req->async.callback(req);
723 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
724 DEBUG(2,("Unexpected packet type %d in dcerpc response\n",
726 req->fault_code = DCERPC_FAULT_OTHER;
727 req->status = NT_STATUS_NET_WRITE_FAULT;
728 req->state = RPC_REQUEST_DONE;
729 DLIST_REMOVE(p->pending, req);
730 if (req->async.callback) {
731 req->async.callback(req);
736 length = pkt.u.response.stub_and_verifier.length;
739 req->payload.data = talloc_realloc(req->payload.data,
740 req->payload.length + length);
741 if (!req->payload.data) {
742 req->status = NT_STATUS_NO_MEMORY;
743 req->state = RPC_REQUEST_DONE;
744 DLIST_REMOVE(p->pending, req);
745 if (req->async.callback) {
746 req->async.callback(req);
750 memcpy(req->payload.data+req->payload.length,
751 pkt.u.response.stub_and_verifier.data, length);
752 req->payload.length += length;
755 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
756 p->transport.send_read(p);
760 /* we've got the full payload */
761 req->state = RPC_REQUEST_DONE;
762 DLIST_REMOVE(p->pending, req);
764 if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
765 req->flags |= DCERPC_PULL_BIGENDIAN;
767 req->flags &= ~DCERPC_PULL_BIGENDIAN;
770 if (req->async.callback) {
771 req->async.callback(req);
777 perform the send size of a async dcerpc request
779 struct rpc_request *dcerpc_request_send(struct dcerpc_pipe *p,
782 DATA_BLOB *stub_data)
784 struct rpc_request *req;
785 struct dcerpc_packet pkt;
787 uint32_t remaining, chunk_size;
789 p->transport.recv_data = dcerpc_request_recv_data;
791 req = talloc_p(mem_ctx, struct rpc_request);
797 req->call_id = next_call_id(p);
798 req->status = NT_STATUS_OK;
799 req->state = RPC_REQUEST_PENDING;
800 req->payload = data_blob(NULL, 0);
803 req->async.callback = NULL;
805 init_dcerpc_hdr(p, &pkt);
807 remaining = stub_data->length;
809 /* we can write a full max_recv_frag size, minus the dcerpc
810 request header size */
811 chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
813 pkt.ptype = DCERPC_PKT_REQUEST;
814 pkt.call_id = req->call_id;
816 pkt.u.request.alloc_hint = remaining;
817 pkt.u.request.context_id = 0;
818 pkt.u.request.opnum = opnum;
820 DLIST_ADD(p->pending, req);
822 /* we send a series of pdus without waiting for a reply */
823 while (remaining > 0) {
824 uint32_t chunk = MIN(chunk_size, remaining);
825 BOOL last_frag = False;
829 if (remaining == stub_data->length) {
830 pkt.pfc_flags |= DCERPC_PFC_FLAG_FIRST;
832 if (chunk == remaining) {
833 pkt.pfc_flags |= DCERPC_PFC_FLAG_LAST;
837 pkt.u.request.stub_and_verifier.data = stub_data->data +
838 (stub_data->length - remaining);
839 pkt.u.request.stub_and_verifier.length = chunk;
841 req->status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
842 if (!NT_STATUS_IS_OK(req->status)) {
843 req->state = RPC_REQUEST_DONE;
844 DLIST_REMOVE(p->pending, req);
848 req->status = p->transport.send_request(p, &blob, last_frag);
849 if (!NT_STATUS_IS_OK(req->status)) {
850 req->state = RPC_REQUEST_DONE;
851 DLIST_REMOVE(p->pending, req);
862 return the event context for a dcerpc pipe
863 used by callers who wish to operate asynchronously
865 struct event_context *dcerpc_event_context(struct dcerpc_pipe *p)
867 return p->transport.event_context(p);
873 perform the receive side of a async dcerpc request
875 NTSTATUS dcerpc_request_recv(struct rpc_request *req,
877 DATA_BLOB *stub_data)
881 while (req->state == RPC_REQUEST_PENDING) {
882 struct event_context *ctx = dcerpc_event_context(req->p);
883 event_loop_once(ctx);
885 *stub_data = req->payload;
886 status = req->status;
887 if (stub_data->data) {
888 stub_data->data = talloc_steal(mem_ctx, stub_data->data);
890 if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
891 req->p->last_fault_code = req->fault_code;
898 perform a full request/response pair on a dcerpc pipe
900 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
903 DATA_BLOB *stub_data_in,
904 DATA_BLOB *stub_data_out)
906 struct rpc_request *req;
908 req = dcerpc_request_send(p, opnum, mem_ctx, stub_data_in);
910 return NT_STATUS_NO_MEMORY;
913 return dcerpc_request_recv(req, mem_ctx, stub_data_out);
918 this is a paranoid NDR validator. For every packet we push onto the wire
919 we pull it back again, then push it again. Then we compare the raw NDR data
920 for that to the NDR we initially generated. If they don't match then we know
921 we must have a bug in either the pull or push side of our code
923 static NTSTATUS dcerpc_ndr_validate_in(struct dcerpc_pipe *p,
927 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
928 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
931 struct ndr_pull *pull;
932 struct ndr_push *push;
936 st = talloc(mem_ctx, struct_size);
938 return NT_STATUS_NO_MEMORY;
941 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
943 return NT_STATUS_NO_MEMORY;
946 status = ndr_pull(pull, NDR_IN, st);
947 if (!NT_STATUS_IS_OK(status)) {
948 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
949 "failed input validation pull - %s",
953 push = ndr_push_init_ctx(mem_ctx);
955 return NT_STATUS_NO_MEMORY;
958 status = ndr_push(push, NDR_IN, st);
959 if (!NT_STATUS_IS_OK(status)) {
960 return ndr_push_error(push, NDR_ERR_VALIDATE,
961 "failed input validation push - %s",
965 blob2 = ndr_push_blob(push);
967 if (!data_blob_equal(&blob, &blob2)) {
968 DEBUG(3,("original:\n"));
969 dump_data(3, blob.data, blob.length);
970 DEBUG(3,("secondary:\n"));
971 dump_data(3, blob2.data, blob2.length);
972 return ndr_push_error(push, NDR_ERR_VALIDATE,
973 "failed input validation data - %s",
981 this is a paranoid NDR input validator. For every packet we pull
982 from the wire we push it back again then pull and push it
983 again. Then we compare the raw NDR data for that to the NDR we
984 initially generated. If they don't match then we know we must have a
985 bug in either the pull or push side of our code
987 static NTSTATUS dcerpc_ndr_validate_out(struct dcerpc_pipe *p,
991 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
992 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
995 struct ndr_pull *pull;
996 struct ndr_push *push;
998 DATA_BLOB blob, blob2;
1000 st = talloc(mem_ctx, struct_size);
1002 return NT_STATUS_NO_MEMORY;
1004 memcpy(st, struct_ptr, struct_size);
1006 push = ndr_push_init_ctx(mem_ctx);
1008 return NT_STATUS_NO_MEMORY;
1011 status = ndr_push(push, NDR_OUT, struct_ptr);
1012 if (!NT_STATUS_IS_OK(status)) {
1013 return ndr_push_error(push, NDR_ERR_VALIDATE,
1014 "failed output validation push - %s",
1018 blob = ndr_push_blob(push);
1020 pull = ndr_pull_init_flags(p, &blob, mem_ctx);
1022 return NT_STATUS_NO_MEMORY;
1025 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
1026 status = ndr_pull(pull, NDR_OUT, st);
1027 if (!NT_STATUS_IS_OK(status)) {
1028 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
1029 "failed output validation pull - %s",
1033 push = ndr_push_init_ctx(mem_ctx);
1035 return NT_STATUS_NO_MEMORY;
1038 status = ndr_push(push, NDR_OUT, st);
1039 if (!NT_STATUS_IS_OK(status)) {
1040 return ndr_push_error(push, NDR_ERR_VALIDATE,
1041 "failed output validation push2 - %s",
1045 blob2 = ndr_push_blob(push);
1047 if (!data_blob_equal(&blob, &blob2)) {
1048 DEBUG(3,("original:\n"));
1049 dump_data(3, blob.data, blob.length);
1050 DEBUG(3,("secondary:\n"));
1051 dump_data(3, blob2.data, blob2.length);
1052 return ndr_push_error(push, NDR_ERR_VALIDATE,
1053 "failed output validation data - %s",
1057 return NT_STATUS_OK;
1062 send a rpc request with a given set of ndr helper functions
1064 call dcerpc_ndr_request_recv() to receive the answer
1066 struct rpc_request *dcerpc_ndr_request_send(struct dcerpc_pipe *p,
1068 TALLOC_CTX *mem_ctx,
1069 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1070 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1074 struct ndr_push *push;
1077 struct rpc_request *req;
1079 /* setup for a ndr_push_* call */
1080 push = ndr_push_init();
1085 if (p->flags & DCERPC_PUSH_BIGENDIAN) {
1086 push->flags |= LIBNDR_FLAG_BIGENDIAN;
1089 /* push the structure into a blob */
1090 status = ndr_push(push, NDR_IN, struct_ptr);
1091 if (!NT_STATUS_IS_OK(status)) {
1092 DEBUG(2,("Unable to ndr_push structure in dcerpc_ndr_request_send - %s\n",
1093 nt_errstr(status)));
1094 ndr_push_free(push);
1098 /* retrieve the blob */
1099 request = ndr_push_blob(push);
1101 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
1102 status = dcerpc_ndr_validate_in(p, mem_ctx, request, struct_size,
1103 ndr_push, ndr_pull);
1104 if (!NT_STATUS_IS_OK(status)) {
1105 DEBUG(2,("Validation failed in dcerpc_ndr_request_send - %s\n",
1106 nt_errstr(status)));
1107 ndr_push_free(push);
1112 DEBUG(10,("rpc request data:\n"));
1113 dump_data(10, request.data, request.length);
1115 /* make the actual dcerpc request */
1116 req = dcerpc_request_send(p, opnum, mem_ctx, &request);
1119 req->ndr.ndr_push = ndr_push;
1120 req->ndr.ndr_pull = ndr_pull;
1121 req->ndr.struct_ptr = struct_ptr;
1122 req->ndr.struct_size = struct_size;
1123 req->ndr.mem_ctx = mem_ctx;
1126 ndr_push_free(push);
1132 receive the answer from a dcerpc_ndr_request_send()
1134 NTSTATUS dcerpc_ndr_request_recv(struct rpc_request *req)
1136 struct dcerpc_pipe *p = req->p;
1139 struct ndr_pull *pull;
1140 struct rpc_request_ndr ndr = req->ndr;
1143 /* make sure the recv code doesn't free the request, as we
1144 need to grab the flags element before it is freed */
1145 talloc_increase_ref_count(req);
1147 status = dcerpc_request_recv(req, ndr.mem_ctx, &response);
1148 if (!NT_STATUS_IS_OK(status)) {
1155 /* prepare for ndr_pull_* */
1156 pull = ndr_pull_init_flags(p, &response, ndr.mem_ctx);
1158 return NT_STATUS_NO_MEMORY;
1161 if (flags & DCERPC_PULL_BIGENDIAN) {
1162 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
1165 DEBUG(10,("rpc reply data:\n"));
1166 dump_data(10, pull->data, pull->data_size);
1168 /* pull the structure from the blob */
1169 status = ndr.ndr_pull(pull, NDR_OUT, ndr.struct_ptr);
1170 if (!NT_STATUS_IS_OK(status)) {
1174 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
1175 status = dcerpc_ndr_validate_out(p, ndr.mem_ctx, ndr.struct_ptr, ndr.struct_size,
1176 ndr.ndr_push, ndr.ndr_pull);
1177 if (!NT_STATUS_IS_OK(status)) {
1182 if (pull->offset != pull->data_size) {
1183 DEBUG(0,("Warning! ignoring %d unread bytes in rpc packet!\n",
1184 pull->data_size - pull->offset));
1185 /* we used return NT_STATUS_INFO_LENGTH_MISMATCH here,
1186 but it turns out that early versions of NT
1187 (specifically NT3.1) add junk onto the end of rpc
1188 packets, so if we want to interoperate at all with
1189 those versions then we need to ignore this error */
1192 return NT_STATUS_OK;
1197 a useful helper function for synchronous rpc requests
1199 this can be used when you have ndr push/pull functions in the
1202 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
1204 TALLOC_CTX *mem_ctx,
1205 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
1206 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
1210 struct rpc_request *req;
1212 req = dcerpc_ndr_request_send(p, opnum, mem_ctx, ndr_push, ndr_pull, struct_ptr, struct_size);
1214 return NT_STATUS_NO_MEMORY;
1217 return dcerpc_ndr_request_recv(req);
1222 a useful function for retrieving the server name we connected to
1224 const char *dcerpc_server_name(struct dcerpc_pipe *p)
1226 if (!p->transport.peer_name) {
1229 return p->transport.peer_name(p);
1233 a useful function to get the auth_level
1236 uint32 dcerpc_auth_level(struct dcerpc_pipe *p)
1240 if (p->flags & DCERPC_SEAL) {
1241 auth_level = DCERPC_AUTH_LEVEL_PRIVACY;
1242 } else if (p->flags & DCERPC_SIGN) {
1243 auth_level = DCERPC_AUTH_LEVEL_INTEGRITY;
1245 auth_level = DCERPC_AUTH_LEVEL_NONE;