s3:librpc: move NDR_PRINT_DEBUG() into the caller of dcerpc_pull_ncacn_packet()
[Samba.git] / source3 / rpc_client / cli_pipe.c
blob02af49fb035960413e315da72f6b9826e9fe58a8
1 /*
2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client routines
4 * Largely rewritten by Jeremy Allison 2005.
5 * Heavily modified by Simo Sorce 2010.
6 * Copyright Andrew Bartlett 2011.
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 3 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, see <http://www.gnu.org/licenses/>.
22 #include "includes.h"
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "librpc/gen_ndr/ndr_epmapper_c.h"
25 #include "../librpc/gen_ndr/ndr_dssetup.h"
26 #include "../libcli/auth/schannel.h"
27 #include "../libcli/auth/netlogon_creds_cli.h"
28 #include "auth_generic.h"
29 #include "librpc/gen_ndr/ndr_dcerpc.h"
30 #include "librpc/gen_ndr/ndr_netlogon_c.h"
31 #include "librpc/rpc/dcerpc.h"
32 #include "rpc_dce.h"
33 #include "cli_pipe.h"
34 #include "libsmb/libsmb.h"
35 #include "auth/gensec/gensec.h"
36 #include "auth/credentials/credentials.h"
37 #include "../libcli/smb/smbXcli_base.h"
39 #undef DBGC_CLASS
40 #define DBGC_CLASS DBGC_RPC_CLI
42 /********************************************************************
43 Pipe description for a DEBUG
44 ********************************************************************/
45 static const char *rpccli_pipe_txt(TALLOC_CTX *mem_ctx,
46 struct rpc_pipe_client *cli)
48 char *result = talloc_asprintf(mem_ctx, "host %s", cli->desthost);
49 if (result == NULL) {
50 return "pipe";
52 return result;
55 /********************************************************************
56 Rpc pipe call id.
57 ********************************************************************/
59 static uint32_t get_rpc_call_id(void)
61 static uint32_t call_id = 0;
62 return ++call_id;
65 /*******************************************************************
66 Use SMBreadX to get rest of one fragment's worth of rpc data.
67 Reads the whole size or give an error message
68 ********************************************************************/
70 struct rpc_read_state {
71 struct tevent_context *ev;
72 struct rpc_cli_transport *transport;
73 uint8_t *data;
74 size_t size;
75 size_t num_read;
78 static void rpc_read_done(struct tevent_req *subreq);
80 static struct tevent_req *rpc_read_send(TALLOC_CTX *mem_ctx,
81 struct tevent_context *ev,
82 struct rpc_cli_transport *transport,
83 uint8_t *data, size_t size)
85 struct tevent_req *req, *subreq;
86 struct rpc_read_state *state;
88 req = tevent_req_create(mem_ctx, &state, struct rpc_read_state);
89 if (req == NULL) {
90 return NULL;
92 state->ev = ev;
93 state->transport = transport;
94 state->data = data;
95 state->size = size;
96 state->num_read = 0;
98 DEBUG(5, ("rpc_read_send: data_to_read: %u\n", (unsigned int)size));
100 subreq = transport->read_send(state, ev, (uint8_t *)data, size,
101 transport->priv);
102 if (subreq == NULL) {
103 goto fail;
105 tevent_req_set_callback(subreq, rpc_read_done, req);
106 return req;
108 fail:
109 TALLOC_FREE(req);
110 return NULL;
113 static void rpc_read_done(struct tevent_req *subreq)
115 struct tevent_req *req = tevent_req_callback_data(
116 subreq, struct tevent_req);
117 struct rpc_read_state *state = tevent_req_data(
118 req, struct rpc_read_state);
119 NTSTATUS status;
120 ssize_t received;
122 status = state->transport->read_recv(subreq, &received);
123 TALLOC_FREE(subreq);
124 if (!NT_STATUS_IS_OK(status)) {
125 tevent_req_nterror(req, status);
126 return;
129 state->num_read += received;
130 if (state->num_read == state->size) {
131 tevent_req_done(req);
132 return;
135 subreq = state->transport->read_send(state, state->ev,
136 state->data + state->num_read,
137 state->size - state->num_read,
138 state->transport->priv);
139 if (tevent_req_nomem(subreq, req)) {
140 return;
142 tevent_req_set_callback(subreq, rpc_read_done, req);
145 static NTSTATUS rpc_read_recv(struct tevent_req *req)
147 return tevent_req_simple_recv_ntstatus(req);
150 struct rpc_write_state {
151 struct tevent_context *ev;
152 struct rpc_cli_transport *transport;
153 const uint8_t *data;
154 size_t size;
155 size_t num_written;
158 static void rpc_write_done(struct tevent_req *subreq);
160 static struct tevent_req *rpc_write_send(TALLOC_CTX *mem_ctx,
161 struct tevent_context *ev,
162 struct rpc_cli_transport *transport,
163 const uint8_t *data, size_t size)
165 struct tevent_req *req, *subreq;
166 struct rpc_write_state *state;
168 req = tevent_req_create(mem_ctx, &state, struct rpc_write_state);
169 if (req == NULL) {
170 return NULL;
172 state->ev = ev;
173 state->transport = transport;
174 state->data = data;
175 state->size = size;
176 state->num_written = 0;
178 DEBUG(5, ("rpc_write_send: data_to_write: %u\n", (unsigned int)size));
180 subreq = transport->write_send(state, ev, data, size, transport->priv);
181 if (subreq == NULL) {
182 goto fail;
184 tevent_req_set_callback(subreq, rpc_write_done, req);
185 return req;
186 fail:
187 TALLOC_FREE(req);
188 return NULL;
191 static void rpc_write_done(struct tevent_req *subreq)
193 struct tevent_req *req = tevent_req_callback_data(
194 subreq, struct tevent_req);
195 struct rpc_write_state *state = tevent_req_data(
196 req, struct rpc_write_state);
197 NTSTATUS status;
198 ssize_t written;
200 status = state->transport->write_recv(subreq, &written);
201 TALLOC_FREE(subreq);
202 if (!NT_STATUS_IS_OK(status)) {
203 tevent_req_nterror(req, status);
204 return;
207 state->num_written += written;
209 if (state->num_written == state->size) {
210 tevent_req_done(req);
211 return;
214 subreq = state->transport->write_send(state, state->ev,
215 state->data + state->num_written,
216 state->size - state->num_written,
217 state->transport->priv);
218 if (tevent_req_nomem(subreq, req)) {
219 return;
221 tevent_req_set_callback(subreq, rpc_write_done, req);
224 static NTSTATUS rpc_write_recv(struct tevent_req *req)
226 return tevent_req_simple_recv_ntstatus(req);
230 /****************************************************************************
231 Try and get a PDU's worth of data from current_pdu. If not, then read more
232 from the wire.
233 ****************************************************************************/
235 struct get_complete_frag_state {
236 struct tevent_context *ev;
237 struct rpc_pipe_client *cli;
238 uint16_t frag_len;
239 DATA_BLOB *pdu;
242 static void get_complete_frag_got_header(struct tevent_req *subreq);
243 static void get_complete_frag_got_rest(struct tevent_req *subreq);
245 static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
246 struct tevent_context *ev,
247 struct rpc_pipe_client *cli,
248 DATA_BLOB *pdu)
250 struct tevent_req *req, *subreq;
251 struct get_complete_frag_state *state;
252 size_t received;
253 NTSTATUS status;
255 req = tevent_req_create(mem_ctx, &state,
256 struct get_complete_frag_state);
257 if (req == NULL) {
258 return NULL;
260 state->ev = ev;
261 state->cli = cli;
262 state->frag_len = RPC_HEADER_LEN;
263 state->pdu = pdu;
265 received = pdu->length;
266 if (received < RPC_HEADER_LEN) {
267 if (!data_blob_realloc(mem_ctx, pdu, RPC_HEADER_LEN)) {
268 status = NT_STATUS_NO_MEMORY;
269 goto post_status;
271 subreq = rpc_read_send(state, state->ev,
272 state->cli->transport,
273 pdu->data + received,
274 RPC_HEADER_LEN - received);
275 if (subreq == NULL) {
276 status = NT_STATUS_NO_MEMORY;
277 goto post_status;
279 tevent_req_set_callback(subreq, get_complete_frag_got_header,
280 req);
281 return req;
284 state->frag_len = dcerpc_get_frag_length(pdu);
285 if (state->frag_len < RPC_HEADER_LEN) {
286 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
287 return tevent_req_post(req, ev);
291 * Ensure we have frag_len bytes of data.
293 if (received < state->frag_len) {
294 if (!data_blob_realloc(NULL, pdu, state->frag_len)) {
295 status = NT_STATUS_NO_MEMORY;
296 goto post_status;
298 subreq = rpc_read_send(state, state->ev,
299 state->cli->transport,
300 pdu->data + received,
301 state->frag_len - received);
302 if (subreq == NULL) {
303 status = NT_STATUS_NO_MEMORY;
304 goto post_status;
306 tevent_req_set_callback(subreq, get_complete_frag_got_rest,
307 req);
308 return req;
311 status = NT_STATUS_OK;
312 post_status:
313 if (NT_STATUS_IS_OK(status)) {
314 tevent_req_done(req);
315 } else {
316 tevent_req_nterror(req, status);
318 return tevent_req_post(req, ev);
321 static void get_complete_frag_got_header(struct tevent_req *subreq)
323 struct tevent_req *req = tevent_req_callback_data(
324 subreq, struct tevent_req);
325 struct get_complete_frag_state *state = tevent_req_data(
326 req, struct get_complete_frag_state);
327 NTSTATUS status;
329 status = rpc_read_recv(subreq);
330 TALLOC_FREE(subreq);
331 if (!NT_STATUS_IS_OK(status)) {
332 tevent_req_nterror(req, status);
333 return;
336 state->frag_len = dcerpc_get_frag_length(state->pdu);
337 if (state->frag_len < RPC_HEADER_LEN) {
338 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
339 return;
342 if (!data_blob_realloc(NULL, state->pdu, state->frag_len)) {
343 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
344 return;
348 * We're here in this piece of code because we've read exactly
349 * RPC_HEADER_LEN bytes into state->pdu.
352 subreq = rpc_read_send(state, state->ev, state->cli->transport,
353 state->pdu->data + RPC_HEADER_LEN,
354 state->frag_len - RPC_HEADER_LEN);
355 if (tevent_req_nomem(subreq, req)) {
356 return;
358 tevent_req_set_callback(subreq, get_complete_frag_got_rest, req);
361 static void get_complete_frag_got_rest(struct tevent_req *subreq)
363 struct tevent_req *req = tevent_req_callback_data(
364 subreq, struct tevent_req);
365 NTSTATUS status;
367 status = rpc_read_recv(subreq);
368 TALLOC_FREE(subreq);
369 if (!NT_STATUS_IS_OK(status)) {
370 tevent_req_nterror(req, status);
371 return;
373 tevent_req_done(req);
376 static NTSTATUS get_complete_frag_recv(struct tevent_req *req)
378 return tevent_req_simple_recv_ntstatus(req);
381 /****************************************************************************
382 Do basic authentication checks on an incoming pdu.
383 ****************************************************************************/
385 static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
386 struct rpc_pipe_client *cli,
387 struct ncacn_packet *pkt,
388 DATA_BLOB *pdu,
389 uint8_t expected_pkt_type,
390 uint32_t call_id,
391 DATA_BLOB *rdata,
392 DATA_BLOB *reply_pdu)
394 const struct dcerpc_response *r = NULL;
395 DATA_BLOB tmp_stub = data_blob_null;
396 NTSTATUS ret = NT_STATUS_OK;
399 * Point the return values at the real data including the RPC
400 * header. Just in case the caller wants it.
402 *rdata = *pdu;
404 if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
405 !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
407 * TODO: do we still need this hack which was introduced
408 * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0.
410 * I don't even know what AS/U might be...
412 DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
413 "fragment first/last ON.\n"));
414 pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
417 /* Ensure we have the correct type. */
418 switch (pkt->ptype) {
419 case DCERPC_PKT_BIND_NAK:
420 DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
421 rpccli_pipe_txt(talloc_tos(), cli)));
423 ret = dcerpc_verify_ncacn_packet_header(pkt,
424 DCERPC_PKT_BIND_NAK,
425 0, /* max_auth_info */
426 DCERPC_PFC_FLAG_FIRST |
427 DCERPC_PFC_FLAG_LAST,
428 0); /* optional flags */
429 if (!NT_STATUS_IS_OK(ret)) {
430 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
431 "RPC packet type - %u, expected %u: %s\n",
432 rpccli_pipe_txt(talloc_tos(), cli),
433 pkt->ptype, expected_pkt_type,
434 nt_errstr(ret)));
435 NDR_PRINT_DEBUG(ncacn_packet, pkt);
436 return ret;
439 /* Use this for now... */
440 return NT_STATUS_NETWORK_ACCESS_DENIED;
442 case DCERPC_PKT_BIND_ACK:
443 ret = dcerpc_verify_ncacn_packet_header(pkt,
444 expected_pkt_type,
445 pkt->u.bind_ack.auth_info.length,
446 DCERPC_PFC_FLAG_FIRST |
447 DCERPC_PFC_FLAG_LAST,
448 DCERPC_PFC_FLAG_CONC_MPX |
449 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
450 if (!NT_STATUS_IS_OK(ret)) {
451 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
452 "RPC packet type - %u, expected %u: %s\n",
453 rpccli_pipe_txt(talloc_tos(), cli),
454 pkt->ptype, expected_pkt_type,
455 nt_errstr(ret)));
456 NDR_PRINT_DEBUG(ncacn_packet, pkt);
457 return ret;
460 break;
462 case DCERPC_PKT_ALTER_RESP:
463 ret = dcerpc_verify_ncacn_packet_header(pkt,
464 expected_pkt_type,
465 pkt->u.alter_resp.auth_info.length,
466 DCERPC_PFC_FLAG_FIRST |
467 DCERPC_PFC_FLAG_LAST,
468 DCERPC_PFC_FLAG_CONC_MPX |
469 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
470 if (!NT_STATUS_IS_OK(ret)) {
471 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
472 "RPC packet type - %u, expected %u: %s\n",
473 rpccli_pipe_txt(talloc_tos(), cli),
474 pkt->ptype, expected_pkt_type,
475 nt_errstr(ret)));
476 NDR_PRINT_DEBUG(ncacn_packet, pkt);
477 return ret;
480 break;
482 case DCERPC_PKT_RESPONSE:
484 r = &pkt->u.response;
486 ret = dcerpc_verify_ncacn_packet_header(pkt,
487 expected_pkt_type,
488 r->stub_and_verifier.length,
489 0, /* required_flags */
490 DCERPC_PFC_FLAG_FIRST |
491 DCERPC_PFC_FLAG_LAST);
492 if (!NT_STATUS_IS_OK(ret)) {
493 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
494 "RPC packet type - %u, expected %u: %s\n",
495 rpccli_pipe_txt(talloc_tos(), cli),
496 pkt->ptype, expected_pkt_type,
497 nt_errstr(ret)));
498 NDR_PRINT_DEBUG(ncacn_packet, pkt);
499 return ret;
502 tmp_stub.data = r->stub_and_verifier.data;
503 tmp_stub.length = r->stub_and_verifier.length;
505 /* Here's where we deal with incoming sign/seal. */
506 ret = dcerpc_check_auth(cli->auth, pkt,
507 &tmp_stub,
508 DCERPC_RESPONSE_LENGTH,
509 pdu);
510 if (!NT_STATUS_IS_OK(ret)) {
511 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
512 "RPC packet type - %u, expected %u: %s\n",
513 rpccli_pipe_txt(talloc_tos(), cli),
514 pkt->ptype, expected_pkt_type,
515 nt_errstr(ret)));
516 NDR_PRINT_DEBUG(ncacn_packet, pkt);
517 return ret;
520 /* Point the return values at the NDR data. */
521 *rdata = tmp_stub;
523 DEBUG(10, ("Got pdu len %lu, data_len %lu\n",
524 (long unsigned int)pdu->length,
525 (long unsigned int)rdata->length));
528 * If this is the first reply, and the allocation hint is
529 * reasonable, try and set up the reply_pdu DATA_BLOB to the
530 * correct size.
533 if ((reply_pdu->length == 0) &&
534 r->alloc_hint && (r->alloc_hint < 15*1024*1024)) {
535 if (!data_blob_realloc(mem_ctx, reply_pdu,
536 r->alloc_hint)) {
537 DEBUG(0, ("reply alloc hint %d too "
538 "large to allocate\n",
539 (int)r->alloc_hint));
540 return NT_STATUS_NO_MEMORY;
544 break;
546 case DCERPC_PKT_FAULT:
548 ret = dcerpc_verify_ncacn_packet_header(pkt,
549 DCERPC_PKT_FAULT,
550 0, /* max_auth_info */
551 DCERPC_PFC_FLAG_FIRST |
552 DCERPC_PFC_FLAG_LAST,
553 DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
554 if (!NT_STATUS_IS_OK(ret)) {
555 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
556 "RPC packet type - %u, expected %u: %s\n",
557 rpccli_pipe_txt(talloc_tos(), cli),
558 pkt->ptype, expected_pkt_type,
559 nt_errstr(ret)));
560 NDR_PRINT_DEBUG(ncacn_packet, pkt);
561 return ret;
564 DEBUG(1, (__location__ ": RPC fault code %s received "
565 "from %s!\n",
566 dcerpc_errstr(talloc_tos(),
567 pkt->u.fault.status),
568 rpccli_pipe_txt(talloc_tos(), cli)));
570 return dcerpc_fault_to_nt_status(pkt->u.fault.status);
572 default:
573 DEBUG(0, (__location__ "Unknown packet type %u received "
574 "from %s!\n",
575 (unsigned int)pkt->ptype,
576 rpccli_pipe_txt(talloc_tos(), cli)));
577 return NT_STATUS_RPC_PROTOCOL_ERROR;
581 if (pkt->call_id != call_id) {
582 DEBUG(3, (__location__ ": Connection to %s got an unexpected "
583 "RPC call_id - %u, not %u\n",
584 rpccli_pipe_txt(talloc_tos(), cli),
585 pkt->call_id, call_id));
586 return NT_STATUS_RPC_PROTOCOL_ERROR;
589 return NT_STATUS_OK;
592 /****************************************************************************
593 Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
594 ****************************************************************************/
596 struct cli_api_pipe_state {
597 struct tevent_context *ev;
598 struct rpc_cli_transport *transport;
599 uint8_t *rdata;
600 uint32_t rdata_len;
603 static void cli_api_pipe_trans_done(struct tevent_req *subreq);
604 static void cli_api_pipe_write_done(struct tevent_req *subreq);
605 static void cli_api_pipe_read_done(struct tevent_req *subreq);
607 static struct tevent_req *cli_api_pipe_send(TALLOC_CTX *mem_ctx,
608 struct tevent_context *ev,
609 struct rpc_cli_transport *transport,
610 uint8_t *data, size_t data_len,
611 uint32_t max_rdata_len)
613 struct tevent_req *req, *subreq;
614 struct cli_api_pipe_state *state;
615 NTSTATUS status;
617 req = tevent_req_create(mem_ctx, &state, struct cli_api_pipe_state);
618 if (req == NULL) {
619 return NULL;
621 state->ev = ev;
622 state->transport = transport;
624 if (max_rdata_len < RPC_HEADER_LEN) {
626 * For a RPC reply we always need at least RPC_HEADER_LEN
627 * bytes. We check this here because we will receive
628 * RPC_HEADER_LEN bytes in cli_trans_sock_send_done.
630 status = NT_STATUS_INVALID_PARAMETER;
631 goto post_status;
634 if (transport->trans_send != NULL) {
635 subreq = transport->trans_send(state, ev, data, data_len,
636 max_rdata_len, transport->priv);
637 if (subreq == NULL) {
638 goto fail;
640 tevent_req_set_callback(subreq, cli_api_pipe_trans_done, req);
641 return req;
645 * If the transport does not provide a "trans" routine, i.e. for
646 * example the ncacn_ip_tcp transport, do the write/read step here.
649 subreq = rpc_write_send(state, ev, transport, data, data_len);
650 if (subreq == NULL) {
651 goto fail;
653 tevent_req_set_callback(subreq, cli_api_pipe_write_done, req);
654 return req;
656 post_status:
657 tevent_req_nterror(req, status);
658 return tevent_req_post(req, ev);
659 fail:
660 TALLOC_FREE(req);
661 return NULL;
664 static void cli_api_pipe_trans_done(struct tevent_req *subreq)
666 struct tevent_req *req = tevent_req_callback_data(
667 subreq, struct tevent_req);
668 struct cli_api_pipe_state *state = tevent_req_data(
669 req, struct cli_api_pipe_state);
670 NTSTATUS status;
672 status = state->transport->trans_recv(subreq, state, &state->rdata,
673 &state->rdata_len);
674 TALLOC_FREE(subreq);
675 if (!NT_STATUS_IS_OK(status)) {
676 tevent_req_nterror(req, status);
677 return;
679 tevent_req_done(req);
682 static void cli_api_pipe_write_done(struct tevent_req *subreq)
684 struct tevent_req *req = tevent_req_callback_data(
685 subreq, struct tevent_req);
686 struct cli_api_pipe_state *state = tevent_req_data(
687 req, struct cli_api_pipe_state);
688 NTSTATUS status;
690 status = rpc_write_recv(subreq);
691 TALLOC_FREE(subreq);
692 if (!NT_STATUS_IS_OK(status)) {
693 tevent_req_nterror(req, status);
694 return;
697 state->rdata = talloc_array(state, uint8_t, RPC_HEADER_LEN);
698 if (tevent_req_nomem(state->rdata, req)) {
699 return;
703 * We don't need to use rpc_read_send here, the upper layer will cope
704 * with a short read, transport->trans_send could also return less
705 * than state->max_rdata_len.
707 subreq = state->transport->read_send(state, state->ev, state->rdata,
708 RPC_HEADER_LEN,
709 state->transport->priv);
710 if (tevent_req_nomem(subreq, req)) {
711 return;
713 tevent_req_set_callback(subreq, cli_api_pipe_read_done, req);
716 static void cli_api_pipe_read_done(struct tevent_req *subreq)
718 struct tevent_req *req = tevent_req_callback_data(
719 subreq, struct tevent_req);
720 struct cli_api_pipe_state *state = tevent_req_data(
721 req, struct cli_api_pipe_state);
722 NTSTATUS status;
723 ssize_t received;
725 status = state->transport->read_recv(subreq, &received);
726 TALLOC_FREE(subreq);
727 if (!NT_STATUS_IS_OK(status)) {
728 tevent_req_nterror(req, status);
729 return;
731 state->rdata_len = received;
732 tevent_req_done(req);
735 static NTSTATUS cli_api_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
736 uint8_t **prdata, uint32_t *prdata_len)
738 struct cli_api_pipe_state *state = tevent_req_data(
739 req, struct cli_api_pipe_state);
740 NTSTATUS status;
742 if (tevent_req_is_nterror(req, &status)) {
743 return status;
746 *prdata = talloc_move(mem_ctx, &state->rdata);
747 *prdata_len = state->rdata_len;
748 return NT_STATUS_OK;
751 /****************************************************************************
752 Send data on an rpc pipe via trans. The data must be the last
753 pdu fragment of an NDR data stream.
755 Receive response data from an rpc pipe, which may be large...
757 Read the first fragment: unfortunately have to use SMBtrans for the first
758 bit, then SMBreadX for subsequent bits.
760 If first fragment received also wasn't the last fragment, continue
761 getting fragments until we _do_ receive the last fragment.
763 Request/Response PDU's look like the following...
765 |<------------------PDU len----------------------------------------------->|
766 |<-HDR_LEN-->|<--REQ LEN------>|.............|<-AUTH_HDRLEN->|<-AUTH_LEN-->|
768 +------------+-----------------+-------------+---------------+-------------+
769 | RPC HEADER | REQ/RESP HEADER | DATA ...... | AUTH_HDR | AUTH DATA |
770 +------------+-----------------+-------------+---------------+-------------+
772 Where the presence of the AUTH_HDR and AUTH DATA are dependent on the
773 signing & sealing being negotiated.
775 ****************************************************************************/
777 struct rpc_api_pipe_state {
778 struct tevent_context *ev;
779 struct rpc_pipe_client *cli;
780 uint8_t expected_pkt_type;
781 uint32_t call_id;
783 DATA_BLOB incoming_frag;
784 struct ncacn_packet *pkt;
786 /* Incoming reply */
787 DATA_BLOB reply_pdu;
788 size_t reply_pdu_offset;
789 uint8_t endianess;
792 static void rpc_api_pipe_trans_done(struct tevent_req *subreq);
793 static void rpc_api_pipe_got_pdu(struct tevent_req *subreq);
794 static void rpc_api_pipe_auth3_done(struct tevent_req *subreq);
796 static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
797 struct tevent_context *ev,
798 struct rpc_pipe_client *cli,
799 DATA_BLOB *data, /* Outgoing PDU */
800 uint8_t expected_pkt_type,
801 uint32_t call_id)
803 struct tevent_req *req, *subreq;
804 struct rpc_api_pipe_state *state;
805 uint16_t max_recv_frag;
806 NTSTATUS status;
808 req = tevent_req_create(mem_ctx, &state, struct rpc_api_pipe_state);
809 if (req == NULL) {
810 return NULL;
812 state->ev = ev;
813 state->cli = cli;
814 state->expected_pkt_type = expected_pkt_type;
815 state->call_id = call_id;
816 state->endianess = DCERPC_DREP_LE;
819 * Ensure we're not sending too much.
821 if (data->length > cli->max_xmit_frag) {
822 status = NT_STATUS_INVALID_PARAMETER;
823 goto post_status;
826 DEBUG(5,("rpc_api_pipe: %s\n", rpccli_pipe_txt(talloc_tos(), cli)));
828 if (state->expected_pkt_type == DCERPC_PKT_AUTH3) {
829 subreq = rpc_write_send(state, ev, cli->transport,
830 data->data, data->length);
831 if (subreq == NULL) {
832 goto fail;
834 tevent_req_set_callback(subreq, rpc_api_pipe_auth3_done, req);
835 return req;
838 /* get the header first, then fetch the rest once we have
839 * the frag_length available */
840 max_recv_frag = RPC_HEADER_LEN;
842 subreq = cli_api_pipe_send(state, ev, cli->transport,
843 data->data, data->length, max_recv_frag);
844 if (subreq == NULL) {
845 goto fail;
847 tevent_req_set_callback(subreq, rpc_api_pipe_trans_done, req);
848 return req;
850 post_status:
851 tevent_req_nterror(req, status);
852 return tevent_req_post(req, ev);
853 fail:
854 TALLOC_FREE(req);
855 return NULL;
858 static void rpc_api_pipe_auth3_done(struct tevent_req *subreq)
860 struct tevent_req *req =
861 tevent_req_callback_data(subreq,
862 struct tevent_req);
863 NTSTATUS status;
865 status = rpc_write_recv(subreq);
866 TALLOC_FREE(subreq);
867 if (!NT_STATUS_IS_OK(status)) {
868 tevent_req_nterror(req, status);
869 return;
872 tevent_req_done(req);
875 static void rpc_api_pipe_trans_done(struct tevent_req *subreq)
877 struct tevent_req *req = tevent_req_callback_data(
878 subreq, struct tevent_req);
879 struct rpc_api_pipe_state *state = tevent_req_data(
880 req, struct rpc_api_pipe_state);
881 NTSTATUS status;
882 uint8_t *rdata = NULL;
883 uint32_t rdata_len = 0;
885 status = cli_api_pipe_recv(subreq, state, &rdata, &rdata_len);
886 TALLOC_FREE(subreq);
887 if (!NT_STATUS_IS_OK(status)) {
888 DEBUG(5, ("cli_api_pipe failed: %s\n", nt_errstr(status)));
889 tevent_req_nterror(req, status);
890 return;
893 if (rdata == NULL) {
894 DEBUG(3,("rpc_api_pipe: %s failed to return data.\n",
895 rpccli_pipe_txt(talloc_tos(), state->cli)));
896 tevent_req_done(req);
897 return;
901 * Move data on state->incoming_frag.
903 state->incoming_frag.data = talloc_move(state, &rdata);
904 state->incoming_frag.length = rdata_len;
905 if (!state->incoming_frag.data) {
906 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
907 return;
910 /* Ensure we have enough data for a pdu. */
911 subreq = get_complete_frag_send(state, state->ev, state->cli,
912 &state->incoming_frag);
913 if (tevent_req_nomem(subreq, req)) {
914 return;
916 tevent_req_set_callback(subreq, rpc_api_pipe_got_pdu, req);
919 static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
921 struct tevent_req *req = tevent_req_callback_data(
922 subreq, struct tevent_req);
923 struct rpc_api_pipe_state *state = tevent_req_data(
924 req, struct rpc_api_pipe_state);
925 NTSTATUS status;
926 DATA_BLOB rdata = data_blob_null;
928 status = get_complete_frag_recv(subreq);
929 TALLOC_FREE(subreq);
930 if (!NT_STATUS_IS_OK(status)) {
931 DEBUG(5, ("get_complete_frag failed: %s\n",
932 nt_errstr(status)));
933 tevent_req_nterror(req, status);
934 return;
937 state->pkt = talloc(state, struct ncacn_packet);
938 if (!state->pkt) {
940 * TODO: do a real async disconnect ...
942 * For now do it sync...
944 TALLOC_FREE(state->cli->transport);
945 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
946 return;
949 status = dcerpc_pull_ncacn_packet(state->pkt,
950 &state->incoming_frag,
951 state->pkt);
952 if (!NT_STATUS_IS_OK(status)) {
954 * TODO: do a real async disconnect ...
956 * For now do it sync...
958 TALLOC_FREE(state->cli->transport);
959 tevent_req_nterror(req, status);
960 return;
963 if (DEBUGLEVEL >= 10) {
964 NDR_PRINT_DEBUG(ncacn_packet, state->pkt);
967 status = cli_pipe_validate_current_pdu(state,
968 state->cli, state->pkt,
969 &state->incoming_frag,
970 state->expected_pkt_type,
971 state->call_id,
972 &rdata,
973 &state->reply_pdu);
975 DEBUG(10,("rpc_api_pipe: got frag len of %u at offset %u: %s\n",
976 (unsigned)state->incoming_frag.length,
977 (unsigned)state->reply_pdu_offset,
978 nt_errstr(status)));
980 if (state->pkt->ptype != DCERPC_PKT_FAULT && !NT_STATUS_IS_OK(status)) {
982 * TODO: do a real async disconnect ...
984 * For now do it sync...
986 TALLOC_FREE(state->cli->transport);
987 } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
989 * TODO: do a real async disconnect ...
991 * For now do it sync...
993 TALLOC_FREE(state->cli->transport);
994 } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
996 * TODO: do a real async disconnect ...
998 * For now do it sync...
1000 TALLOC_FREE(state->cli->transport);
1002 if (!NT_STATUS_IS_OK(status)) {
1003 tevent_req_nterror(req, status);
1004 return;
1007 if ((state->pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)
1008 && (state->pkt->drep[0] != DCERPC_DREP_LE)) {
1010 * Set the data type correctly for big-endian data on the
1011 * first packet.
1013 DEBUG(10,("rpc_api_pipe: On %s PDU data format is "
1014 "big-endian.\n",
1015 rpccli_pipe_txt(talloc_tos(), state->cli)));
1016 state->endianess = 0x00; /* BIG ENDIAN */
1019 * Check endianness on subsequent packets.
1021 if (state->endianess != state->pkt->drep[0]) {
1022 DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to "
1023 "%s\n",
1024 state->endianess?"little":"big",
1025 state->pkt->drep[0]?"little":"big"));
1027 * TODO: do a real async disconnect ...
1029 * For now do it sync...
1031 TALLOC_FREE(state->cli->transport);
1032 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1033 return;
1036 if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) {
1038 * TODO: do a real async disconnect ...
1040 * For now do it sync...
1042 TALLOC_FREE(state->cli->transport);
1043 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1044 return;
1047 /* Now copy the data portion out of the pdu into rbuf. */
1048 if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) {
1049 if (!data_blob_realloc(NULL, &state->reply_pdu,
1050 state->reply_pdu_offset + rdata.length)) {
1052 * TODO: do a real async disconnect ...
1054 * For now do it sync...
1056 TALLOC_FREE(state->cli->transport);
1057 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1058 return;
1062 memcpy(state->reply_pdu.data + state->reply_pdu_offset,
1063 rdata.data, rdata.length);
1064 state->reply_pdu_offset += rdata.length;
1066 /* reset state->incoming_frag, there is no need to free it,
1067 * it will be reallocated to the right size the next time
1068 * it is used */
1069 state->incoming_frag.length = 0;
1071 if (state->pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1072 /* make sure the pdu length is right now that we
1073 * have all the data available (alloc hint may
1074 * have allocated more than was actually used) */
1075 state->reply_pdu.length = state->reply_pdu_offset;
1076 DEBUG(10,("rpc_api_pipe: %s returned %u bytes.\n",
1077 rpccli_pipe_txt(talloc_tos(), state->cli),
1078 (unsigned)state->reply_pdu.length));
1079 tevent_req_done(req);
1080 return;
1083 subreq = get_complete_frag_send(state, state->ev, state->cli,
1084 &state->incoming_frag);
1085 if (subreq == NULL) {
1087 * TODO: do a real async disconnect ...
1089 * For now do it sync...
1091 TALLOC_FREE(state->cli->transport);
1093 if (tevent_req_nomem(subreq, req)) {
1094 return;
1096 tevent_req_set_callback(subreq, rpc_api_pipe_got_pdu, req);
1099 static NTSTATUS rpc_api_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1100 struct ncacn_packet **pkt,
1101 DATA_BLOB *reply_pdu)
1103 struct rpc_api_pipe_state *state = tevent_req_data(
1104 req, struct rpc_api_pipe_state);
1105 NTSTATUS status;
1107 if (tevent_req_is_nterror(req, &status)) {
1108 return status;
1111 /* return data to caller and assign it ownership of memory */
1112 if (reply_pdu) {
1113 reply_pdu->data = talloc_move(mem_ctx, &state->reply_pdu.data);
1114 reply_pdu->length = state->reply_pdu.length;
1115 state->reply_pdu.length = 0;
1116 } else {
1117 data_blob_free(&state->reply_pdu);
1120 if (pkt) {
1121 *pkt = talloc_steal(mem_ctx, state->pkt);
1124 return NT_STATUS_OK;
1127 /*******************************************************************
1128 Creates NTLMSSP auth bind.
1129 ********************************************************************/
1131 static NTSTATUS create_generic_auth_rpc_bind_req(struct rpc_pipe_client *cli,
1132 TALLOC_CTX *mem_ctx,
1133 DATA_BLOB *auth_token,
1134 bool *client_hdr_signing)
1136 struct gensec_security *gensec_security;
1137 DATA_BLOB null_blob = data_blob_null;
1138 NTSTATUS status;
1140 gensec_security = cli->auth->auth_ctx;
1142 DEBUG(5, ("create_generic_auth_rpc_bind_req: generate first token\n"));
1143 status = gensec_update(gensec_security, mem_ctx, null_blob, auth_token);
1145 if (!NT_STATUS_IS_OK(status) &&
1146 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
1148 return status;
1151 if (client_hdr_signing == NULL) {
1152 return status;
1155 if (cli->auth->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
1156 *client_hdr_signing = false;
1157 return status;
1160 *client_hdr_signing = gensec_have_feature(gensec_security,
1161 GENSEC_FEATURE_SIGN_PKT_HEADER);
1163 return status;
1166 /*******************************************************************
1167 Creates the internals of a DCE/RPC bind request or alter context PDU.
1168 ********************************************************************/
1170 static NTSTATUS create_bind_or_alt_ctx_internal(TALLOC_CTX *mem_ctx,
1171 enum dcerpc_pkt_type ptype,
1172 uint32_t rpc_call_id,
1173 const struct ndr_syntax_id *abstract,
1174 const struct ndr_syntax_id *transfer,
1175 const DATA_BLOB *auth_info,
1176 bool client_hdr_signing,
1177 DATA_BLOB *blob)
1179 uint16_t auth_len = auth_info->length;
1180 NTSTATUS status;
1181 union dcerpc_payload u;
1182 struct dcerpc_ctx_list ctx_list;
1183 uint8_t pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1185 if (auth_len) {
1186 auth_len -= DCERPC_AUTH_TRAILER_LENGTH;
1189 if (client_hdr_signing) {
1190 pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1193 ctx_list.context_id = 0;
1194 ctx_list.num_transfer_syntaxes = 1;
1195 ctx_list.abstract_syntax = *abstract;
1196 ctx_list.transfer_syntaxes = (struct ndr_syntax_id *)discard_const(transfer);
1198 u.bind.max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
1199 u.bind.max_recv_frag = RPC_MAX_PDU_FRAG_LEN;
1200 u.bind.assoc_group_id = 0x0;
1201 u.bind.num_contexts = 1;
1202 u.bind.ctx_list = &ctx_list;
1203 u.bind.auth_info = *auth_info;
1205 status = dcerpc_push_ncacn_packet(mem_ctx,
1206 ptype, pfc_flags,
1207 auth_len,
1208 rpc_call_id,
1210 blob);
1211 if (!NT_STATUS_IS_OK(status)) {
1212 DEBUG(0, ("Failed to marshall bind/alter ncacn_packet.\n"));
1213 return status;
1216 return NT_STATUS_OK;
1219 /*******************************************************************
1220 Creates a DCE/RPC bind request.
1221 ********************************************************************/
1223 static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx,
1224 struct rpc_pipe_client *cli,
1225 struct pipe_auth_data *auth,
1226 uint32_t rpc_call_id,
1227 const struct ndr_syntax_id *abstract,
1228 const struct ndr_syntax_id *transfer,
1229 DATA_BLOB *rpc_out)
1231 DATA_BLOB auth_token = data_blob_null;
1232 DATA_BLOB auth_info = data_blob_null;
1233 NTSTATUS ret = NT_STATUS_OK;
1235 switch (auth->auth_type) {
1236 case DCERPC_AUTH_TYPE_NONE:
1237 break;
1239 default:
1240 ret = create_generic_auth_rpc_bind_req(cli, mem_ctx,
1241 &auth_token,
1242 &auth->client_hdr_signing);
1244 if (!NT_STATUS_IS_OK(ret) &&
1245 !NT_STATUS_EQUAL(ret, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1246 return ret;
1248 break;
1251 if (auth_token.length != 0) {
1252 ret = dcerpc_push_dcerpc_auth(cli,
1253 auth->auth_type,
1254 auth->auth_level,
1255 0, /* auth_pad_length */
1256 auth->auth_context_id,
1257 &auth_token,
1258 &auth_info);
1259 if (!NT_STATUS_IS_OK(ret)) {
1260 return ret;
1262 data_blob_free(&auth_token);
1265 ret = create_bind_or_alt_ctx_internal(mem_ctx,
1266 DCERPC_PKT_BIND,
1267 rpc_call_id,
1268 abstract,
1269 transfer,
1270 &auth_info,
1271 auth->client_hdr_signing,
1272 rpc_out);
1273 return ret;
1276 /*******************************************************************
1277 External interface.
1278 Does an rpc request on a pipe. Incoming data is NDR encoded in in_data.
1279 Reply is NDR encoded in out_data. Splits the data stream into RPC PDU's
1280 and deals with signing/sealing details.
1281 ********************************************************************/
1283 struct rpc_api_pipe_req_state {
1284 struct tevent_context *ev;
1285 struct rpc_pipe_client *cli;
1286 uint8_t op_num;
1287 uint32_t call_id;
1288 const DATA_BLOB *req_data;
1289 uint32_t req_data_sent;
1290 DATA_BLOB req_trailer;
1291 uint32_t req_trailer_sent;
1292 bool verify_bitmask1;
1293 bool verify_pcontext;
1294 DATA_BLOB rpc_out;
1295 DATA_BLOB reply_pdu;
1298 static void rpc_api_pipe_req_write_done(struct tevent_req *subreq);
1299 static void rpc_api_pipe_req_done(struct tevent_req *subreq);
1300 static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state);
1301 static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
1302 bool *is_last_frag);
1304 static struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
1305 struct tevent_context *ev,
1306 struct rpc_pipe_client *cli,
1307 uint8_t op_num,
1308 const DATA_BLOB *req_data)
1310 struct tevent_req *req, *subreq;
1311 struct rpc_api_pipe_req_state *state;
1312 NTSTATUS status;
1313 bool is_last_frag;
1315 req = tevent_req_create(mem_ctx, &state,
1316 struct rpc_api_pipe_req_state);
1317 if (req == NULL) {
1318 return NULL;
1320 state->ev = ev;
1321 state->cli = cli;
1322 state->op_num = op_num;
1323 state->req_data = req_data;
1324 state->req_data_sent = 0;
1325 state->call_id = get_rpc_call_id();
1326 state->reply_pdu = data_blob_null;
1327 state->rpc_out = data_blob_null;
1329 if (cli->max_xmit_frag < DCERPC_REQUEST_LENGTH
1330 + RPC_MAX_SIGN_SIZE) {
1331 /* Server is screwed up ! */
1332 status = NT_STATUS_INVALID_PARAMETER;
1333 goto post_status;
1336 status = prepare_verification_trailer(state);
1337 if (!NT_STATUS_IS_OK(status)) {
1338 goto post_status;
1341 status = prepare_next_frag(state, &is_last_frag);
1342 if (!NT_STATUS_IS_OK(status)) {
1343 goto post_status;
1346 if (is_last_frag) {
1347 subreq = rpc_api_pipe_send(state, ev, state->cli,
1348 &state->rpc_out,
1349 DCERPC_PKT_RESPONSE,
1350 state->call_id);
1351 if (subreq == NULL) {
1352 goto fail;
1354 tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req);
1355 } else {
1356 subreq = rpc_write_send(state, ev, cli->transport,
1357 state->rpc_out.data,
1358 state->rpc_out.length);
1359 if (subreq == NULL) {
1360 goto fail;
1362 tevent_req_set_callback(subreq, rpc_api_pipe_req_write_done,
1363 req);
1365 return req;
1367 post_status:
1368 tevent_req_nterror(req, status);
1369 return tevent_req_post(req, ev);
1370 fail:
1371 TALLOC_FREE(req);
1372 return NULL;
1375 static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state)
1377 struct pipe_auth_data *a = state->cli->auth;
1378 struct dcerpc_sec_verification_trailer *t;
1379 struct dcerpc_sec_vt *c = NULL;
1380 struct ndr_push *ndr = NULL;
1381 enum ndr_err_code ndr_err;
1382 size_t align = 0;
1383 size_t pad = 0;
1385 if (a == NULL) {
1386 return NT_STATUS_OK;
1389 if (a->auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
1390 return NT_STATUS_OK;
1393 t = talloc_zero(state, struct dcerpc_sec_verification_trailer);
1394 if (t == NULL) {
1395 return NT_STATUS_NO_MEMORY;
1398 if (!a->verified_bitmask1) {
1399 t->commands = talloc_realloc(t, t->commands,
1400 struct dcerpc_sec_vt,
1401 t->count.count + 1);
1402 if (t->commands == NULL) {
1403 return NT_STATUS_NO_MEMORY;
1405 c = &t->commands[t->count.count++];
1406 ZERO_STRUCTP(c);
1408 c->command = DCERPC_SEC_VT_COMMAND_BITMASK1;
1409 if (a->client_hdr_signing) {
1410 c->u.bitmask1 = DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING;
1412 state->verify_bitmask1 = true;
1415 if (!state->cli->verified_pcontext) {
1416 t->commands = talloc_realloc(t, t->commands,
1417 struct dcerpc_sec_vt,
1418 t->count.count + 1);
1419 if (t->commands == NULL) {
1420 return NT_STATUS_NO_MEMORY;
1422 c = &t->commands[t->count.count++];
1423 ZERO_STRUCTP(c);
1425 c->command = DCERPC_SEC_VT_COMMAND_PCONTEXT;
1426 c->u.pcontext.abstract_syntax = state->cli->abstract_syntax;
1427 c->u.pcontext.transfer_syntax = state->cli->transfer_syntax;
1429 state->verify_pcontext = true;
1432 if (!a->hdr_signing) {
1433 t->commands = talloc_realloc(t, t->commands,
1434 struct dcerpc_sec_vt,
1435 t->count.count + 1);
1436 if (t->commands == NULL) {
1437 return NT_STATUS_NO_MEMORY;
1439 c = &t->commands[t->count.count++];
1440 ZERO_STRUCTP(c);
1442 c->command = DCERPC_SEC_VT_COMMAND_HEADER2;
1443 c->u.header2.ptype = DCERPC_PKT_REQUEST;
1444 c->u.header2.drep[0] = DCERPC_DREP_LE;
1445 c->u.header2.drep[1] = 0;
1446 c->u.header2.drep[2] = 0;
1447 c->u.header2.drep[3] = 0;
1448 c->u.header2.call_id = state->call_id;
1449 c->u.header2.context_id = 0;
1450 c->u.header2.opnum = state->op_num;
1453 if (t->count.count == 0) {
1454 TALLOC_FREE(t);
1455 return NT_STATUS_OK;
1458 c = &t->commands[t->count.count - 1];
1459 c->command |= DCERPC_SEC_VT_COMMAND_END;
1461 if (DEBUGLEVEL >= 10) {
1462 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1465 ndr = ndr_push_init_ctx(state);
1466 if (ndr == NULL) {
1467 return NT_STATUS_NO_MEMORY;
1470 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1471 NDR_SCALARS | NDR_BUFFERS,
1473 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1474 return ndr_map_error2ntstatus(ndr_err);
1476 state->req_trailer = ndr_push_blob(ndr);
1478 align = state->req_data->length & 0x3;
1479 if (align > 0) {
1480 pad = 4 - align;
1482 if (pad > 0) {
1483 bool ok;
1484 uint8_t *p;
1485 const uint8_t zeros[4] = { 0, };
1487 ok = data_blob_append(ndr, &state->req_trailer, zeros, pad);
1488 if (!ok) {
1489 return NT_STATUS_NO_MEMORY;
1492 /* move the padding to the start */
1493 p = state->req_trailer.data;
1494 memmove(p + pad, p, state->req_trailer.length - pad);
1495 memset(p, 0, pad);
1498 return NT_STATUS_OK;
1501 static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
1502 bool *is_last_frag)
1504 size_t auth_len;
1505 size_t frag_len;
1506 uint8_t flags = 0;
1507 size_t pad_len;
1508 size_t data_left;
1509 size_t data_thistime;
1510 size_t trailer_left;
1511 size_t trailer_thistime = 0;
1512 size_t total_left;
1513 size_t total_thistime;
1514 NTSTATUS status;
1515 bool ok;
1516 union dcerpc_payload u;
1518 data_left = state->req_data->length - state->req_data_sent;
1519 trailer_left = state->req_trailer.length - state->req_trailer_sent;
1520 total_left = data_left + trailer_left;
1521 if ((total_left < data_left) || (total_left < trailer_left)) {
1523 * overflow
1525 return NT_STATUS_INVALID_PARAMETER_MIX;
1528 status = dcerpc_guess_sizes(state->cli->auth,
1529 DCERPC_REQUEST_LENGTH, total_left,
1530 state->cli->max_xmit_frag,
1531 &total_thistime,
1532 &frag_len, &auth_len, &pad_len);
1533 if (!NT_STATUS_IS_OK(status)) {
1534 return status;
1537 if (state->req_data_sent == 0) {
1538 flags = DCERPC_PFC_FLAG_FIRST;
1541 if (total_thistime == total_left) {
1542 flags |= DCERPC_PFC_FLAG_LAST;
1545 data_thistime = MIN(total_thistime, data_left);
1546 if (data_thistime < total_thistime) {
1547 trailer_thistime = total_thistime - data_thistime;
1550 data_blob_free(&state->rpc_out);
1552 ZERO_STRUCT(u.request);
1554 u.request.alloc_hint = total_left;
1555 u.request.context_id = 0;
1556 u.request.opnum = state->op_num;
1558 status = dcerpc_push_ncacn_packet(state,
1559 DCERPC_PKT_REQUEST,
1560 flags,
1561 auth_len,
1562 state->call_id,
1564 &state->rpc_out);
1565 if (!NT_STATUS_IS_OK(status)) {
1566 return status;
1569 /* explicitly set frag_len here as dcerpc_push_ncacn_packet() can't
1570 * compute it right for requests because the auth trailer is missing
1571 * at this stage */
1572 dcerpc_set_frag_length(&state->rpc_out, frag_len);
1574 if (data_thistime > 0) {
1575 /* Copy in the data. */
1576 ok = data_blob_append(NULL, &state->rpc_out,
1577 state->req_data->data + state->req_data_sent,
1578 data_thistime);
1579 if (!ok) {
1580 return NT_STATUS_NO_MEMORY;
1582 state->req_data_sent += data_thistime;
1585 if (trailer_thistime > 0) {
1586 /* Copy in the verification trailer. */
1587 ok = data_blob_append(NULL, &state->rpc_out,
1588 state->req_trailer.data + state->req_trailer_sent,
1589 trailer_thistime);
1590 if (!ok) {
1591 return NT_STATUS_NO_MEMORY;
1593 state->req_trailer_sent += trailer_thistime;
1596 switch (state->cli->auth->auth_level) {
1597 case DCERPC_AUTH_LEVEL_NONE:
1598 case DCERPC_AUTH_LEVEL_CONNECT:
1599 case DCERPC_AUTH_LEVEL_PACKET:
1600 break;
1601 case DCERPC_AUTH_LEVEL_INTEGRITY:
1602 case DCERPC_AUTH_LEVEL_PRIVACY:
1603 status = dcerpc_add_auth_footer(state->cli->auth, pad_len,
1604 &state->rpc_out);
1605 if (!NT_STATUS_IS_OK(status)) {
1606 return status;
1608 break;
1609 default:
1610 return NT_STATUS_INVALID_PARAMETER;
1613 *is_last_frag = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
1615 return status;
1618 static void rpc_api_pipe_req_write_done(struct tevent_req *subreq)
1620 struct tevent_req *req = tevent_req_callback_data(
1621 subreq, struct tevent_req);
1622 struct rpc_api_pipe_req_state *state = tevent_req_data(
1623 req, struct rpc_api_pipe_req_state);
1624 NTSTATUS status;
1625 bool is_last_frag;
1627 status = rpc_write_recv(subreq);
1628 TALLOC_FREE(subreq);
1629 if (!NT_STATUS_IS_OK(status)) {
1630 tevent_req_nterror(req, status);
1631 return;
1634 status = prepare_next_frag(state, &is_last_frag);
1635 if (!NT_STATUS_IS_OK(status)) {
1636 tevent_req_nterror(req, status);
1637 return;
1640 if (is_last_frag) {
1641 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
1642 &state->rpc_out,
1643 DCERPC_PKT_RESPONSE,
1644 state->call_id);
1645 if (tevent_req_nomem(subreq, req)) {
1646 return;
1648 tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req);
1649 } else {
1650 subreq = rpc_write_send(state, state->ev,
1651 state->cli->transport,
1652 state->rpc_out.data,
1653 state->rpc_out.length);
1654 if (tevent_req_nomem(subreq, req)) {
1655 return;
1657 tevent_req_set_callback(subreq, rpc_api_pipe_req_write_done,
1658 req);
1662 static void rpc_api_pipe_req_done(struct tevent_req *subreq)
1664 struct tevent_req *req = tevent_req_callback_data(
1665 subreq, struct tevent_req);
1666 struct rpc_api_pipe_req_state *state = tevent_req_data(
1667 req, struct rpc_api_pipe_req_state);
1668 NTSTATUS status;
1670 status = rpc_api_pipe_recv(subreq, state, NULL, &state->reply_pdu);
1671 TALLOC_FREE(subreq);
1672 if (!NT_STATUS_IS_OK(status)) {
1673 tevent_req_nterror(req, status);
1674 return;
1677 if (state->cli->auth == NULL) {
1678 tevent_req_done(req);
1679 return;
1682 if (state->verify_bitmask1) {
1683 state->cli->auth->verified_bitmask1 = true;
1686 if (state->verify_pcontext) {
1687 state->cli->verified_pcontext = true;
1690 tevent_req_done(req);
1693 static NTSTATUS rpc_api_pipe_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1694 DATA_BLOB *reply_pdu)
1696 struct rpc_api_pipe_req_state *state = tevent_req_data(
1697 req, struct rpc_api_pipe_req_state);
1698 NTSTATUS status;
1700 if (tevent_req_is_nterror(req, &status)) {
1702 * We always have to initialize to reply pdu, even if there is
1703 * none. The rpccli_* caller routines expect this.
1705 *reply_pdu = data_blob_null;
1706 return status;
1709 /* return data to caller and assign it ownership of memory */
1710 reply_pdu->data = talloc_move(mem_ctx, &state->reply_pdu.data);
1711 reply_pdu->length = state->reply_pdu.length;
1712 state->reply_pdu.length = 0;
1714 return NT_STATUS_OK;
1717 /****************************************************************************
1718 Check the rpc bind acknowledge response.
1719 ****************************************************************************/
1721 static bool check_bind_response(const struct dcerpc_bind_ack *r,
1722 const struct ndr_syntax_id *transfer)
1724 struct dcerpc_ack_ctx ctx;
1726 if (r->secondary_address_size == 0) {
1727 DEBUG(4,("Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly)"));
1730 if (r->num_results < 1 || !r->ctx_list) {
1731 return false;
1734 ctx = r->ctx_list[0];
1736 /* check the transfer syntax */
1737 if ((ctx.syntax.if_version != transfer->if_version) ||
1738 (memcmp(&ctx.syntax.uuid, &transfer->uuid, sizeof(transfer->uuid)) !=0)) {
1739 DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n"));
1740 return False;
1743 if (r->num_results != 0x1 || ctx.result != 0) {
1744 DEBUG(2,("bind_rpc_pipe: bind denied results: %d reason: %x\n",
1745 r->num_results, ctx.reason.value));
1748 DEBUG(5,("check_bind_response: accepted!\n"));
1749 return True;
1752 /*******************************************************************
1753 Creates a DCE/RPC bind authentication response.
1754 This is the packet that is sent back to the server once we
1755 have received a BIND-ACK, to finish the third leg of
1756 the authentication handshake.
1757 ********************************************************************/
1759 static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
1760 struct rpc_pipe_client *cli,
1761 struct pipe_auth_data *auth,
1762 uint32_t rpc_call_id,
1763 DATA_BLOB *pauth_blob,
1764 DATA_BLOB *rpc_out)
1766 NTSTATUS status;
1767 union dcerpc_payload u;
1769 u.auth3._pad = 0;
1771 status = dcerpc_push_dcerpc_auth(mem_ctx,
1772 auth->auth_type,
1773 auth->auth_level,
1774 0, /* auth_pad_length */
1775 auth->auth_context_id,
1776 pauth_blob,
1777 &u.auth3.auth_info);
1778 if (!NT_STATUS_IS_OK(status)) {
1779 return status;
1782 status = dcerpc_push_ncacn_packet(mem_ctx,
1783 DCERPC_PKT_AUTH3,
1784 DCERPC_PFC_FLAG_FIRST |
1785 DCERPC_PFC_FLAG_LAST,
1786 pauth_blob->length,
1787 rpc_call_id,
1789 rpc_out);
1790 data_blob_free(&u.auth3.auth_info);
1791 if (!NT_STATUS_IS_OK(status)) {
1792 DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR_RB.\n"));
1793 return status;
1796 return NT_STATUS_OK;
1799 /*******************************************************************
1800 Creates a DCE/RPC bind alter context authentication request which
1801 may contain a spnego auth blobl
1802 ********************************************************************/
1804 static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
1805 struct pipe_auth_data *auth,
1806 uint32_t rpc_call_id,
1807 const struct ndr_syntax_id *abstract,
1808 const struct ndr_syntax_id *transfer,
1809 const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
1810 DATA_BLOB *rpc_out)
1812 DATA_BLOB auth_info;
1813 NTSTATUS status;
1815 status = dcerpc_push_dcerpc_auth(mem_ctx,
1816 auth->auth_type,
1817 auth->auth_level,
1818 0, /* auth_pad_length */
1819 auth->auth_context_id,
1820 pauth_blob,
1821 &auth_info);
1822 if (!NT_STATUS_IS_OK(status)) {
1823 return status;
1826 status = create_bind_or_alt_ctx_internal(mem_ctx,
1827 DCERPC_PKT_ALTER,
1828 rpc_call_id,
1829 abstract,
1830 transfer,
1831 &auth_info,
1832 false, /* client_hdr_signing */
1833 rpc_out);
1834 data_blob_free(&auth_info);
1835 return status;
1838 /****************************************************************************
1839 Do an rpc bind.
1840 ****************************************************************************/
1842 struct rpc_pipe_bind_state {
1843 struct tevent_context *ev;
1844 struct rpc_pipe_client *cli;
1845 DATA_BLOB rpc_out;
1846 bool auth3;
1847 uint32_t rpc_call_id;
1850 static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq);
1851 static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
1852 struct rpc_pipe_bind_state *state,
1853 DATA_BLOB *credentials);
1854 static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
1855 struct rpc_pipe_bind_state *state,
1856 DATA_BLOB *credentials);
1858 struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx,
1859 struct tevent_context *ev,
1860 struct rpc_pipe_client *cli,
1861 struct pipe_auth_data *auth)
1863 struct tevent_req *req, *subreq;
1864 struct rpc_pipe_bind_state *state;
1865 NTSTATUS status;
1867 req = tevent_req_create(mem_ctx, &state, struct rpc_pipe_bind_state);
1868 if (req == NULL) {
1869 return NULL;
1872 DEBUG(5,("Bind RPC Pipe: %s auth_type %u, auth_level %u\n",
1873 rpccli_pipe_txt(talloc_tos(), cli),
1874 (unsigned int)auth->auth_type,
1875 (unsigned int)auth->auth_level ));
1877 state->ev = ev;
1878 state->cli = cli;
1879 state->rpc_call_id = get_rpc_call_id();
1881 cli->auth = talloc_move(cli, &auth);
1883 /* Marshall the outgoing data. */
1884 status = create_rpc_bind_req(state, cli,
1885 cli->auth,
1886 state->rpc_call_id,
1887 &cli->abstract_syntax,
1888 &cli->transfer_syntax,
1889 &state->rpc_out);
1891 if (!NT_STATUS_IS_OK(status) &&
1892 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1893 goto post_status;
1896 subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
1897 DCERPC_PKT_BIND_ACK, state->rpc_call_id);
1898 if (subreq == NULL) {
1899 goto fail;
1901 tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
1902 return req;
1904 post_status:
1905 tevent_req_nterror(req, status);
1906 return tevent_req_post(req, ev);
1907 fail:
1908 TALLOC_FREE(req);
1909 return NULL;
1912 static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq)
1914 struct tevent_req *req = tevent_req_callback_data(
1915 subreq, struct tevent_req);
1916 struct rpc_pipe_bind_state *state = tevent_req_data(
1917 req, struct rpc_pipe_bind_state);
1918 struct pipe_auth_data *pauth = state->cli->auth;
1919 struct gensec_security *gensec_security;
1920 struct ncacn_packet *pkt = NULL;
1921 struct dcerpc_auth auth;
1922 DATA_BLOB auth_token = data_blob_null;
1923 NTSTATUS status;
1925 status = rpc_api_pipe_recv(subreq, talloc_tos(), &pkt, NULL);
1926 TALLOC_FREE(subreq);
1927 if (!NT_STATUS_IS_OK(status)) {
1928 DEBUG(3, ("rpc_pipe_bind: %s bind request returned %s\n",
1929 rpccli_pipe_txt(talloc_tos(), state->cli),
1930 nt_errstr(status)));
1931 tevent_req_nterror(req, status);
1932 return;
1935 if (state->auth3) {
1936 tevent_req_done(req);
1937 return;
1940 if (!check_bind_response(&pkt->u.bind_ack, &state->cli->transfer_syntax)) {
1941 DEBUG(2, ("rpc_pipe_bind: check_bind_response failed.\n"));
1942 tevent_req_nterror(req, NT_STATUS_BUFFER_TOO_SMALL);
1943 return;
1946 state->cli->max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1948 switch(pauth->auth_type) {
1950 case DCERPC_AUTH_TYPE_NONE:
1951 /* Bind complete. */
1952 tevent_req_done(req);
1953 return;
1955 default:
1956 if (pkt->auth_length == 0) {
1957 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1958 return;
1961 /* get auth credentials */
1962 status = dcerpc_pull_auth_trailer(pkt, talloc_tos(),
1963 &pkt->u.bind_ack.auth_info,
1964 &auth, NULL, true);
1965 if (!NT_STATUS_IS_OK(status)) {
1966 DEBUG(0, ("Failed to pull dcerpc auth: %s.\n",
1967 nt_errstr(status)));
1968 tevent_req_nterror(req, status);
1969 return;
1972 if (auth.auth_type != pauth->auth_type) {
1973 DEBUG(0, (__location__ " Auth type %u mismatch expected %u.\n",
1974 auth.auth_type, pauth->auth_type));
1975 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1976 return;
1979 if (auth.auth_level != pauth->auth_level) {
1980 DEBUG(0, (__location__ " Auth level %u mismatch expected %u.\n",
1981 auth.auth_level, pauth->auth_level));
1982 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1983 return;
1986 if (auth.auth_context_id != pauth->auth_context_id) {
1987 DEBUG(0, (__location__ " Auth context id %u mismatch expected %u.\n",
1988 (unsigned)auth.auth_context_id,
1989 (unsigned)pauth->auth_context_id));
1990 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1991 return;
1994 break;
1998 * For authenticated binds we may need to do 3 or 4 leg binds.
2001 switch(pauth->auth_type) {
2003 case DCERPC_AUTH_TYPE_NONE:
2004 /* Bind complete. */
2005 tevent_req_done(req);
2006 return;
2008 default:
2009 gensec_security = pauth->auth_ctx;
2011 if (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
2012 if (pauth->client_hdr_signing) {
2013 pauth->hdr_signing = true;
2014 gensec_want_feature(gensec_security,
2015 GENSEC_FEATURE_SIGN_PKT_HEADER);
2019 status = gensec_update(gensec_security, state,
2020 auth.credentials, &auth_token);
2021 if (NT_STATUS_EQUAL(status,
2022 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
2023 status = rpc_bind_next_send(req, state,
2024 &auth_token);
2025 } else if (NT_STATUS_IS_OK(status)) {
2026 if (auth_token.length == 0) {
2027 /* Bind complete. */
2028 tevent_req_done(req);
2029 return;
2031 status = rpc_bind_finish_send(req, state,
2032 &auth_token);
2034 break;
2037 if (!NT_STATUS_IS_OK(status)) {
2038 tevent_req_nterror(req, status);
2040 return;
2043 static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
2044 struct rpc_pipe_bind_state *state,
2045 DATA_BLOB *auth_token)
2047 struct pipe_auth_data *auth = state->cli->auth;
2048 struct tevent_req *subreq;
2049 NTSTATUS status;
2051 /* Now prepare the alter context pdu. */
2052 data_blob_free(&state->rpc_out);
2054 status = create_rpc_alter_context(state, auth,
2055 state->rpc_call_id,
2056 &state->cli->abstract_syntax,
2057 &state->cli->transfer_syntax,
2058 auth_token,
2059 &state->rpc_out);
2060 if (!NT_STATUS_IS_OK(status)) {
2061 return status;
2064 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
2065 &state->rpc_out, DCERPC_PKT_ALTER_RESP,
2066 state->rpc_call_id);
2067 if (subreq == NULL) {
2068 return NT_STATUS_NO_MEMORY;
2070 tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
2071 return NT_STATUS_OK;
2074 static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
2075 struct rpc_pipe_bind_state *state,
2076 DATA_BLOB *auth_token)
2078 struct pipe_auth_data *auth = state->cli->auth;
2079 struct tevent_req *subreq;
2080 NTSTATUS status;
2082 state->auth3 = true;
2084 /* Now prepare the auth3 context pdu. */
2085 data_blob_free(&state->rpc_out);
2087 status = create_rpc_bind_auth3(state, state->cli, auth,
2088 state->rpc_call_id,
2089 auth_token,
2090 &state->rpc_out);
2091 if (!NT_STATUS_IS_OK(status)) {
2092 return status;
2095 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
2096 &state->rpc_out, DCERPC_PKT_AUTH3,
2097 state->rpc_call_id);
2098 if (subreq == NULL) {
2099 return NT_STATUS_NO_MEMORY;
2101 tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
2102 return NT_STATUS_OK;
2105 NTSTATUS rpc_pipe_bind_recv(struct tevent_req *req)
2107 return tevent_req_simple_recv_ntstatus(req);
2110 NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
2111 struct pipe_auth_data *auth)
2113 TALLOC_CTX *frame = talloc_stackframe();
2114 struct tevent_context *ev;
2115 struct tevent_req *req;
2116 NTSTATUS status = NT_STATUS_OK;
2118 ev = samba_tevent_context_init(frame);
2119 if (ev == NULL) {
2120 status = NT_STATUS_NO_MEMORY;
2121 goto fail;
2124 req = rpc_pipe_bind_send(frame, ev, cli, auth);
2125 if (req == NULL) {
2126 status = NT_STATUS_NO_MEMORY;
2127 goto fail;
2130 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2131 goto fail;
2134 status = rpc_pipe_bind_recv(req);
2135 fail:
2136 TALLOC_FREE(frame);
2137 return status;
2140 #define RPCCLI_DEFAULT_TIMEOUT 10000 /* 10 seconds. */
2142 unsigned int rpccli_set_timeout(struct rpc_pipe_client *rpc_cli,
2143 unsigned int timeout)
2145 unsigned int old;
2147 if (rpc_cli->transport == NULL) {
2148 return RPCCLI_DEFAULT_TIMEOUT;
2151 if (rpc_cli->transport->set_timeout == NULL) {
2152 return RPCCLI_DEFAULT_TIMEOUT;
2155 old = rpc_cli->transport->set_timeout(rpc_cli->transport->priv, timeout);
2156 if (old == 0) {
2157 return RPCCLI_DEFAULT_TIMEOUT;
2160 return old;
2163 bool rpccli_is_connected(struct rpc_pipe_client *rpc_cli)
2165 if (rpc_cli == NULL) {
2166 return false;
2169 if (rpc_cli->transport == NULL) {
2170 return false;
2173 return rpc_cli->transport->is_connected(rpc_cli->transport->priv);
2176 struct rpccli_bh_state {
2177 struct rpc_pipe_client *rpc_cli;
2180 static bool rpccli_bh_is_connected(struct dcerpc_binding_handle *h)
2182 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2183 struct rpccli_bh_state);
2185 return rpccli_is_connected(hs->rpc_cli);
2188 static uint32_t rpccli_bh_set_timeout(struct dcerpc_binding_handle *h,
2189 uint32_t timeout)
2191 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2192 struct rpccli_bh_state);
2194 return rpccli_set_timeout(hs->rpc_cli, timeout);
2197 static void rpccli_bh_auth_info(struct dcerpc_binding_handle *h,
2198 enum dcerpc_AuthType *auth_type,
2199 enum dcerpc_AuthLevel *auth_level)
2201 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2202 struct rpccli_bh_state);
2204 if (hs->rpc_cli == NULL) {
2205 return;
2208 if (hs->rpc_cli->auth == NULL) {
2209 return;
2212 *auth_type = hs->rpc_cli->auth->auth_type;
2213 *auth_level = hs->rpc_cli->auth->auth_level;
2216 struct rpccli_bh_raw_call_state {
2217 DATA_BLOB in_data;
2218 DATA_BLOB out_data;
2219 uint32_t out_flags;
2222 static void rpccli_bh_raw_call_done(struct tevent_req *subreq);
2224 static struct tevent_req *rpccli_bh_raw_call_send(TALLOC_CTX *mem_ctx,
2225 struct tevent_context *ev,
2226 struct dcerpc_binding_handle *h,
2227 const struct GUID *object,
2228 uint32_t opnum,
2229 uint32_t in_flags,
2230 const uint8_t *in_data,
2231 size_t in_length)
2233 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2234 struct rpccli_bh_state);
2235 struct tevent_req *req;
2236 struct rpccli_bh_raw_call_state *state;
2237 bool ok;
2238 struct tevent_req *subreq;
2240 req = tevent_req_create(mem_ctx, &state,
2241 struct rpccli_bh_raw_call_state);
2242 if (req == NULL) {
2243 return NULL;
2245 state->in_data.data = discard_const_p(uint8_t, in_data);
2246 state->in_data.length = in_length;
2248 ok = rpccli_bh_is_connected(h);
2249 if (!ok) {
2250 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
2251 return tevent_req_post(req, ev);
2254 subreq = rpc_api_pipe_req_send(state, ev, hs->rpc_cli,
2255 opnum, &state->in_data);
2256 if (tevent_req_nomem(subreq, req)) {
2257 return tevent_req_post(req, ev);
2259 tevent_req_set_callback(subreq, rpccli_bh_raw_call_done, req);
2261 return req;
2264 static void rpccli_bh_raw_call_done(struct tevent_req *subreq)
2266 struct tevent_req *req =
2267 tevent_req_callback_data(subreq,
2268 struct tevent_req);
2269 struct rpccli_bh_raw_call_state *state =
2270 tevent_req_data(req,
2271 struct rpccli_bh_raw_call_state);
2272 NTSTATUS status;
2274 state->out_flags = 0;
2276 /* TODO: support bigendian responses */
2278 status = rpc_api_pipe_req_recv(subreq, state, &state->out_data);
2279 TALLOC_FREE(subreq);
2280 if (!NT_STATUS_IS_OK(status)) {
2281 tevent_req_nterror(req, status);
2282 return;
2285 tevent_req_done(req);
2288 static NTSTATUS rpccli_bh_raw_call_recv(struct tevent_req *req,
2289 TALLOC_CTX *mem_ctx,
2290 uint8_t **out_data,
2291 size_t *out_length,
2292 uint32_t *out_flags)
2294 struct rpccli_bh_raw_call_state *state =
2295 tevent_req_data(req,
2296 struct rpccli_bh_raw_call_state);
2297 NTSTATUS status;
2299 if (tevent_req_is_nterror(req, &status)) {
2300 tevent_req_received(req);
2301 return status;
2304 *out_data = talloc_move(mem_ctx, &state->out_data.data);
2305 *out_length = state->out_data.length;
2306 *out_flags = state->out_flags;
2307 tevent_req_received(req);
2308 return NT_STATUS_OK;
2311 struct rpccli_bh_disconnect_state {
2312 uint8_t _dummy;
2315 static struct tevent_req *rpccli_bh_disconnect_send(TALLOC_CTX *mem_ctx,
2316 struct tevent_context *ev,
2317 struct dcerpc_binding_handle *h)
2319 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2320 struct rpccli_bh_state);
2321 struct tevent_req *req;
2322 struct rpccli_bh_disconnect_state *state;
2323 bool ok;
2325 req = tevent_req_create(mem_ctx, &state,
2326 struct rpccli_bh_disconnect_state);
2327 if (req == NULL) {
2328 return NULL;
2331 ok = rpccli_bh_is_connected(h);
2332 if (!ok) {
2333 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
2334 return tevent_req_post(req, ev);
2338 * TODO: do a real async disconnect ...
2340 * For now we do it sync...
2342 TALLOC_FREE(hs->rpc_cli->transport);
2343 hs->rpc_cli = NULL;
2345 tevent_req_done(req);
2346 return tevent_req_post(req, ev);
2349 static NTSTATUS rpccli_bh_disconnect_recv(struct tevent_req *req)
2351 NTSTATUS status;
2353 if (tevent_req_is_nterror(req, &status)) {
2354 tevent_req_received(req);
2355 return status;
2358 tevent_req_received(req);
2359 return NT_STATUS_OK;
2362 static bool rpccli_bh_ref_alloc(struct dcerpc_binding_handle *h)
2364 return true;
2367 static void rpccli_bh_do_ndr_print(struct dcerpc_binding_handle *h,
2368 int ndr_flags,
2369 const void *_struct_ptr,
2370 const struct ndr_interface_call *call)
2372 void *struct_ptr = discard_const(_struct_ptr);
2374 if (DEBUGLEVEL < 10) {
2375 return;
2378 if (ndr_flags & NDR_IN) {
2379 ndr_print_function_debug(call->ndr_print,
2380 call->name,
2381 ndr_flags,
2382 struct_ptr);
2384 if (ndr_flags & NDR_OUT) {
2385 ndr_print_function_debug(call->ndr_print,
2386 call->name,
2387 ndr_flags,
2388 struct_ptr);
2392 static const struct dcerpc_binding_handle_ops rpccli_bh_ops = {
2393 .name = "rpccli",
2394 .is_connected = rpccli_bh_is_connected,
2395 .set_timeout = rpccli_bh_set_timeout,
2396 .auth_info = rpccli_bh_auth_info,
2397 .raw_call_send = rpccli_bh_raw_call_send,
2398 .raw_call_recv = rpccli_bh_raw_call_recv,
2399 .disconnect_send = rpccli_bh_disconnect_send,
2400 .disconnect_recv = rpccli_bh_disconnect_recv,
2402 .ref_alloc = rpccli_bh_ref_alloc,
2403 .do_ndr_print = rpccli_bh_do_ndr_print,
2406 /* initialise a rpc_pipe_client binding handle */
2407 struct dcerpc_binding_handle *rpccli_bh_create(struct rpc_pipe_client *c,
2408 const struct GUID *object,
2409 const struct ndr_interface_table *table)
2411 struct dcerpc_binding_handle *h;
2412 struct rpccli_bh_state *hs;
2414 h = dcerpc_binding_handle_create(c,
2415 &rpccli_bh_ops,
2416 object,
2417 table,
2418 &hs,
2419 struct rpccli_bh_state,
2420 __location__);
2421 if (h == NULL) {
2422 return NULL;
2424 hs->rpc_cli = c;
2426 return h;
2429 NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
2430 struct pipe_auth_data **presult)
2432 struct pipe_auth_data *result;
2433 struct auth_generic_state *auth_generic_ctx;
2434 NTSTATUS status;
2436 result = talloc_zero(mem_ctx, struct pipe_auth_data);
2437 if (result == NULL) {
2438 return NT_STATUS_NO_MEMORY;
2441 result->auth_type = DCERPC_AUTH_TYPE_NONE;
2442 result->auth_level = DCERPC_AUTH_LEVEL_NONE;
2443 result->auth_context_id = 0;
2445 status = auth_generic_client_prepare(result,
2446 &auth_generic_ctx);
2447 if (!NT_STATUS_IS_OK(status)) {
2448 DEBUG(1, ("Failed to create auth_generic context: %s\n",
2449 nt_errstr(status)));
2452 status = auth_generic_set_username(auth_generic_ctx, "");
2453 if (!NT_STATUS_IS_OK(status)) {
2454 DEBUG(1, ("Failed to set username: %s\n",
2455 nt_errstr(status)));
2458 status = auth_generic_set_domain(auth_generic_ctx, "");
2459 if (!NT_STATUS_IS_OK(status)) {
2460 DEBUG(1, ("Failed to set domain: %s\n",
2461 nt_errstr(status)));
2462 return status;
2465 status = gensec_set_credentials(auth_generic_ctx->gensec_security,
2466 auth_generic_ctx->credentials);
2467 if (!NT_STATUS_IS_OK(status)) {
2468 DEBUG(1, ("Failed to set GENSEC credentials: %s\n",
2469 nt_errstr(status)));
2470 return status;
2472 talloc_unlink(auth_generic_ctx, auth_generic_ctx->credentials);
2473 auth_generic_ctx->credentials = NULL;
2475 result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2476 talloc_free(auth_generic_ctx);
2477 *presult = result;
2478 return NT_STATUS_OK;
2481 static NTSTATUS rpccli_generic_bind_data(TALLOC_CTX *mem_ctx,
2482 enum dcerpc_AuthType auth_type,
2483 enum dcerpc_AuthLevel auth_level,
2484 const char *server,
2485 const char *target_service,
2486 const char *domain,
2487 const char *username,
2488 const char *password,
2489 enum credentials_use_kerberos use_kerberos,
2490 struct netlogon_creds_CredentialState *creds,
2491 struct pipe_auth_data **presult)
2493 struct auth_generic_state *auth_generic_ctx;
2494 struct pipe_auth_data *result;
2495 NTSTATUS status;
2497 result = talloc_zero(mem_ctx, struct pipe_auth_data);
2498 if (result == NULL) {
2499 return NT_STATUS_NO_MEMORY;
2502 result->auth_type = auth_type;
2503 result->auth_level = auth_level;
2504 result->auth_context_id = 1;
2506 status = auth_generic_client_prepare(result,
2507 &auth_generic_ctx);
2508 if (!NT_STATUS_IS_OK(status)) {
2509 goto fail;
2512 status = auth_generic_set_username(auth_generic_ctx, username);
2513 if (!NT_STATUS_IS_OK(status)) {
2514 goto fail;
2517 status = auth_generic_set_domain(auth_generic_ctx, domain);
2518 if (!NT_STATUS_IS_OK(status)) {
2519 goto fail;
2522 status = auth_generic_set_password(auth_generic_ctx, password);
2523 if (!NT_STATUS_IS_OK(status)) {
2524 goto fail;
2527 status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
2528 if (!NT_STATUS_IS_OK(status)) {
2529 goto fail;
2532 status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
2533 if (!NT_STATUS_IS_OK(status)) {
2534 goto fail;
2537 cli_credentials_set_kerberos_state(auth_generic_ctx->credentials, use_kerberos);
2538 cli_credentials_set_netlogon_creds(auth_generic_ctx->credentials, creds);
2540 status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
2541 if (!NT_STATUS_IS_OK(status)) {
2542 goto fail;
2545 result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2546 talloc_free(auth_generic_ctx);
2547 *presult = result;
2548 return NT_STATUS_OK;
2550 fail:
2551 TALLOC_FREE(result);
2552 return status;
2555 /* This routine steals the creds pointer that is passed in */
2556 static NTSTATUS rpccli_generic_bind_data_from_creds(TALLOC_CTX *mem_ctx,
2557 enum dcerpc_AuthType auth_type,
2558 enum dcerpc_AuthLevel auth_level,
2559 const char *server,
2560 const char *target_service,
2561 struct cli_credentials *creds,
2562 struct pipe_auth_data **presult)
2564 struct auth_generic_state *auth_generic_ctx;
2565 struct pipe_auth_data *result;
2566 NTSTATUS status;
2568 result = talloc_zero(mem_ctx, struct pipe_auth_data);
2569 if (result == NULL) {
2570 return NT_STATUS_NO_MEMORY;
2573 result->auth_type = auth_type;
2574 result->auth_level = auth_level;
2575 result->auth_context_id = 1;
2577 status = auth_generic_client_prepare(result,
2578 &auth_generic_ctx);
2579 if (!NT_STATUS_IS_OK(status)) {
2580 goto fail;
2583 status = auth_generic_set_creds(auth_generic_ctx, creds);
2584 if (!NT_STATUS_IS_OK(status)) {
2585 goto fail;
2588 status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
2589 if (!NT_STATUS_IS_OK(status)) {
2590 goto fail;
2593 status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
2594 if (!NT_STATUS_IS_OK(status)) {
2595 goto fail;
2598 status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
2599 if (!NT_STATUS_IS_OK(status)) {
2600 goto fail;
2603 result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2604 talloc_free(auth_generic_ctx);
2605 *presult = result;
2606 return NT_STATUS_OK;
2608 fail:
2609 TALLOC_FREE(result);
2610 return status;
2613 NTSTATUS rpccli_ncalrpc_bind_data(TALLOC_CTX *mem_ctx,
2614 struct pipe_auth_data **presult)
2616 return rpccli_generic_bind_data(mem_ctx,
2617 DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM,
2618 DCERPC_AUTH_LEVEL_CONNECT,
2619 NULL, /* server */
2620 "host", /* target_service */
2621 NAME_NT_AUTHORITY, /* domain */
2622 "SYSTEM",
2623 "", /* password */
2624 CRED_DONT_USE_KERBEROS,
2625 NULL, /* netlogon_creds_CredentialState */
2626 presult);
2630 * Create an rpc pipe client struct, connecting to a tcp port.
2632 static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
2633 const struct sockaddr_storage *ss_addr,
2634 uint16_t port,
2635 const struct ndr_interface_table *table,
2636 struct rpc_pipe_client **presult)
2638 struct rpc_pipe_client *result;
2639 struct sockaddr_storage addr;
2640 NTSTATUS status;
2641 int fd;
2643 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
2644 if (result == NULL) {
2645 return NT_STATUS_NO_MEMORY;
2648 result->abstract_syntax = table->syntax_id;
2649 result->transfer_syntax = ndr_transfer_syntax_ndr;
2651 result->desthost = talloc_strdup(result, host);
2652 result->srv_name_slash = talloc_asprintf_strupper_m(
2653 result, "\\\\%s", result->desthost);
2654 if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
2655 status = NT_STATUS_NO_MEMORY;
2656 goto fail;
2659 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
2661 if (ss_addr == NULL) {
2662 if (!resolve_name(host, &addr, NBT_NAME_SERVER, false)) {
2663 status = NT_STATUS_NOT_FOUND;
2664 goto fail;
2666 } else {
2667 addr = *ss_addr;
2670 status = open_socket_out(&addr, port, 60*1000, &fd);
2671 if (!NT_STATUS_IS_OK(status)) {
2672 goto fail;
2674 set_socket_options(fd, lp_socket_options());
2676 status = rpc_transport_sock_init(result, fd, &result->transport);
2677 if (!NT_STATUS_IS_OK(status)) {
2678 close(fd);
2679 goto fail;
2682 result->transport->transport = NCACN_IP_TCP;
2684 result->binding_handle = rpccli_bh_create(result, NULL, table);
2685 if (result->binding_handle == NULL) {
2686 TALLOC_FREE(result);
2687 return NT_STATUS_NO_MEMORY;
2690 *presult = result;
2691 return NT_STATUS_OK;
2693 fail:
2694 TALLOC_FREE(result);
2695 return status;
2699 * Determine the tcp port on which a dcerpc interface is listening
2700 * for the ncacn_ip_tcp transport via the endpoint mapper of the
2701 * target host.
2703 static NTSTATUS rpc_pipe_get_tcp_port(const char *host,
2704 const struct sockaddr_storage *addr,
2705 const struct ndr_interface_table *table,
2706 uint16_t *pport)
2708 NTSTATUS status;
2709 struct rpc_pipe_client *epm_pipe = NULL;
2710 struct dcerpc_binding_handle *epm_handle = NULL;
2711 struct pipe_auth_data *auth = NULL;
2712 struct dcerpc_binding *map_binding = NULL;
2713 struct dcerpc_binding *res_binding = NULL;
2714 enum dcerpc_transport_t transport;
2715 const char *endpoint = NULL;
2716 struct epm_twr_t *map_tower = NULL;
2717 struct epm_twr_t *res_towers = NULL;
2718 struct policy_handle *entry_handle = NULL;
2719 uint32_t num_towers = 0;
2720 uint32_t max_towers = 1;
2721 struct epm_twr_p_t towers;
2722 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2723 uint32_t result = 0;
2725 if (pport == NULL) {
2726 status = NT_STATUS_INVALID_PARAMETER;
2727 goto done;
2730 if (ndr_syntax_id_equal(&table->syntax_id,
2731 &ndr_table_epmapper.syntax_id)) {
2732 *pport = 135;
2733 status = NT_STATUS_OK;
2734 goto done;
2737 /* open the connection to the endpoint mapper */
2738 status = rpc_pipe_open_tcp_port(tmp_ctx, host, addr, 135,
2739 &ndr_table_epmapper,
2740 &epm_pipe);
2742 if (!NT_STATUS_IS_OK(status)) {
2743 goto done;
2745 epm_handle = epm_pipe->binding_handle;
2747 status = rpccli_anon_bind_data(tmp_ctx, &auth);
2748 if (!NT_STATUS_IS_OK(status)) {
2749 goto done;
2752 status = rpc_pipe_bind(epm_pipe, auth);
2753 if (!NT_STATUS_IS_OK(status)) {
2754 goto done;
2757 /* create tower for asking the epmapper */
2759 status = dcerpc_parse_binding(tmp_ctx, "ncacn_ip_tcp:[135]",
2760 &map_binding);
2761 if (!NT_STATUS_IS_OK(status)) {
2762 goto done;
2765 status = dcerpc_binding_set_abstract_syntax(map_binding,
2766 &table->syntax_id);
2767 if (!NT_STATUS_IS_OK(status)) {
2768 goto done;
2771 map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
2772 if (map_tower == NULL) {
2773 status = NT_STATUS_NO_MEMORY;
2774 goto done;
2777 status = dcerpc_binding_build_tower(tmp_ctx, map_binding,
2778 &(map_tower->tower));
2779 if (!NT_STATUS_IS_OK(status)) {
2780 goto done;
2783 /* allocate further parameters for the epm_Map call */
2785 res_towers = talloc_array(tmp_ctx, struct epm_twr_t, max_towers);
2786 if (res_towers == NULL) {
2787 status = NT_STATUS_NO_MEMORY;
2788 goto done;
2790 towers.twr = res_towers;
2792 entry_handle = talloc_zero(tmp_ctx, struct policy_handle);
2793 if (entry_handle == NULL) {
2794 status = NT_STATUS_NO_MEMORY;
2795 goto done;
2798 /* ask the endpoint mapper for the port */
2800 status = dcerpc_epm_Map(epm_handle,
2801 tmp_ctx,
2802 discard_const_p(struct GUID,
2803 &(table->syntax_id.uuid)),
2804 map_tower,
2805 entry_handle,
2806 max_towers,
2807 &num_towers,
2808 &towers,
2809 &result);
2811 if (!NT_STATUS_IS_OK(status)) {
2812 goto done;
2815 if (result != EPMAPPER_STATUS_OK) {
2816 status = NT_STATUS_UNSUCCESSFUL;
2817 goto done;
2820 if (num_towers != 1) {
2821 status = NT_STATUS_UNSUCCESSFUL;
2822 goto done;
2825 /* extract the port from the answer */
2827 status = dcerpc_binding_from_tower(tmp_ctx,
2828 &(towers.twr->tower),
2829 &res_binding);
2830 if (!NT_STATUS_IS_OK(status)) {
2831 goto done;
2834 transport = dcerpc_binding_get_transport(res_binding);
2835 endpoint = dcerpc_binding_get_string_option(res_binding, "endpoint");
2837 /* are further checks here necessary? */
2838 if (transport != NCACN_IP_TCP) {
2839 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2840 goto done;
2843 if (endpoint == NULL) {
2844 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2845 goto done;
2848 *pport = (uint16_t)atoi(endpoint);
2850 done:
2851 TALLOC_FREE(tmp_ctx);
2852 return status;
2856 * Create a rpc pipe client struct, connecting to a host via tcp.
2857 * The port is determined by asking the endpoint mapper on the given
2858 * host.
2860 NTSTATUS rpc_pipe_open_tcp(TALLOC_CTX *mem_ctx, const char *host,
2861 const struct sockaddr_storage *addr,
2862 const struct ndr_interface_table *table,
2863 struct rpc_pipe_client **presult)
2865 NTSTATUS status;
2866 uint16_t port = 0;
2868 status = rpc_pipe_get_tcp_port(host, addr, table, &port);
2869 if (!NT_STATUS_IS_OK(status)) {
2870 return status;
2873 return rpc_pipe_open_tcp_port(mem_ctx, host, addr, port,
2874 table, presult);
2877 /********************************************************************
2878 Create a rpc pipe client struct, connecting to a unix domain socket
2879 ********************************************************************/
2880 NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx, const char *socket_path,
2881 const struct ndr_interface_table *table,
2882 struct rpc_pipe_client **presult)
2884 struct rpc_pipe_client *result;
2885 struct sockaddr_un addr;
2886 NTSTATUS status;
2887 int fd;
2888 socklen_t salen;
2890 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
2891 if (result == NULL) {
2892 return NT_STATUS_NO_MEMORY;
2895 result->abstract_syntax = table->syntax_id;
2896 result->transfer_syntax = ndr_transfer_syntax_ndr;
2898 result->desthost = get_myname(result);
2899 result->srv_name_slash = talloc_asprintf_strupper_m(
2900 result, "\\\\%s", result->desthost);
2901 if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
2902 status = NT_STATUS_NO_MEMORY;
2903 goto fail;
2906 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
2908 fd = socket(AF_UNIX, SOCK_STREAM, 0);
2909 if (fd == -1) {
2910 status = map_nt_error_from_unix(errno);
2911 goto fail;
2914 ZERO_STRUCT(addr);
2915 addr.sun_family = AF_UNIX;
2916 strlcpy(addr.sun_path, socket_path, sizeof(addr.sun_path));
2917 salen = sizeof(struct sockaddr_un);
2919 if (connect(fd, (struct sockaddr *)(void *)&addr, salen) == -1) {
2920 DEBUG(0, ("connect(%s) failed: %s\n", socket_path,
2921 strerror(errno)));
2922 close(fd);
2923 return map_nt_error_from_unix(errno);
2926 status = rpc_transport_sock_init(result, fd, &result->transport);
2927 if (!NT_STATUS_IS_OK(status)) {
2928 close(fd);
2929 goto fail;
2932 result->transport->transport = NCALRPC;
2934 result->binding_handle = rpccli_bh_create(result, NULL, table);
2935 if (result->binding_handle == NULL) {
2936 TALLOC_FREE(result);
2937 return NT_STATUS_NO_MEMORY;
2940 *presult = result;
2941 return NT_STATUS_OK;
2943 fail:
2944 TALLOC_FREE(result);
2945 return status;
2948 struct rpc_pipe_client_np_ref {
2949 struct cli_state *cli;
2950 struct rpc_pipe_client *pipe;
2953 static int rpc_pipe_client_np_ref_destructor(struct rpc_pipe_client_np_ref *np_ref)
2955 DLIST_REMOVE(np_ref->cli->pipe_list, np_ref->pipe);
2956 return 0;
2959 /****************************************************************************
2960 Open a named pipe over SMB to a remote server.
2962 * CAVEAT CALLER OF THIS FUNCTION:
2963 * The returned rpc_pipe_client saves a copy of the cli_state cli pointer,
2964 * so be sure that this function is called AFTER any structure (vs pointer)
2965 * assignment of the cli. In particular, libsmbclient does structure
2966 * assignments of cli, which invalidates the data in the returned
2967 * rpc_pipe_client if this function is called before the structure assignment
2968 * of cli.
2970 ****************************************************************************/
2972 static NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
2973 const struct ndr_interface_table *table,
2974 struct rpc_pipe_client **presult)
2976 struct rpc_pipe_client *result;
2977 NTSTATUS status;
2978 struct rpc_pipe_client_np_ref *np_ref;
2980 /* sanity check to protect against crashes */
2982 if ( !cli ) {
2983 return NT_STATUS_INVALID_HANDLE;
2986 result = talloc_zero(NULL, struct rpc_pipe_client);
2987 if (result == NULL) {
2988 return NT_STATUS_NO_MEMORY;
2991 result->abstract_syntax = table->syntax_id;
2992 result->transfer_syntax = ndr_transfer_syntax_ndr;
2993 result->desthost = talloc_strdup(result, smbXcli_conn_remote_name(cli->conn));
2994 result->srv_name_slash = talloc_asprintf_strupper_m(
2995 result, "\\\\%s", result->desthost);
2997 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
2999 if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
3000 TALLOC_FREE(result);
3001 return NT_STATUS_NO_MEMORY;
3004 status = rpc_transport_np_init(result, cli, table,
3005 &result->transport);
3006 if (!NT_STATUS_IS_OK(status)) {
3007 TALLOC_FREE(result);
3008 return status;
3011 result->transport->transport = NCACN_NP;
3013 np_ref = talloc(result->transport, struct rpc_pipe_client_np_ref);
3014 if (np_ref == NULL) {
3015 TALLOC_FREE(result);
3016 return NT_STATUS_NO_MEMORY;
3018 np_ref->cli = cli;
3019 np_ref->pipe = result;
3021 DLIST_ADD(np_ref->cli->pipe_list, np_ref->pipe);
3022 talloc_set_destructor(np_ref, rpc_pipe_client_np_ref_destructor);
3024 result->binding_handle = rpccli_bh_create(result, NULL, table);
3025 if (result->binding_handle == NULL) {
3026 TALLOC_FREE(result);
3027 return NT_STATUS_NO_MEMORY;
3030 *presult = result;
3031 return NT_STATUS_OK;
3034 /****************************************************************************
3035 Open a pipe to a remote server.
3036 ****************************************************************************/
3038 static NTSTATUS cli_rpc_pipe_open(struct cli_state *cli,
3039 enum dcerpc_transport_t transport,
3040 const struct ndr_interface_table *table,
3041 struct rpc_pipe_client **presult)
3043 switch (transport) {
3044 case NCACN_IP_TCP:
3045 return rpc_pipe_open_tcp(NULL,
3046 smbXcli_conn_remote_name(cli->conn),
3047 smbXcli_conn_remote_sockaddr(cli->conn),
3048 table, presult);
3049 case NCACN_NP:
3050 return rpc_pipe_open_np(cli, table, presult);
3051 default:
3052 return NT_STATUS_NOT_IMPLEMENTED;
3056 /****************************************************************************
3057 Open a named pipe to an SMB server and bind anonymously.
3058 ****************************************************************************/
3060 NTSTATUS cli_rpc_pipe_open_noauth_transport(struct cli_state *cli,
3061 enum dcerpc_transport_t transport,
3062 const struct ndr_interface_table *table,
3063 struct rpc_pipe_client **presult)
3065 struct rpc_pipe_client *result;
3066 struct pipe_auth_data *auth;
3067 NTSTATUS status;
3069 status = cli_rpc_pipe_open(cli, transport, table, &result);
3070 if (!NT_STATUS_IS_OK(status)) {
3071 return status;
3074 status = rpccli_anon_bind_data(result, &auth);
3075 if (!NT_STATUS_IS_OK(status)) {
3076 DEBUG(0, ("rpccli_anon_bind_data returned %s\n",
3077 nt_errstr(status)));
3078 TALLOC_FREE(result);
3079 return status;
3083 * This is a bit of an abstraction violation due to the fact that an
3084 * anonymous bind on an authenticated SMB inherits the user/domain
3085 * from the enclosing SMB creds
3088 if (transport == NCACN_NP) {
3089 struct smbXcli_session *session;
3091 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3092 session = cli->smb2.session;
3093 } else {
3094 session = cli->smb1.session;
3097 status = smbXcli_session_application_key(session, auth,
3098 &auth->transport_session_key);
3099 if (!NT_STATUS_IS_OK(status)) {
3100 auth->transport_session_key = data_blob_null;
3104 status = rpc_pipe_bind(result, auth);
3105 if (!NT_STATUS_IS_OK(status)) {
3106 int lvl = 0;
3107 if (ndr_syntax_id_equal(&table->syntax_id,
3108 &ndr_table_dssetup.syntax_id)) {
3109 /* non AD domains just don't have this pipe, avoid
3110 * level 0 statement in that case - gd */
3111 lvl = 3;
3113 DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe "
3114 "%s failed with error %s\n",
3115 table->name,
3116 nt_errstr(status) ));
3117 TALLOC_FREE(result);
3118 return status;
3121 DEBUG(10,("cli_rpc_pipe_open_noauth: opened pipe %s to machine "
3122 "%s and bound anonymously.\n",
3123 table->name,
3124 result->desthost));
3126 *presult = result;
3127 return NT_STATUS_OK;
3130 /****************************************************************************
3131 ****************************************************************************/
3133 NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli,
3134 const struct ndr_interface_table *table,
3135 struct rpc_pipe_client **presult)
3137 return cli_rpc_pipe_open_noauth_transport(cli, NCACN_NP,
3138 table, presult);
3141 /****************************************************************************
3142 Open a named pipe to an SMB server and bind using the mech specified
3144 This routine references the creds pointer that is passed in
3145 ****************************************************************************/
3147 NTSTATUS cli_rpc_pipe_open_with_creds(struct cli_state *cli,
3148 const struct ndr_interface_table *table,
3149 enum dcerpc_transport_t transport,
3150 enum dcerpc_AuthType auth_type,
3151 enum dcerpc_AuthLevel auth_level,
3152 const char *server,
3153 struct cli_credentials *creds,
3154 struct rpc_pipe_client **presult)
3156 struct rpc_pipe_client *result;
3157 struct pipe_auth_data *auth = NULL;
3158 const char *target_service = table->authservices->names[0];
3160 NTSTATUS status;
3162 status = cli_rpc_pipe_open(cli, transport, table, &result);
3163 if (!NT_STATUS_IS_OK(status)) {
3164 return status;
3167 status = rpccli_generic_bind_data_from_creds(result,
3168 auth_type, auth_level,
3169 server, target_service,
3170 creds,
3171 &auth);
3172 if (!NT_STATUS_IS_OK(status)) {
3173 DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
3174 nt_errstr(status)));
3175 goto err;
3178 status = rpc_pipe_bind(result, auth);
3179 if (!NT_STATUS_IS_OK(status)) {
3180 DEBUG(0, ("cli_rpc_pipe_open_generic_auth: cli_rpc_pipe_bind failed with error %s\n",
3181 nt_errstr(status) ));
3182 goto err;
3185 DEBUG(10,("cli_rpc_pipe_open_generic_auth: opened pipe %s to "
3186 "machine %s and bound as user %s.\n", table->name,
3187 result->desthost, cli_credentials_get_unparsed_name(creds, talloc_tos())));
3189 *presult = result;
3190 return NT_STATUS_OK;
3192 err:
3194 TALLOC_FREE(result);
3195 return status;
3198 /****************************************************************************
3199 Open a named pipe to an SMB server and bind using the mech specified
3201 This routine steals the creds pointer that is passed in
3202 ****************************************************************************/
3204 NTSTATUS cli_rpc_pipe_open_generic_auth(struct cli_state *cli,
3205 const struct ndr_interface_table *table,
3206 enum dcerpc_transport_t transport,
3207 enum credentials_use_kerberos use_kerberos,
3208 enum dcerpc_AuthType auth_type,
3209 enum dcerpc_AuthLevel auth_level,
3210 const char *server,
3211 const char *domain,
3212 const char *username,
3213 const char *password,
3214 struct rpc_pipe_client **presult)
3216 struct rpc_pipe_client *result;
3217 struct pipe_auth_data *auth = NULL;
3218 const char *target_service = table->authservices->names[0];
3220 NTSTATUS status;
3222 status = cli_rpc_pipe_open(cli, transport, table, &result);
3223 if (!NT_STATUS_IS_OK(status)) {
3224 return status;
3227 status = rpccli_generic_bind_data(result,
3228 auth_type, auth_level,
3229 server, target_service,
3230 domain, username, password,
3231 CRED_AUTO_USE_KERBEROS,
3232 NULL,
3233 &auth);
3234 if (!NT_STATUS_IS_OK(status)) {
3235 DEBUG(0, ("rpccli_generic_bind_data returned %s\n",
3236 nt_errstr(status)));
3237 goto err;
3240 status = rpc_pipe_bind(result, auth);
3241 if (!NT_STATUS_IS_OK(status)) {
3242 DEBUG(0, ("cli_rpc_pipe_open_generic_auth: cli_rpc_pipe_bind failed with error %s\n",
3243 nt_errstr(status) ));
3244 goto err;
3247 DEBUG(10,("cli_rpc_pipe_open_generic_auth: opened pipe %s to "
3248 "machine %s and bound as user %s\\%s.\n", table->name,
3249 result->desthost, domain, username));
3251 *presult = result;
3252 return NT_STATUS_OK;
3254 err:
3256 TALLOC_FREE(result);
3257 return status;
3260 NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
3261 const struct ndr_interface_table *table,
3262 enum dcerpc_transport_t transport,
3263 struct cli_credentials *cli_creds,
3264 struct netlogon_creds_cli_context *netlogon_creds,
3265 struct rpc_pipe_client **_rpccli)
3267 struct rpc_pipe_client *rpccli;
3268 struct pipe_auth_data *rpcauth;
3269 const char *target_service = table->authservices->names[0];
3270 struct netlogon_creds_CredentialState *ncreds = NULL;
3271 enum dcerpc_AuthLevel auth_level;
3272 NTSTATUS status;
3273 int rpc_pipe_bind_dbglvl = 0;
3275 status = cli_rpc_pipe_open(cli, transport, table, &rpccli);
3276 if (!NT_STATUS_IS_OK(status)) {
3277 return status;
3280 status = netlogon_creds_cli_lock(netlogon_creds, rpccli, &ncreds);
3281 if (!NT_STATUS_IS_OK(status)) {
3282 DEBUG(0, ("netlogon_creds_cli_get returned %s\n",
3283 nt_errstr(status)));
3284 TALLOC_FREE(rpccli);
3285 return status;
3288 auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
3290 cli_credentials_set_netlogon_creds(cli_creds, ncreds);
3292 status = rpccli_generic_bind_data_from_creds(rpccli,
3293 DCERPC_AUTH_TYPE_SCHANNEL,
3294 auth_level,
3295 rpccli->desthost,
3296 target_service,
3297 cli_creds,
3298 &rpcauth);
3299 if (!NT_STATUS_IS_OK(status)) {
3300 DEBUG(0, ("rpccli_generic_bind_data_from_creds returned %s\n",
3301 nt_errstr(status)));
3302 TALLOC_FREE(rpccli);
3303 return status;
3306 status = rpc_pipe_bind(rpccli, rpcauth);
3307 cli_credentials_set_netlogon_creds(cli_creds, NULL);
3308 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
3309 rpc_pipe_bind_dbglvl = 1;
3310 netlogon_creds_cli_delete(netlogon_creds, &ncreds);
3312 if (!NT_STATUS_IS_OK(status)) {
3313 DEBUG(rpc_pipe_bind_dbglvl,
3314 ("%s: rpc_pipe_bind failed with error %s\n",
3315 __func__, nt_errstr(status)));
3316 TALLOC_FREE(rpccli);
3317 return status;
3320 TALLOC_FREE(ncreds);
3322 if (!ndr_syntax_id_equal(&table->syntax_id, &ndr_table_netlogon.syntax_id)) {
3323 goto done;
3326 status = netlogon_creds_cli_check(netlogon_creds,
3327 rpccli->binding_handle);
3328 if (!NT_STATUS_IS_OK(status)) {
3329 DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
3330 nt_errstr(status)));
3331 TALLOC_FREE(rpccli);
3332 return status;
3336 done:
3337 DEBUG(10,("%s: opened pipe %s to machine %s "
3338 "for domain %s and bound using schannel.\n",
3339 __func__, table->name,
3340 rpccli->desthost, cli_credentials_get_domain(cli_creds)));
3342 *_rpccli = rpccli;
3343 return NT_STATUS_OK;
3346 NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
3347 struct rpc_pipe_client *cli,
3348 DATA_BLOB *session_key)
3350 NTSTATUS status;
3351 struct pipe_auth_data *a;
3352 struct gensec_security *gensec_security;
3353 DATA_BLOB sk = data_blob_null;
3354 bool make_dup = false;
3356 if (!session_key || !cli) {
3357 return NT_STATUS_INVALID_PARAMETER;
3360 a = cli->auth;
3362 if (a == NULL) {
3363 return NT_STATUS_INVALID_PARAMETER;
3366 switch (cli->auth->auth_type) {
3367 case DCERPC_AUTH_TYPE_NONE:
3368 sk = data_blob_const(a->transport_session_key.data,
3369 a->transport_session_key.length);
3370 make_dup = true;
3371 break;
3372 default:
3373 gensec_security = a->auth_ctx;
3374 status = gensec_session_key(gensec_security, mem_ctx, &sk);
3375 if (!NT_STATUS_IS_OK(status)) {
3376 return status;
3378 make_dup = false;
3379 break;
3382 if (!sk.data) {
3383 return NT_STATUS_NO_USER_SESSION_KEY;
3386 if (make_dup) {
3387 *session_key = data_blob_dup_talloc(mem_ctx, sk);
3388 } else {
3389 *session_key = sk;
3392 return NT_STATUS_OK;