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 TALLOC_CTX *mem_ctx = talloc_init("dcerpc_tree");
35 p = talloc(mem_ctx, sizeof(*p));
37 talloc_destroy(mem_ctx);
41 p->reference_count = 0;
45 p->ntlmssp_state = NULL;
47 p->srv_max_xmit_frag = 0;
48 p->srv_max_recv_frag = 0;
53 /* close down a dcerpc over SMB pipe */
54 void dcerpc_pipe_close(struct dcerpc_pipe *p)
58 if (p->reference_count <= 0) {
59 if (p->ntlmssp_state) {
60 ntlmssp_end(&p->ntlmssp_state);
62 p->transport.shutdown_pipe(p);
63 talloc_destroy(p->mem_ctx);
69 parse a data blob into a dcerpc_packet structure. This handles both
70 input and output packets
72 static NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
73 struct dcerpc_packet *pkt)
77 ndr = ndr_pull_init_blob(blob, mem_ctx);
79 return NT_STATUS_NO_MEMORY;
82 return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
86 parse a possibly signed blob into a dcerpc request packet structure
88 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p,
89 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
90 struct dcerpc_packet *pkt)
94 struct dcerpc_auth auth;
97 /* non-signed packets are simpler */
98 if (!p->auth_info || !p->ntlmssp_state) {
99 return dcerpc_pull(blob, mem_ctx, pkt);
102 ndr = ndr_pull_init_blob(blob, mem_ctx);
104 return NT_STATUS_NO_MEMORY;
107 /* pull the basic packet */
108 status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
109 if (!NT_STATUS_IS_OK(status)) {
113 if (pkt->ptype != DCERPC_PKT_RESPONSE) {
117 auth_blob.length = 8 + pkt->auth_length;
119 /* check for a valid length */
120 if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
121 return NT_STATUS_INFO_LENGTH_MISMATCH;
125 pkt->u.response.stub_and_verifier.data +
126 pkt->u.response.stub_and_verifier.length - auth_blob.length;
127 pkt->u.response.stub_and_verifier.length -= auth_blob.length;
129 /* pull the auth structure */
130 ndr = ndr_pull_init_blob(&auth_blob, mem_ctx);
132 return NT_STATUS_NO_MEMORY;
135 status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
136 if (!NT_STATUS_IS_OK(status)) {
141 /* check signature or unseal the packet */
142 switch (p->auth_info->auth_level) {
143 case DCERPC_AUTH_LEVEL_PRIVACY:
144 status = ntlmssp_unseal_packet(p->ntlmssp_state,
145 pkt->u.response.stub_and_verifier.data,
146 pkt->u.response.stub_and_verifier.length,
150 case DCERPC_AUTH_LEVEL_INTEGRITY:
151 status = ntlmssp_check_packet(p->ntlmssp_state,
152 pkt->u.response.stub_and_verifier.data,
153 pkt->u.response.stub_and_verifier.length,
157 case DCERPC_AUTH_LEVEL_NONE:
161 status = NT_STATUS_INVALID_LEVEL;
165 /* remove the indicated amount of paddiing */
166 if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
167 return NT_STATUS_INFO_LENGTH_MISMATCH;
169 pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
176 push a dcerpc_packet into a blob. This handles both input and
179 static NTSTATUS dcerpc_push(struct dcerpc_pipe *p,
180 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
181 struct dcerpc_packet *pkt)
184 struct ndr_push *ndr;
186 ndr = ndr_push_init_ctx(mem_ctx);
188 return NT_STATUS_NO_MEMORY;
192 pkt->auth_length = p->auth_info->credentials.length;
194 pkt->auth_length = 0;
197 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
198 if (!NT_STATUS_IS_OK(status)) {
203 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS,
207 *blob = ndr_push_blob(ndr);
209 /* fill in the frag length */
210 SSVAL(blob->data, 8, blob->length);
217 push a dcerpc request packet into a blob, possibly signing it.
219 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p,
220 DATA_BLOB *blob, TALLOC_CTX *mem_ctx,
221 struct dcerpc_packet *pkt)
224 struct ndr_push *ndr;
226 /* non-signed packets are simpler */
227 if (!p->auth_info || !p->ntlmssp_state) {
228 return dcerpc_push(p, blob, mem_ctx, pkt);
231 ndr = ndr_push_init_ctx(mem_ctx);
233 return NT_STATUS_NO_MEMORY;
236 status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
237 if (!NT_STATUS_IS_OK(status)) {
241 /* pad to 8 byte multiple */
242 p->auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
243 ndr_push_zero(ndr, p->auth_info->auth_pad_length);
245 /* sign or seal the packet */
246 switch (p->auth_info->auth_level) {
247 case DCERPC_AUTH_LEVEL_PRIVACY:
248 status = ntlmssp_seal_packet(p->ntlmssp_state,
249 ndr->data + DCERPC_REQUEST_LENGTH,
250 ndr->offset - DCERPC_REQUEST_LENGTH,
251 &p->auth_info->credentials);
254 case DCERPC_AUTH_LEVEL_INTEGRITY:
255 status = ntlmssp_sign_packet(p->ntlmssp_state,
256 ndr->data + DCERPC_REQUEST_LENGTH,
257 ndr->offset - DCERPC_REQUEST_LENGTH,
258 &p->auth_info->credentials);
261 case DCERPC_AUTH_LEVEL_NONE:
262 p->auth_info->credentials = data_blob(NULL, 0);
266 status = NT_STATUS_INVALID_LEVEL;
270 if (!NT_STATUS_IS_OK(status)) {
274 /* add the auth verifier */
275 status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->auth_info);
276 if (!NT_STATUS_IS_OK(status)) {
280 /* extract the whole packet as a blob */
281 *blob = ndr_push_blob(ndr);
283 /* fill in the fragment length and auth_length, we can't fill
284 in these earlier as we don't know the signature length (it
285 could be variable length) */
286 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, blob->length);
287 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, p->auth_info->credentials.length);
289 data_blob_free(&p->auth_info->credentials);
296 fill in the fixed values in a dcerpc header
298 static void init_dcerpc_hdr(struct dcerpc_packet *pkt)
301 pkt->rpc_vers_minor = 0;
302 pkt->drep[0] = 0x10; /* Little endian */
310 perform a bind using the given syntax
312 the auth_info structure is updated with the reply authentication info
315 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p,
317 const struct dcerpc_syntax_id *syntax,
318 const struct dcerpc_syntax_id *transfer_syntax)
320 struct dcerpc_packet pkt;
323 struct dcerpc_syntax_id tsyntax;
325 init_dcerpc_hdr(&pkt);
327 pkt.ptype = DCERPC_PKT_BIND;
328 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
329 pkt.call_id = p->call_id;
332 pkt.u.bind.max_xmit_frag = 0x2000;
333 pkt.u.bind.max_recv_frag = 0x2000;
334 pkt.u.bind.assoc_group_id = 0;
335 pkt.u.bind.num_contexts = 1;
336 pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
337 if (!pkt.u.bind.ctx_list) {
338 return NT_STATUS_NO_MEMORY;
340 pkt.u.bind.ctx_list[0].context_id = 0;
341 pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
342 pkt.u.bind.ctx_list[0].abstract_syntax = *syntax;
343 tsyntax = *transfer_syntax;
344 pkt.u.bind.ctx_list[0].transfer_syntaxes = &tsyntax;
345 pkt.u.bind.auth_info = data_blob(NULL, 0);
347 /* construct the NDR form of the packet */
348 status = dcerpc_push(p, &blob, mem_ctx, &pkt);
349 if (!NT_STATUS_IS_OK(status)) {
353 /* send it on its way */
354 status = p->transport.full_request(p, mem_ctx, &blob, &blob);
355 if (!NT_STATUS_IS_OK(status)) {
359 /* unmarshall the NDR */
360 status = dcerpc_pull(&blob, mem_ctx, &pkt);
361 if (!NT_STATUS_IS_OK(status)) {
365 if ((pkt.ptype != DCERPC_PKT_BIND_ACK && pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
366 pkt.u.bind_ack.num_results == 0 ||
367 pkt.u.bind_ack.ctx_list[0].result != 0) {
368 status = NT_STATUS_UNSUCCESSFUL;
371 if (pkt.ptype != DCERPC_PKT_ALTER_ACK) {
372 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
373 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
376 /* the bind_ack might contain a reply set of credentials */
377 if (p->auth_info && pkt.u.bind_ack.auth_info.length) {
378 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
381 (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
388 perform a continued bind (and auth3)
390 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p,
393 struct dcerpc_packet pkt;
397 init_dcerpc_hdr(&pkt);
399 pkt.ptype = DCERPC_PKT_AUTH3;
400 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
401 pkt.call_id = p->call_id++;
404 pkt.u.auth.auth_info = data_blob(NULL, 0);
406 /* construct the NDR form of the packet */
407 status = dcerpc_push(p, &blob, mem_ctx, &pkt);
408 if (!NT_STATUS_IS_OK(status)) {
412 /* send it on its way */
413 status = p->transport.initial_request(p, mem_ctx, &blob);
414 if (!NT_STATUS_IS_OK(status)) {
422 /* perform a dcerpc bind, using the uuid as the key */
423 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p,
425 const char *uuid, unsigned version)
427 struct dcerpc_syntax_id syntax;
428 struct dcerpc_syntax_id transfer_syntax;
431 status = GUID_from_string(uuid, &syntax.uuid);
432 if (!NT_STATUS_IS_OK(status)) {
433 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
436 syntax.major_version = version;
437 syntax.minor_version = 0;
439 status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
440 if (!NT_STATUS_IS_OK(status)) {
443 transfer_syntax.major_version = NDR_GUID_VERSION;
444 transfer_syntax.minor_version = 0;
446 return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
450 perform a full request/response pair on a dcerpc pipe
452 NTSTATUS dcerpc_request(struct dcerpc_pipe *p,
455 DATA_BLOB *stub_data_in,
456 DATA_BLOB *stub_data_out)
459 struct dcerpc_packet pkt;
461 DATA_BLOB blob, payload;
462 uint32 remaining, chunk_size;
464 init_dcerpc_hdr(&pkt);
466 remaining = stub_data_in->length;
468 /* we can write a full max_recv_frag size, minus the dcerpc
469 request header size */
470 chunk_size = p->srv_max_recv_frag - DCERPC_REQUEST_LENGTH;
472 pkt.ptype = DCERPC_PKT_REQUEST;
473 pkt.call_id = p->call_id++;
475 pkt.u.request.alloc_hint = remaining;
476 pkt.u.request.context_id = 0;
477 pkt.u.request.opnum = opnum;
479 /* we send a series of pdus without waiting for a reply until
481 while (remaining > chunk_size) {
482 if (remaining == stub_data_in->length) {
483 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST;
488 pkt.u.request.stub_and_verifier.data = stub_data_in->data +
489 (stub_data_in->length - remaining);
490 pkt.u.request.stub_and_verifier.length = chunk_size;
492 status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
493 if (!NT_STATUS_IS_OK(status)) {
497 status = p->transport.initial_request(p, mem_ctx, &blob);
498 if (!NT_STATUS_IS_OK(status)) {
502 remaining -= chunk_size;
505 /* now we send a pdu with LAST_FRAG sent and get the first
507 if (remaining == stub_data_in->length) {
508 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
510 pkt.pfc_flags = DCERPC_PFC_FLAG_LAST;
512 pkt.u.request.stub_and_verifier.data = stub_data_in->data +
513 (stub_data_in->length - remaining);
514 pkt.u.request.stub_and_verifier.length = remaining;
516 status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
517 if (!NT_STATUS_IS_OK(status)) {
521 /* send the pdu and get the initial response pdu */
522 status = p->transport.full_request(p, mem_ctx, &blob, &blob);
523 if (!NT_STATUS_IS_OK(status)) {
527 status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
528 if (!NT_STATUS_IS_OK(status)) {
532 if (pkt.ptype == DCERPC_PKT_FAULT) {
533 p->last_fault_code = pkt.u.fault.status;
534 return NT_STATUS_NET_WRITE_FAULT;
537 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
538 return NT_STATUS_UNSUCCESSFUL;
541 if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
542 /* something is badly wrong! */
543 return NT_STATUS_UNSUCCESSFUL;
546 payload = pkt.u.response.stub_and_verifier;
548 /* continue receiving fragments */
549 while (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
552 status = p->transport.secondary_request(p, mem_ctx, &blob);
553 if (!NT_STATUS_IS_OK(status)) {
557 status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
558 if (!NT_STATUS_IS_OK(status)) {
562 if (pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
563 /* start of another packet!? */
564 return NT_STATUS_UNSUCCESSFUL;
567 if (pkt.ptype == DCERPC_PKT_FAULT) {
568 p->last_fault_code = pkt.u.fault.status;
569 return NT_STATUS_NET_WRITE_FAULT;
572 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
573 return NT_STATUS_UNSUCCESSFUL;
576 length = pkt.u.response.stub_and_verifier.length;
578 payload.data = talloc_realloc(mem_ctx,
580 payload.length + length);
582 return NT_STATUS_NO_MEMORY;
585 memcpy(payload.data + payload.length,
586 pkt.u.response.stub_and_verifier.data,
589 payload.length += length;
593 *stub_data_out = payload;
601 this is a paranoid NDR validator. For every packet we push onto the wire
602 we pull it back again, then push it again. Then we compare the raw NDR data
603 for that to the NDR we initially generated. If they don't match then we know
604 we must have a bug in either the pull or push side of our code
606 static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
609 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
610 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
613 struct ndr_pull *pull;
614 struct ndr_push *push;
618 st = talloc(mem_ctx, struct_size);
620 return NT_STATUS_NO_MEMORY;
623 pull = ndr_pull_init_blob(&blob, mem_ctx);
625 return NT_STATUS_NO_MEMORY;
628 status = ndr_pull(pull, NDR_IN, st);
629 if (!NT_STATUS_IS_OK(status)) {
630 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
631 "failed input validation pull - %s",
635 push = ndr_push_init_ctx(mem_ctx);
637 return NT_STATUS_NO_MEMORY;
640 status = ndr_push(push, NDR_IN, st);
641 if (!NT_STATUS_IS_OK(status)) {
642 return ndr_push_error(push, NDR_ERR_VALIDATE,
643 "failed input validation push - %s",
647 blob2 = ndr_push_blob(push);
649 if (!data_blob_equal(&blob, &blob2)) {
650 DEBUG(3,("original:\n"));
651 dump_data(3, blob.data, blob.length);
652 DEBUG(3,("secondary:\n"));
653 dump_data(3, blob2.data, blob2.length);
654 return ndr_push_error(push, NDR_ERR_VALIDATE,
655 "failed input validation data - %s",
663 this is a paranoid NDR input validator. For every packet we pull
664 from the wire we push it back again then pull and push it
665 again. Then we compare the raw NDR data for that to the NDR we
666 initially generated. If they don't match then we know we must have a
667 bug in either the pull or push side of our code
669 static NTSTATUS dcerpc_ndr_validate_out(TALLOC_CTX *mem_ctx,
672 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
673 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
676 struct ndr_pull *pull;
677 struct ndr_push *push;
679 DATA_BLOB blob, blob2;
681 st = talloc(mem_ctx, struct_size);
683 return NT_STATUS_NO_MEMORY;
685 memcpy(st, struct_ptr, struct_size);
687 push = ndr_push_init_ctx(mem_ctx);
689 return NT_STATUS_NO_MEMORY;
692 status = ndr_push(push, NDR_OUT, struct_ptr);
693 if (!NT_STATUS_IS_OK(status)) {
694 return ndr_push_error(push, NDR_ERR_VALIDATE,
695 "failed output validation push - %s",
699 blob = ndr_push_blob(push);
701 pull = ndr_pull_init_blob(&blob, mem_ctx);
703 return NT_STATUS_NO_MEMORY;
706 pull->flags |= LIBNDR_FLAG_REF_ALLOC;
707 status = ndr_pull(pull, NDR_OUT, st);
708 if (!NT_STATUS_IS_OK(status)) {
709 return ndr_pull_error(pull, NDR_ERR_VALIDATE,
710 "failed output validation pull - %s",
714 push = ndr_push_init_ctx(mem_ctx);
716 return NT_STATUS_NO_MEMORY;
719 status = ndr_push(push, NDR_OUT, st);
720 if (!NT_STATUS_IS_OK(status)) {
721 return ndr_push_error(push, NDR_ERR_VALIDATE,
722 "failed output validation push2 - %s",
726 blob2 = ndr_push_blob(push);
728 if (!data_blob_equal(&blob, &blob2)) {
729 DEBUG(3,("original:\n"));
730 dump_data(3, blob.data, blob.length);
731 DEBUG(3,("secondary:\n"));
732 dump_data(3, blob2.data, blob2.length);
733 return ndr_push_error(push, NDR_ERR_VALIDATE,
734 "failed output validation data - %s",
742 a useful helper function for synchronous rpc requests
744 this can be used when you have ndr push/pull functions in the
747 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
750 NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
751 NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
755 struct ndr_push *push;
756 struct ndr_pull *pull;
758 DATA_BLOB request, response;
760 /* setup for a ndr_push_* call */
761 push = ndr_push_init();
763 talloc_destroy(mem_ctx);
764 return NT_STATUS_NO_MEMORY;
767 /* push the structure into a blob */
768 status = ndr_push(push, NDR_IN, struct_ptr);
769 if (!NT_STATUS_IS_OK(status)) {
773 /* retrieve the blob */
774 request = ndr_push_blob(push);
776 if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
777 status = dcerpc_ndr_validate_in(mem_ctx, request, struct_size,
779 if (!NT_STATUS_IS_OK(status)) {
784 DEBUG(10,("rpc request data:\n"));
785 dump_data(10, request.data, request.length);
787 /* make the actual dcerpc request */
788 status = dcerpc_request(p, opnum, mem_ctx, &request, &response);
789 if (!NT_STATUS_IS_OK(status)) {
793 /* prepare for ndr_pull_* */
794 pull = ndr_pull_init_blob(&response, mem_ctx);
799 DEBUG(10,("rpc reply data:\n"));
800 dump_data(10, pull->data, pull->data_size);
802 /* pull the structure from the blob */
803 status = ndr_pull(pull, NDR_OUT, struct_ptr);
804 if (!NT_STATUS_IS_OK(status)) {
808 /* possibly check the packet signature */
811 if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
812 status = dcerpc_ndr_validate_out(mem_ctx, struct_ptr, struct_size,
814 if (!NT_STATUS_IS_OK(status)) {
819 if (pull->offset != pull->data_size) {
820 DEBUG(0,("Warning! %d unread bytes\n", pull->data_size - pull->offset));
821 status = NT_STATUS_INFO_LENGTH_MISMATCH;
832 a useful function for retrieving the server name we connected to
834 const char *dcerpc_server_name(struct dcerpc_pipe *p)
836 if (!p->transport.peer_name) {
839 return p->transport.peer_name(p);