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 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 in response packet\n"));
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->payload.data,
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;