tevent: allow the "standard" backend to be overloaded
[Samba.git] / source3 / rpc_client / cli_pipe.c
blob5e26dc1806de7503a9091225e36be07adeedb238
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 "libsmb/namequery.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "librpc/gen_ndr/ndr_epmapper_c.h"
26 #include "../librpc/gen_ndr/ndr_dssetup.h"
27 #include "../libcli/auth/schannel.h"
28 #include "../libcli/auth/netlogon_creds_cli.h"
29 #include "auth_generic.h"
30 #include "librpc/gen_ndr/ndr_dcerpc.h"
31 #include "librpc/gen_ndr/ndr_netlogon_c.h"
32 #include "librpc/gen_ndr/auth.h"
33 #include "librpc/rpc/dcerpc.h"
34 #include "librpc/rpc/dcerpc_util.h"
35 #include "rpc_dce.h"
36 #include "cli_pipe.h"
37 #include "libsmb/libsmb.h"
38 #include "auth/gensec/gensec.h"
39 #include "auth/credentials/credentials.h"
40 #include "auth/auth_util.h"
41 #include "../libcli/smb/smbXcli_base.h"
42 #include "lib/tsocket/tsocket.h"
43 #include "libcli/named_pipe_auth/npa_tstream.h"
44 #include "librpc/gen_ndr/ndr_winreg.h"
45 #include "local_np.h"
47 #undef DBGC_CLASS
48 #define DBGC_CLASS DBGC_RPC_CLI
50 /********************************************************************
51 Pipe description for a DEBUG
52 ********************************************************************/
53 static const char *rpccli_pipe_txt(TALLOC_CTX *mem_ctx,
54 struct rpc_pipe_client *cli)
56 char *result = talloc_asprintf(mem_ctx, "host %s", cli->desthost);
57 if (result == NULL) {
58 return "pipe";
60 return result;
63 /********************************************************************
64 Rpc pipe call id.
65 ********************************************************************/
67 static uint32_t get_rpc_call_id(void)
69 static uint32_t call_id = 0;
70 return ++call_id;
73 /*******************************************************************
74 Use SMBreadX to get rest of one fragment's worth of rpc data.
75 Reads the whole size or give an error message
76 ********************************************************************/
78 struct rpc_read_state {
79 struct tevent_context *ev;
80 struct rpc_cli_transport *transport;
81 uint8_t *data;
82 size_t size;
83 size_t num_read;
86 static void rpc_read_done(struct tevent_req *subreq);
88 static struct tevent_req *rpc_read_send(TALLOC_CTX *mem_ctx,
89 struct tevent_context *ev,
90 struct rpc_cli_transport *transport,
91 uint8_t *data, size_t size)
93 struct tevent_req *req, *subreq;
94 struct rpc_read_state *state;
96 req = tevent_req_create(mem_ctx, &state, struct rpc_read_state);
97 if (req == NULL) {
98 return NULL;
100 state->ev = ev;
101 state->transport = transport;
102 state->data = data;
103 state->size = size;
104 state->num_read = 0;
106 DBG_INFO("data_to_read: %zu\n", size);
108 subreq = transport->read_send(state, ev, (uint8_t *)data, size,
109 transport->priv);
110 if (subreq == NULL) {
111 goto fail;
113 tevent_req_set_callback(subreq, rpc_read_done, req);
114 return req;
116 fail:
117 TALLOC_FREE(req);
118 return NULL;
121 static void rpc_read_done(struct tevent_req *subreq)
123 struct tevent_req *req = tevent_req_callback_data(
124 subreq, struct tevent_req);
125 struct rpc_read_state *state = tevent_req_data(
126 req, struct rpc_read_state);
127 NTSTATUS status;
128 ssize_t received;
130 status = state->transport->read_recv(subreq, &received);
131 TALLOC_FREE(subreq);
132 if (tevent_req_nterror(req, status)) {
133 return;
136 state->num_read += received;
137 if (state->num_read == state->size) {
138 tevent_req_done(req);
139 return;
142 subreq = state->transport->read_send(state, state->ev,
143 state->data + state->num_read,
144 state->size - state->num_read,
145 state->transport->priv);
146 if (tevent_req_nomem(subreq, req)) {
147 return;
149 tevent_req_set_callback(subreq, rpc_read_done, req);
152 static NTSTATUS rpc_read_recv(struct tevent_req *req)
154 return tevent_req_simple_recv_ntstatus(req);
157 struct rpc_write_state {
158 struct tevent_context *ev;
159 struct rpc_cli_transport *transport;
160 const uint8_t *data;
161 size_t size;
162 size_t num_written;
165 static void rpc_write_done(struct tevent_req *subreq);
167 static struct tevent_req *rpc_write_send(TALLOC_CTX *mem_ctx,
168 struct tevent_context *ev,
169 struct rpc_cli_transport *transport,
170 const uint8_t *data, size_t size)
172 struct tevent_req *req, *subreq;
173 struct rpc_write_state *state;
175 req = tevent_req_create(mem_ctx, &state, struct rpc_write_state);
176 if (req == NULL) {
177 return NULL;
179 state->ev = ev;
180 state->transport = transport;
181 state->data = data;
182 state->size = size;
183 state->num_written = 0;
185 DBG_INFO("data_to_write: %zu\n", size);
187 subreq = transport->write_send(state, ev, data, size, transport->priv);
188 if (tevent_req_nomem(subreq, req)) {
189 return tevent_req_post(req, ev);
191 tevent_req_set_callback(subreq, rpc_write_done, req);
192 return req;
195 static void rpc_write_done(struct tevent_req *subreq)
197 struct tevent_req *req = tevent_req_callback_data(
198 subreq, struct tevent_req);
199 struct rpc_write_state *state = tevent_req_data(
200 req, struct rpc_write_state);
201 NTSTATUS status;
202 ssize_t written;
204 status = state->transport->write_recv(subreq, &written);
205 TALLOC_FREE(subreq);
206 if (tevent_req_nterror(req, status)) {
207 return;
210 state->num_written += written;
212 if (state->num_written == state->size) {
213 tevent_req_done(req);
214 return;
217 subreq = state->transport->write_send(state, state->ev,
218 state->data + state->num_written,
219 state->size - state->num_written,
220 state->transport->priv);
221 if (tevent_req_nomem(subreq, req)) {
222 return;
224 tevent_req_set_callback(subreq, rpc_write_done, req);
227 static NTSTATUS rpc_write_recv(struct tevent_req *req)
229 return tevent_req_simple_recv_ntstatus(req);
233 /****************************************************************************
234 Try and get a PDU's worth of data from current_pdu. If not, then read more
235 from the wire.
236 ****************************************************************************/
238 struct get_complete_frag_state {
239 struct tevent_context *ev;
240 struct rpc_pipe_client *cli;
241 uint16_t frag_len;
242 DATA_BLOB *pdu;
245 static void get_complete_frag_got_header(struct tevent_req *subreq);
246 static void get_complete_frag_got_rest(struct tevent_req *subreq);
248 static struct tevent_req *get_complete_frag_send(TALLOC_CTX *mem_ctx,
249 struct tevent_context *ev,
250 struct rpc_pipe_client *cli,
251 DATA_BLOB *pdu)
253 struct tevent_req *req, *subreq;
254 struct get_complete_frag_state *state;
255 size_t received;
257 req = tevent_req_create(mem_ctx, &state,
258 struct get_complete_frag_state);
259 if (req == NULL) {
260 return NULL;
262 state->ev = ev;
263 state->cli = cli;
264 state->frag_len = RPC_HEADER_LEN;
265 state->pdu = pdu;
267 received = pdu->length;
268 if (received < RPC_HEADER_LEN) {
269 if (!data_blob_realloc(mem_ctx, pdu, RPC_HEADER_LEN)) {
270 tevent_req_oom(req);
271 return tevent_req_post(req, ev);
273 subreq = rpc_read_send(state, state->ev,
274 state->cli->transport,
275 pdu->data + received,
276 RPC_HEADER_LEN - received);
277 if (tevent_req_nomem(subreq, req)) {
278 return tevent_req_post(req, ev);
280 tevent_req_set_callback(subreq, get_complete_frag_got_header,
281 req);
282 return req;
285 state->frag_len = dcerpc_get_frag_length(pdu);
286 if (state->frag_len < RPC_HEADER_LEN) {
287 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
288 return tevent_req_post(req, ev);
291 if (received >= state->frag_len) {
293 * Got the whole fragment
295 tevent_req_done(req);
296 return tevent_req_post(req, ev);
299 if (!data_blob_realloc(NULL, pdu, state->frag_len)) {
300 tevent_req_oom(req);
301 return tevent_req_post(req, ev);
304 subreq = rpc_read_send(
305 state,
306 state->ev,
307 state->cli->transport,
308 pdu->data + received,
309 state->frag_len - received);
310 if (tevent_req_nomem(subreq, req)) {
311 return tevent_req_post(req, ev);
313 tevent_req_set_callback(subreq, get_complete_frag_got_rest, req);
314 return req;
317 static void get_complete_frag_got_header(struct tevent_req *subreq)
319 struct tevent_req *req = tevent_req_callback_data(
320 subreq, struct tevent_req);
321 struct get_complete_frag_state *state = tevent_req_data(
322 req, struct get_complete_frag_state);
323 NTSTATUS status;
325 status = rpc_read_recv(subreq);
326 TALLOC_FREE(subreq);
327 if (tevent_req_nterror(req, status)) {
328 return;
331 state->frag_len = dcerpc_get_frag_length(state->pdu);
332 if (state->frag_len < RPC_HEADER_LEN) {
333 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
334 return;
337 if (!data_blob_realloc(NULL, state->pdu, state->frag_len)) {
338 tevent_req_oom(req);
339 return;
343 * We're here in this piece of code because we've read exactly
344 * RPC_HEADER_LEN bytes into state->pdu.
347 subreq = rpc_read_send(state, state->ev, state->cli->transport,
348 state->pdu->data + RPC_HEADER_LEN,
349 state->frag_len - RPC_HEADER_LEN);
350 if (tevent_req_nomem(subreq, req)) {
351 return;
353 tevent_req_set_callback(subreq, get_complete_frag_got_rest, req);
356 static void get_complete_frag_got_rest(struct tevent_req *subreq)
358 NTSTATUS status = rpc_read_recv(subreq);
359 return tevent_req_simple_finish_ntstatus(subreq, status);
362 static NTSTATUS get_complete_frag_recv(struct tevent_req *req)
364 return tevent_req_simple_recv_ntstatus(req);
367 /****************************************************************************
368 Do basic authentication checks on an incoming pdu.
369 ****************************************************************************/
371 static NTSTATUS cli_pipe_validate_current_pdu(TALLOC_CTX *mem_ctx,
372 struct rpc_pipe_client *cli,
373 struct ncacn_packet *pkt,
374 DATA_BLOB *pdu,
375 uint8_t expected_pkt_type,
376 uint32_t call_id,
377 DATA_BLOB *rdata,
378 DATA_BLOB *reply_pdu)
380 const struct dcerpc_response *r = NULL;
381 DATA_BLOB tmp_stub = { .data = NULL };
382 NTSTATUS ret;
385 * Point the return values at the real data including the RPC
386 * header. Just in case the caller wants it.
388 *rdata = *pdu;
390 if ((pkt->ptype == DCERPC_PKT_BIND_ACK) &&
391 !(pkt->pfc_flags & DCERPC_PFC_FLAG_LAST)) {
393 * TODO: do we still need this hack which was introduced
394 * in commit a42afcdcc7ab9aa9ed193ae36d3dbb10843447f0.
396 * I don't even know what AS/U might be...
398 DEBUG(5, (__location__ ": bug in server (AS/U?), setting "
399 "fragment first/last ON.\n"));
400 pkt->pfc_flags |= DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
403 /* Ensure we have the correct type. */
404 switch (pkt->ptype) {
405 case DCERPC_PKT_BIND_NAK:
406 DEBUG(1, (__location__ ": Bind NACK received from %s!\n",
407 rpccli_pipe_txt(talloc_tos(), cli)));
409 ret = dcerpc_verify_ncacn_packet_header(pkt,
410 DCERPC_PKT_BIND_NAK,
411 0, /* max_auth_info */
412 DCERPC_PFC_FLAG_FIRST |
413 DCERPC_PFC_FLAG_LAST,
414 0); /* optional flags */
415 if (!NT_STATUS_IS_OK(ret)) {
416 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
417 "RPC packet type - %u, expected %u: %s\n",
418 rpccli_pipe_txt(talloc_tos(), cli),
419 pkt->ptype, expected_pkt_type,
420 nt_errstr(ret)));
421 NDR_PRINT_DEBUG(ncacn_packet, pkt);
422 return ret;
425 /* Use this for now... */
426 return NT_STATUS_NETWORK_ACCESS_DENIED;
428 case DCERPC_PKT_BIND_ACK:
429 ret = dcerpc_verify_ncacn_packet_header(pkt,
430 expected_pkt_type,
431 pkt->u.bind_ack.auth_info.length,
432 DCERPC_PFC_FLAG_FIRST |
433 DCERPC_PFC_FLAG_LAST,
434 DCERPC_PFC_FLAG_CONC_MPX |
435 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
436 if (!NT_STATUS_IS_OK(ret)) {
437 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
438 "RPC packet type - %u, expected %u: %s\n",
439 rpccli_pipe_txt(talloc_tos(), cli),
440 pkt->ptype, expected_pkt_type,
441 nt_errstr(ret)));
442 NDR_PRINT_DEBUG(ncacn_packet, pkt);
443 return ret;
446 break;
448 case DCERPC_PKT_ALTER_RESP:
449 ret = dcerpc_verify_ncacn_packet_header(pkt,
450 expected_pkt_type,
451 pkt->u.alter_resp.auth_info.length,
452 DCERPC_PFC_FLAG_FIRST |
453 DCERPC_PFC_FLAG_LAST,
454 DCERPC_PFC_FLAG_CONC_MPX |
455 DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN);
456 if (!NT_STATUS_IS_OK(ret)) {
457 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
458 "RPC packet type - %u, expected %u: %s\n",
459 rpccli_pipe_txt(talloc_tos(), cli),
460 pkt->ptype, expected_pkt_type,
461 nt_errstr(ret)));
462 NDR_PRINT_DEBUG(ncacn_packet, pkt);
463 return ret;
466 break;
468 case DCERPC_PKT_RESPONSE:
470 r = &pkt->u.response;
472 ret = dcerpc_verify_ncacn_packet_header(pkt,
473 expected_pkt_type,
474 r->stub_and_verifier.length,
475 0, /* required_flags */
476 DCERPC_PFC_FLAG_FIRST |
477 DCERPC_PFC_FLAG_LAST);
478 if (!NT_STATUS_IS_OK(ret)) {
479 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
480 "RPC packet type - %u, expected %u: %s\n",
481 rpccli_pipe_txt(talloc_tos(), cli),
482 pkt->ptype, expected_pkt_type,
483 nt_errstr(ret)));
484 NDR_PRINT_DEBUG(ncacn_packet, pkt);
485 return ret;
488 tmp_stub.data = r->stub_and_verifier.data;
489 tmp_stub.length = r->stub_and_verifier.length;
491 /* Here's where we deal with incoming sign/seal. */
492 ret = dcerpc_check_auth(cli->auth, pkt,
493 &tmp_stub,
494 DCERPC_RESPONSE_LENGTH,
495 pdu);
496 if (!NT_STATUS_IS_OK(ret)) {
497 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
498 "RPC packet type - %u, expected %u: %s\n",
499 rpccli_pipe_txt(talloc_tos(), cli),
500 pkt->ptype, expected_pkt_type,
501 nt_errstr(ret)));
502 NDR_PRINT_DEBUG(ncacn_packet, pkt);
503 return ret;
506 /* Point the return values at the NDR data. */
507 *rdata = tmp_stub;
509 DEBUG(10, ("Got pdu len %lu, data_len %lu\n",
510 (long unsigned int)pdu->length,
511 (long unsigned int)rdata->length));
514 * If this is the first reply, and the allocation hint is
515 * reasonable, try and set up the reply_pdu DATA_BLOB to the
516 * correct size.
519 if ((reply_pdu->length == 0) &&
520 r->alloc_hint && (r->alloc_hint < 15*1024*1024)) {
521 if (!data_blob_realloc(mem_ctx, reply_pdu,
522 r->alloc_hint)) {
523 DEBUG(0, ("reply alloc hint %d too "
524 "large to allocate\n",
525 (int)r->alloc_hint));
526 return NT_STATUS_NO_MEMORY;
530 break;
532 case DCERPC_PKT_FAULT:
534 ret = dcerpc_verify_ncacn_packet_header(pkt,
535 DCERPC_PKT_FAULT,
536 0, /* max_auth_info */
537 DCERPC_PFC_FLAG_FIRST |
538 DCERPC_PFC_FLAG_LAST,
539 DCERPC_PFC_FLAG_DID_NOT_EXECUTE);
540 if (!NT_STATUS_IS_OK(ret)) {
541 DEBUG(1, (__location__ ": Connection to %s got an unexpected "
542 "RPC packet type - %u, expected %u: %s\n",
543 rpccli_pipe_txt(talloc_tos(), cli),
544 pkt->ptype, expected_pkt_type,
545 nt_errstr(ret)));
546 NDR_PRINT_DEBUG(ncacn_packet, pkt);
547 return ret;
550 DEBUG(1, (__location__ ": RPC fault code %s received "
551 "from %s!\n",
552 dcerpc_errstr(talloc_tos(),
553 pkt->u.fault.status),
554 rpccli_pipe_txt(talloc_tos(), cli)));
556 return dcerpc_fault_to_nt_status(pkt->u.fault.status);
558 default:
559 DEBUG(0, (__location__ "Unknown packet type %u received "
560 "from %s!\n",
561 (unsigned int)pkt->ptype,
562 rpccli_pipe_txt(talloc_tos(), cli)));
563 return NT_STATUS_RPC_PROTOCOL_ERROR;
567 if (pkt->call_id != call_id) {
568 DEBUG(3, (__location__ ": Connection to %s got an unexpected "
569 "RPC call_id - %u, not %u\n",
570 rpccli_pipe_txt(talloc_tos(), cli),
571 pkt->call_id, call_id));
572 return NT_STATUS_RPC_PROTOCOL_ERROR;
575 return NT_STATUS_OK;
578 /****************************************************************************
579 Call a remote api on an arbitrary pipe. takes param, data and setup buffers.
580 ****************************************************************************/
582 struct cli_api_pipe_state {
583 struct tevent_context *ev;
584 struct rpc_cli_transport *transport;
585 uint8_t *rdata;
586 uint32_t rdata_len;
589 static void cli_api_pipe_trans_done(struct tevent_req *subreq);
590 static void cli_api_pipe_write_done(struct tevent_req *subreq);
591 static void cli_api_pipe_read_done(struct tevent_req *subreq);
593 static struct tevent_req *cli_api_pipe_send(TALLOC_CTX *mem_ctx,
594 struct tevent_context *ev,
595 struct rpc_cli_transport *transport,
596 uint8_t *data, size_t data_len,
597 uint32_t max_rdata_len)
599 struct tevent_req *req, *subreq;
600 struct cli_api_pipe_state *state;
602 req = tevent_req_create(mem_ctx, &state, struct cli_api_pipe_state);
603 if (req == NULL) {
604 return NULL;
606 state->ev = ev;
607 state->transport = transport;
609 if (max_rdata_len < RPC_HEADER_LEN) {
611 * For a RPC reply we always need at least RPC_HEADER_LEN
612 * bytes. We check this here because we will receive
613 * RPC_HEADER_LEN bytes in cli_trans_sock_send_done.
615 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
616 return tevent_req_post(req, ev);
619 if (transport->trans_send != NULL) {
620 subreq = transport->trans_send(state, ev, data, data_len,
621 max_rdata_len, transport->priv);
622 if (tevent_req_nomem(subreq, req)) {
623 return tevent_req_post(req, ev);
625 tevent_req_set_callback(subreq, cli_api_pipe_trans_done, req);
626 return req;
630 * If the transport does not provide a "trans" routine, i.e. for
631 * example the ncacn_ip_tcp transport, do the write/read step here.
634 subreq = rpc_write_send(state, ev, transport, data, data_len);
635 if (tevent_req_nomem(subreq, req)) {
636 return tevent_req_post(req, ev);
638 tevent_req_set_callback(subreq, cli_api_pipe_write_done, req);
639 return req;
642 static void cli_api_pipe_trans_done(struct tevent_req *subreq)
644 struct tevent_req *req = tevent_req_callback_data(
645 subreq, struct tevent_req);
646 struct cli_api_pipe_state *state = tevent_req_data(
647 req, struct cli_api_pipe_state);
648 NTSTATUS status;
650 status = state->transport->trans_recv(subreq, state, &state->rdata,
651 &state->rdata_len);
652 TALLOC_FREE(subreq);
653 if (tevent_req_nterror(req, status)) {
654 return;
656 tevent_req_done(req);
659 static void cli_api_pipe_write_done(struct tevent_req *subreq)
661 struct tevent_req *req = tevent_req_callback_data(
662 subreq, struct tevent_req);
663 struct cli_api_pipe_state *state = tevent_req_data(
664 req, struct cli_api_pipe_state);
665 NTSTATUS status;
667 status = rpc_write_recv(subreq);
668 TALLOC_FREE(subreq);
669 if (tevent_req_nterror(req, status)) {
670 return;
673 state->rdata = talloc_array(state, uint8_t, RPC_HEADER_LEN);
674 if (tevent_req_nomem(state->rdata, req)) {
675 return;
679 * We don't need to use rpc_read_send here, the upper layer will cope
680 * with a short read, transport->trans_send could also return less
681 * than state->max_rdata_len.
683 subreq = state->transport->read_send(state, state->ev, state->rdata,
684 RPC_HEADER_LEN,
685 state->transport->priv);
686 if (tevent_req_nomem(subreq, req)) {
687 return;
689 tevent_req_set_callback(subreq, cli_api_pipe_read_done, req);
692 static void cli_api_pipe_read_done(struct tevent_req *subreq)
694 struct tevent_req *req = tevent_req_callback_data(
695 subreq, struct tevent_req);
696 struct cli_api_pipe_state *state = tevent_req_data(
697 req, struct cli_api_pipe_state);
698 NTSTATUS status;
699 ssize_t received;
701 status = state->transport->read_recv(subreq, &received);
702 TALLOC_FREE(subreq);
703 if (tevent_req_nterror(req, status)) {
704 return;
706 state->rdata_len = received;
707 tevent_req_done(req);
710 static NTSTATUS cli_api_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
711 uint8_t **prdata, uint32_t *prdata_len)
713 struct cli_api_pipe_state *state = tevent_req_data(
714 req, struct cli_api_pipe_state);
715 NTSTATUS status;
717 if (tevent_req_is_nterror(req, &status)) {
718 return status;
721 *prdata = talloc_move(mem_ctx, &state->rdata);
722 *prdata_len = state->rdata_len;
723 return NT_STATUS_OK;
726 /****************************************************************************
727 Send data on an rpc pipe via trans. The data must be the last
728 pdu fragment of an NDR data stream.
730 Receive response data from an rpc pipe, which may be large...
732 Read the first fragment: unfortunately have to use SMBtrans for the first
733 bit, then SMBreadX for subsequent bits.
735 If first fragment received also wasn't the last fragment, continue
736 getting fragments until we _do_ receive the last fragment.
738 Request/Response PDU's look like the following...
740 |<------------------PDU len----------------------------------------------->|
741 |<-HDR_LEN-->|<--REQ LEN------>|.............|<-AUTH_HDRLEN->|<-AUTH_LEN-->|
743 +------------+-----------------+-------------+---------------+-------------+
744 | RPC HEADER | REQ/RESP HEADER | DATA ...... | AUTH_HDR | AUTH DATA |
745 +------------+-----------------+-------------+---------------+-------------+
747 Where the presence of the AUTH_HDR and AUTH DATA are dependent on the
748 signing & sealing being negotiated.
750 ****************************************************************************/
752 struct rpc_api_pipe_state {
753 struct tevent_context *ev;
754 struct rpc_pipe_client *cli;
755 uint8_t expected_pkt_type;
756 uint32_t call_id;
758 DATA_BLOB incoming_frag;
759 struct ncacn_packet *pkt;
761 /* Incoming reply */
762 DATA_BLOB reply_pdu;
763 size_t reply_pdu_offset;
764 uint8_t endianess;
767 static void rpc_api_pipe_trans_done(struct tevent_req *subreq);
768 static void rpc_api_pipe_got_pdu(struct tevent_req *subreq);
769 static void rpc_api_pipe_auth3_done(struct tevent_req *subreq);
771 static struct tevent_req *rpc_api_pipe_send(TALLOC_CTX *mem_ctx,
772 struct tevent_context *ev,
773 struct rpc_pipe_client *cli,
774 DATA_BLOB *data, /* Outgoing PDU */
775 uint8_t expected_pkt_type,
776 uint32_t call_id)
778 struct tevent_req *req, *subreq;
779 struct rpc_api_pipe_state *state;
780 uint16_t max_recv_frag;
782 req = tevent_req_create(mem_ctx, &state, struct rpc_api_pipe_state);
783 if (req == NULL) {
784 return NULL;
786 state->ev = ev;
787 state->cli = cli;
788 state->expected_pkt_type = expected_pkt_type;
789 state->call_id = call_id;
790 state->endianess = DCERPC_DREP_LE;
793 * Ensure we're not sending too much.
795 if (data->length > cli->max_xmit_frag) {
796 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
797 return tevent_req_post(req, ev);
800 DEBUG(5,("rpc_api_pipe: %s\n", rpccli_pipe_txt(talloc_tos(), cli)));
802 if (state->expected_pkt_type == DCERPC_PKT_AUTH3) {
803 subreq = rpc_write_send(state, ev, cli->transport,
804 data->data, data->length);
805 if (tevent_req_nomem(subreq, req)) {
806 return tevent_req_post(req, ev);
808 tevent_req_set_callback(subreq, rpc_api_pipe_auth3_done, req);
809 return req;
812 /* get the header first, then fetch the rest once we have
813 * the frag_length available */
814 max_recv_frag = RPC_HEADER_LEN;
816 subreq = cli_api_pipe_send(state, ev, cli->transport,
817 data->data, data->length, max_recv_frag);
818 if (tevent_req_nomem(subreq, req)) {
819 return tevent_req_post(req, ev);
821 tevent_req_set_callback(subreq, rpc_api_pipe_trans_done, req);
822 return req;
825 static void rpc_api_pipe_auth3_done(struct tevent_req *subreq)
827 NTSTATUS status = rpc_write_recv(subreq);
828 return tevent_req_simple_finish_ntstatus(subreq, status);
831 static void rpc_api_pipe_trans_done(struct tevent_req *subreq)
833 struct tevent_req *req = tevent_req_callback_data(
834 subreq, struct tevent_req);
835 struct rpc_api_pipe_state *state = tevent_req_data(
836 req, struct rpc_api_pipe_state);
837 NTSTATUS status;
838 uint8_t *rdata = NULL;
839 uint32_t rdata_len = 0;
841 status = cli_api_pipe_recv(subreq, state, &rdata, &rdata_len);
842 TALLOC_FREE(subreq);
843 if (tevent_req_nterror(req, status)) {;
844 DEBUG(5, ("cli_api_pipe failed: %s\n", nt_errstr(status)));
845 return;
848 if (rdata == NULL) {
849 DEBUG(3,("rpc_api_pipe: %s failed to return data.\n",
850 rpccli_pipe_txt(talloc_tos(), state->cli)));
851 tevent_req_done(req);
852 return;
856 * Move data on state->incoming_frag.
858 state->incoming_frag.data = talloc_move(state, &rdata);
859 state->incoming_frag.length = rdata_len;
860 if (!state->incoming_frag.data) {
861 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
862 return;
865 /* Ensure we have enough data for a pdu. */
866 subreq = get_complete_frag_send(state, state->ev, state->cli,
867 &state->incoming_frag);
868 if (tevent_req_nomem(subreq, req)) {
869 return;
871 tevent_req_set_callback(subreq, rpc_api_pipe_got_pdu, req);
874 static void rpc_api_pipe_got_pdu(struct tevent_req *subreq)
876 struct tevent_req *req = tevent_req_callback_data(
877 subreq, struct tevent_req);
878 struct rpc_api_pipe_state *state = tevent_req_data(
879 req, struct rpc_api_pipe_state);
880 NTSTATUS status;
881 DATA_BLOB rdata = { .data = NULL };
883 status = get_complete_frag_recv(subreq);
884 TALLOC_FREE(subreq);
885 if (tevent_req_nterror(req, status)) {
886 DEBUG(5, ("get_complete_frag failed: %s\n",
887 nt_errstr(status)));
888 return;
891 state->pkt = talloc(state, struct ncacn_packet);
892 if (!state->pkt) {
894 * TODO: do a real async disconnect ...
896 * For now do it sync...
898 TALLOC_FREE(state->cli->transport);
899 tevent_req_oom(req);
900 return;
903 status = dcerpc_pull_ncacn_packet(state->pkt,
904 &state->incoming_frag,
905 state->pkt);
906 if (tevent_req_nterror(req, status)) {
908 * TODO: do a real async disconnect ...
910 * For now do it sync...
912 TALLOC_FREE(state->cli->transport);
913 return;
916 if (DEBUGLEVEL >= 10) {
917 NDR_PRINT_DEBUG(ncacn_packet, state->pkt);
920 status = cli_pipe_validate_current_pdu(state,
921 state->cli, state->pkt,
922 &state->incoming_frag,
923 state->expected_pkt_type,
924 state->call_id,
925 &rdata,
926 &state->reply_pdu);
928 DBG_DEBUG("got frag len of %zu at offset %zu: %s\n",
929 state->incoming_frag.length,
930 state->reply_pdu_offset,
931 nt_errstr(status));
933 if (state->pkt->ptype != DCERPC_PKT_FAULT && !NT_STATUS_IS_OK(status)) {
935 * TODO: do a real async disconnect ...
937 * For now do it sync...
939 TALLOC_FREE(state->cli->transport);
940 } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_PROTOCOL_ERROR)) {
942 * TODO: do a real async disconnect ...
944 * For now do it sync...
946 TALLOC_FREE(state->cli->transport);
947 } else if (NT_STATUS_EQUAL(status, NT_STATUS_RPC_SEC_PKG_ERROR)) {
949 * TODO: do a real async disconnect ...
951 * For now do it sync...
953 TALLOC_FREE(state->cli->transport);
955 if (tevent_req_nterror(req, status)) {
956 return;
959 if ((state->pkt->pfc_flags & DCERPC_PFC_FLAG_FIRST)
960 && (state->pkt->drep[0] != DCERPC_DREP_LE)) {
962 * Set the data type correctly for big-endian data on the
963 * first packet.
965 DEBUG(10,("rpc_api_pipe: On %s PDU data format is "
966 "big-endian.\n",
967 rpccli_pipe_txt(talloc_tos(), state->cli)));
968 state->endianess = 0x00; /* BIG ENDIAN */
971 * Check endianness on subsequent packets.
973 if (state->endianess != state->pkt->drep[0]) {
974 DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to "
975 "%s\n",
976 state->endianess?"little":"big",
977 state->pkt->drep[0]?"little":"big"));
979 * TODO: do a real async disconnect ...
981 * For now do it sync...
983 TALLOC_FREE(state->cli->transport);
984 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
985 return;
988 if (state->reply_pdu_offset + rdata.length > MAX_RPC_DATA_SIZE) {
990 * TODO: do a real async disconnect ...
992 * For now do it sync...
994 TALLOC_FREE(state->cli->transport);
995 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
996 return;
999 /* Now copy the data portion out of the pdu into rbuf. */
1000 if (state->reply_pdu.length < state->reply_pdu_offset + rdata.length) {
1001 if (!data_blob_realloc(NULL, &state->reply_pdu,
1002 state->reply_pdu_offset + rdata.length)) {
1004 * TODO: do a real async disconnect ...
1006 * For now do it sync...
1008 TALLOC_FREE(state->cli->transport);
1009 tevent_req_oom(req);
1010 return;
1014 memcpy(state->reply_pdu.data + state->reply_pdu_offset,
1015 rdata.data, rdata.length);
1016 state->reply_pdu_offset += rdata.length;
1018 /* reset state->incoming_frag, there is no need to free it,
1019 * it will be reallocated to the right size the next time
1020 * it is used */
1021 state->incoming_frag.length = 0;
1023 if (state->pkt->pfc_flags & DCERPC_PFC_FLAG_LAST) {
1024 /* make sure the pdu length is right now that we
1025 * have all the data available (alloc hint may
1026 * have allocated more than was actually used) */
1027 state->reply_pdu.length = state->reply_pdu_offset;
1028 DEBUG(10,("rpc_api_pipe: %s returned %u bytes.\n",
1029 rpccli_pipe_txt(talloc_tos(), state->cli),
1030 (unsigned)state->reply_pdu.length));
1031 tevent_req_done(req);
1032 return;
1035 subreq = get_complete_frag_send(state, state->ev, state->cli,
1036 &state->incoming_frag);
1037 if (subreq == NULL) {
1039 * TODO: do a real async disconnect ...
1041 * For now do it sync...
1043 TALLOC_FREE(state->cli->transport);
1045 if (tevent_req_nomem(subreq, req)) {
1046 return;
1048 tevent_req_set_callback(subreq, rpc_api_pipe_got_pdu, req);
1051 static NTSTATUS rpc_api_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1052 struct ncacn_packet **pkt,
1053 DATA_BLOB *reply_pdu)
1055 struct rpc_api_pipe_state *state = tevent_req_data(
1056 req, struct rpc_api_pipe_state);
1057 NTSTATUS status;
1059 if (tevent_req_is_nterror(req, &status)) {
1060 return status;
1063 /* return data to caller and assign it ownership of memory */
1064 if (reply_pdu) {
1065 reply_pdu->data = talloc_move(mem_ctx, &state->reply_pdu.data);
1066 reply_pdu->length = state->reply_pdu.length;
1067 state->reply_pdu.length = 0;
1068 } else {
1069 data_blob_free(&state->reply_pdu);
1072 if (pkt) {
1073 *pkt = talloc_steal(mem_ctx, state->pkt);
1076 return NT_STATUS_OK;
1079 /*******************************************************************
1080 Creates NTLMSSP auth bind.
1081 ********************************************************************/
1083 static NTSTATUS create_generic_auth_rpc_bind_req(struct rpc_pipe_client *cli,
1084 TALLOC_CTX *mem_ctx,
1085 DATA_BLOB *auth_token,
1086 bool *client_hdr_signing)
1088 struct gensec_security *gensec_security;
1089 DATA_BLOB null_blob = { .data = NULL };
1090 NTSTATUS status;
1092 gensec_security = cli->auth->auth_ctx;
1094 DEBUG(5, ("create_generic_auth_rpc_bind_req: generate first token\n"));
1095 status = gensec_update(gensec_security, mem_ctx, null_blob, auth_token);
1097 if (!NT_STATUS_IS_OK(status) &&
1098 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED))
1100 return status;
1103 if (client_hdr_signing == NULL) {
1104 return status;
1107 if (cli->auth->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1108 *client_hdr_signing = false;
1109 return status;
1112 *client_hdr_signing = gensec_have_feature(gensec_security,
1113 GENSEC_FEATURE_SIGN_PKT_HEADER);
1115 return status;
1118 /*******************************************************************
1119 Creates the internals of a DCE/RPC bind request or alter context PDU.
1120 ********************************************************************/
1122 static NTSTATUS create_bind_or_alt_ctx_internal(TALLOC_CTX *mem_ctx,
1123 enum dcerpc_pkt_type ptype,
1124 uint32_t rpc_call_id,
1125 const struct ndr_syntax_id *abstract,
1126 const struct ndr_syntax_id *transfer,
1127 const DATA_BLOB *auth_info,
1128 bool client_hdr_signing,
1129 DATA_BLOB *blob)
1131 uint16_t auth_len = auth_info->length;
1132 NTSTATUS status;
1133 struct dcerpc_ctx_list ctx_list = {
1134 .context_id = 0,
1135 .num_transfer_syntaxes = 1,
1136 .abstract_syntax = *abstract,
1137 .transfer_syntaxes = (struct ndr_syntax_id *)discard_const(transfer),
1139 union dcerpc_payload u = {
1140 .bind.max_xmit_frag = RPC_MAX_PDU_FRAG_LEN,
1141 .bind.max_recv_frag = RPC_MAX_PDU_FRAG_LEN,
1142 .bind.num_contexts = 1,
1143 .bind.ctx_list = &ctx_list,
1144 .bind.auth_info = *auth_info,
1146 uint8_t pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1148 if (auth_len) {
1149 auth_len -= DCERPC_AUTH_TRAILER_LENGTH;
1152 if (client_hdr_signing) {
1153 pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1156 status = dcerpc_push_ncacn_packet(mem_ctx,
1157 ptype, pfc_flags,
1158 auth_len,
1159 rpc_call_id,
1161 blob);
1162 if (!NT_STATUS_IS_OK(status)) {
1163 DEBUG(0, ("Failed to marshall bind/alter ncacn_packet.\n"));
1164 return status;
1167 return NT_STATUS_OK;
1170 /*******************************************************************
1171 Creates a DCE/RPC bind request.
1172 ********************************************************************/
1174 static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx,
1175 struct rpc_pipe_client *cli,
1176 struct pipe_auth_data *auth,
1177 uint32_t rpc_call_id,
1178 const struct ndr_syntax_id *abstract,
1179 const struct ndr_syntax_id *transfer,
1180 DATA_BLOB *rpc_out)
1182 DATA_BLOB auth_token = { .data = NULL };
1183 DATA_BLOB auth_info = { .data = NULL };
1184 NTSTATUS ret;
1186 if (auth->auth_type != DCERPC_AUTH_TYPE_NONE) {
1187 ret = create_generic_auth_rpc_bind_req(
1188 cli, mem_ctx, &auth_token, &auth->client_hdr_signing);
1190 if (!NT_STATUS_IS_OK(ret) &&
1191 !NT_STATUS_EQUAL(ret, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1192 return ret;
1196 if (auth_token.length != 0) {
1197 ret = dcerpc_push_dcerpc_auth(cli,
1198 auth->auth_type,
1199 auth->auth_level,
1200 0, /* auth_pad_length */
1201 auth->auth_context_id,
1202 &auth_token,
1203 &auth_info);
1204 if (!NT_STATUS_IS_OK(ret)) {
1205 return ret;
1207 data_blob_free(&auth_token);
1210 ret = create_bind_or_alt_ctx_internal(mem_ctx,
1211 DCERPC_PKT_BIND,
1212 rpc_call_id,
1213 abstract,
1214 transfer,
1215 &auth_info,
1216 auth->client_hdr_signing,
1217 rpc_out);
1218 data_blob_free(&auth_info);
1220 return ret;
1223 /*******************************************************************
1224 External interface.
1225 Does an rpc request on a pipe. Incoming data is NDR encoded in in_data.
1226 Reply is NDR encoded in out_data. Splits the data stream into RPC PDU's
1227 and deals with signing/sealing details.
1228 ********************************************************************/
1230 struct rpc_api_pipe_req_state {
1231 struct tevent_context *ev;
1232 struct rpc_pipe_client *cli;
1233 uint8_t op_num;
1234 uint32_t call_id;
1235 const DATA_BLOB *req_data;
1236 const struct GUID *object_uuid;
1237 uint32_t req_data_sent;
1238 DATA_BLOB req_trailer;
1239 uint32_t req_trailer_sent;
1240 bool verify_bitmask1;
1241 bool verify_pcontext;
1242 DATA_BLOB rpc_out;
1243 DATA_BLOB reply_pdu;
1246 static void rpc_api_pipe_req_write_done(struct tevent_req *subreq);
1247 static void rpc_api_pipe_req_done(struct tevent_req *subreq);
1248 static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state);
1249 static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
1250 bool *is_last_frag);
1252 static struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
1253 struct tevent_context *ev,
1254 struct rpc_pipe_client *cli,
1255 uint8_t op_num,
1256 const struct GUID *object_uuid,
1257 const DATA_BLOB *req_data)
1259 struct tevent_req *req, *subreq;
1260 struct rpc_api_pipe_req_state *state;
1261 NTSTATUS status;
1262 bool is_last_frag;
1264 req = tevent_req_create(mem_ctx, &state,
1265 struct rpc_api_pipe_req_state);
1266 if (req == NULL) {
1267 return NULL;
1269 state->ev = ev;
1270 state->cli = cli;
1271 state->op_num = op_num;
1272 state->object_uuid = object_uuid;
1273 state->req_data = req_data;
1274 state->call_id = get_rpc_call_id();
1276 if (cli->max_xmit_frag < DCERPC_REQUEST_LENGTH
1277 + RPC_MAX_SIGN_SIZE) {
1278 /* Server is screwed up ! */
1279 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1280 return tevent_req_post(req, ev);
1283 status = prepare_verification_trailer(state);
1284 if (tevent_req_nterror(req, status)) {
1285 return tevent_req_post(req, ev);
1288 status = prepare_next_frag(state, &is_last_frag);
1289 if (tevent_req_nterror(req, status)) {
1290 return tevent_req_post(req, ev);
1293 if (is_last_frag) {
1294 subreq = rpc_api_pipe_send(state, ev, state->cli,
1295 &state->rpc_out,
1296 DCERPC_PKT_RESPONSE,
1297 state->call_id);
1298 if (tevent_req_nomem(subreq, req)) {
1299 return tevent_req_post(req, ev);
1301 tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req);
1302 } else {
1303 subreq = rpc_write_send(state, ev, cli->transport,
1304 state->rpc_out.data,
1305 state->rpc_out.length);
1306 if (tevent_req_nomem(subreq, req)) {
1307 return tevent_req_post(req, ev);
1309 tevent_req_set_callback(subreq, rpc_api_pipe_req_write_done,
1310 req);
1312 return req;
1315 static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state)
1317 struct pipe_auth_data *a = state->cli->auth;
1318 struct dcerpc_sec_verification_trailer *t;
1319 struct ndr_push *ndr = NULL;
1320 enum ndr_err_code ndr_err;
1321 size_t align = 0;
1322 size_t pad = 0;
1324 if (a == NULL) {
1325 return NT_STATUS_OK;
1328 if (a->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1329 return NT_STATUS_OK;
1332 t = talloc_zero(state, struct dcerpc_sec_verification_trailer);
1333 if (t == NULL) {
1334 return NT_STATUS_NO_MEMORY;
1337 if (!a->verified_bitmask1) {
1338 t->commands = talloc_realloc(t, t->commands,
1339 struct dcerpc_sec_vt,
1340 t->count.count + 1);
1341 if (t->commands == NULL) {
1342 return NT_STATUS_NO_MEMORY;
1344 t->commands[t->count.count++] = (struct dcerpc_sec_vt) {
1345 .command = DCERPC_SEC_VT_COMMAND_BITMASK1,
1346 .u.bitmask1 = (a->client_hdr_signing) ?
1347 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING :
1350 state->verify_bitmask1 = true;
1353 if (!state->cli->verified_pcontext) {
1354 t->commands = talloc_realloc(t, t->commands,
1355 struct dcerpc_sec_vt,
1356 t->count.count + 1);
1357 if (t->commands == NULL) {
1358 return NT_STATUS_NO_MEMORY;
1360 t->commands[t->count.count++] = (struct dcerpc_sec_vt) {
1361 .command = DCERPC_SEC_VT_COMMAND_PCONTEXT,
1362 .u.pcontext.abstract_syntax =
1363 state->cli->abstract_syntax,
1364 .u.pcontext.transfer_syntax =
1365 state->cli->transfer_syntax,
1367 state->verify_pcontext = true;
1370 if (!a->hdr_signing) {
1371 t->commands = talloc_realloc(t, t->commands,
1372 struct dcerpc_sec_vt,
1373 t->count.count + 1);
1374 if (t->commands == NULL) {
1375 return NT_STATUS_NO_MEMORY;
1377 t->commands[t->count.count++] = (struct dcerpc_sec_vt) {
1378 .command = DCERPC_SEC_VT_COMMAND_HEADER2,
1379 .u.header2.ptype = DCERPC_PKT_REQUEST,
1380 .u.header2.drep[0] = DCERPC_DREP_LE,
1381 .u.header2.call_id = state->call_id,
1382 .u.header2.context_id = 0,
1383 .u.header2.opnum = state->op_num,
1387 if (t->count.count == 0) {
1388 TALLOC_FREE(t);
1389 return NT_STATUS_OK;
1392 t->commands[t->count.count - 1].command |= DCERPC_SEC_VT_COMMAND_END;
1394 if (DEBUGLEVEL >= 10) {
1395 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1398 ndr = ndr_push_init_ctx(state);
1399 if (ndr == NULL) {
1400 return NT_STATUS_NO_MEMORY;
1403 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1404 NDR_SCALARS | NDR_BUFFERS,
1406 TALLOC_FREE(t);
1407 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1408 return ndr_map_error2ntstatus(ndr_err);
1410 state->req_trailer = ndr_push_blob(ndr);
1412 align = state->req_data->length & 0x3;
1413 if (align > 0) {
1414 pad = 4 - align;
1416 if (pad > 0) {
1417 bool ok;
1418 uint8_t *p;
1419 const uint8_t zeros[4] = { 0, };
1421 ok = data_blob_append(ndr, &state->req_trailer, zeros, pad);
1422 if (!ok) {
1423 return NT_STATUS_NO_MEMORY;
1426 /* move the padding to the start */
1427 p = state->req_trailer.data;
1428 memmove(p + pad, p, state->req_trailer.length - pad);
1429 memset(p, 0, pad);
1432 return NT_STATUS_OK;
1435 static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
1436 bool *is_last_frag)
1438 size_t auth_len;
1439 size_t frag_len;
1440 uint8_t flags = 0;
1441 size_t pad_len;
1442 size_t data_left;
1443 size_t data_thistime;
1444 size_t trailer_left;
1445 size_t trailer_thistime = 0;
1446 size_t total_left;
1447 size_t total_thistime;
1448 NTSTATUS status;
1449 bool ok;
1450 union dcerpc_payload u;
1452 data_left = state->req_data->length - state->req_data_sent;
1453 trailer_left = state->req_trailer.length - state->req_trailer_sent;
1454 total_left = data_left + trailer_left;
1455 if ((total_left < data_left) || (total_left < trailer_left)) {
1457 * overflow
1459 return NT_STATUS_INVALID_PARAMETER_MIX;
1462 status = dcerpc_guess_sizes(state->cli->auth,
1463 DCERPC_REQUEST_LENGTH, total_left,
1464 state->cli->max_xmit_frag,
1465 &total_thistime,
1466 &frag_len, &auth_len, &pad_len);
1467 if (!NT_STATUS_IS_OK(status)) {
1468 return status;
1471 if (state->req_data_sent == 0) {
1472 flags = DCERPC_PFC_FLAG_FIRST;
1475 if (total_thistime == total_left) {
1476 flags |= DCERPC_PFC_FLAG_LAST;
1479 data_thistime = MIN(total_thistime, data_left);
1480 if (data_thistime < total_thistime) {
1481 trailer_thistime = total_thistime - data_thistime;
1484 data_blob_free(&state->rpc_out);
1486 u = (union dcerpc_payload) {
1487 .request.alloc_hint = total_left,
1488 .request.context_id = 0,
1489 .request.opnum = state->op_num,
1492 if (state->object_uuid) {
1493 flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1494 u.request.object.object = *state->object_uuid;
1495 frag_len += ndr_size_GUID(state->object_uuid, 0);
1498 status = dcerpc_push_ncacn_packet(state,
1499 DCERPC_PKT_REQUEST,
1500 flags,
1501 auth_len,
1502 state->call_id,
1504 &state->rpc_out);
1505 if (!NT_STATUS_IS_OK(status)) {
1506 return status;
1509 /* explicitly set frag_len here as dcerpc_push_ncacn_packet() can't
1510 * compute it right for requests because the auth trailer is missing
1511 * at this stage */
1512 dcerpc_set_frag_length(&state->rpc_out, frag_len);
1514 if (data_thistime > 0) {
1515 /* Copy in the data. */
1516 ok = data_blob_append(NULL, &state->rpc_out,
1517 state->req_data->data + state->req_data_sent,
1518 data_thistime);
1519 if (!ok) {
1520 return NT_STATUS_NO_MEMORY;
1522 state->req_data_sent += data_thistime;
1525 if (trailer_thistime > 0) {
1526 /* Copy in the verification trailer. */
1527 ok = data_blob_append(NULL, &state->rpc_out,
1528 state->req_trailer.data + state->req_trailer_sent,
1529 trailer_thistime);
1530 if (!ok) {
1531 return NT_STATUS_NO_MEMORY;
1533 state->req_trailer_sent += trailer_thistime;
1536 switch (state->cli->auth->auth_level) {
1537 case DCERPC_AUTH_LEVEL_NONE:
1538 case DCERPC_AUTH_LEVEL_CONNECT:
1539 break;
1540 case DCERPC_AUTH_LEVEL_PACKET:
1541 case DCERPC_AUTH_LEVEL_INTEGRITY:
1542 case DCERPC_AUTH_LEVEL_PRIVACY:
1543 status = dcerpc_add_auth_footer(state->cli->auth, pad_len,
1544 &state->rpc_out);
1545 if (!NT_STATUS_IS_OK(status)) {
1546 return status;
1548 break;
1549 default:
1550 return NT_STATUS_INVALID_PARAMETER;
1553 *is_last_frag = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
1555 return status;
1558 static void rpc_api_pipe_req_write_done(struct tevent_req *subreq)
1560 struct tevent_req *req = tevent_req_callback_data(
1561 subreq, struct tevent_req);
1562 struct rpc_api_pipe_req_state *state = tevent_req_data(
1563 req, struct rpc_api_pipe_req_state);
1564 NTSTATUS status;
1565 bool is_last_frag;
1567 status = rpc_write_recv(subreq);
1568 TALLOC_FREE(subreq);
1569 if (tevent_req_nterror(req, status)) {
1570 return;
1573 status = prepare_next_frag(state, &is_last_frag);
1574 if (tevent_req_nterror(req, status)) {
1575 return;
1578 if (is_last_frag) {
1579 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
1580 &state->rpc_out,
1581 DCERPC_PKT_RESPONSE,
1582 state->call_id);
1583 if (tevent_req_nomem(subreq, req)) {
1584 return;
1586 tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req);
1587 } else {
1588 subreq = rpc_write_send(state, state->ev,
1589 state->cli->transport,
1590 state->rpc_out.data,
1591 state->rpc_out.length);
1592 if (tevent_req_nomem(subreq, req)) {
1593 return;
1595 tevent_req_set_callback(subreq, rpc_api_pipe_req_write_done,
1596 req);
1600 static void rpc_api_pipe_req_done(struct tevent_req *subreq)
1602 struct tevent_req *req = tevent_req_callback_data(
1603 subreq, struct tevent_req);
1604 struct rpc_api_pipe_req_state *state = tevent_req_data(
1605 req, struct rpc_api_pipe_req_state);
1606 NTSTATUS status;
1608 status = rpc_api_pipe_recv(subreq, state, NULL, &state->reply_pdu);
1609 TALLOC_FREE(subreq);
1610 if (tevent_req_nterror(req, status)) {
1611 return;
1614 if (state->cli->auth == NULL) {
1615 tevent_req_done(req);
1616 return;
1619 if (state->verify_bitmask1) {
1620 state->cli->auth->verified_bitmask1 = true;
1623 if (state->verify_pcontext) {
1624 state->cli->verified_pcontext = true;
1627 tevent_req_done(req);
1630 static NTSTATUS rpc_api_pipe_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1631 DATA_BLOB *reply_pdu)
1633 struct rpc_api_pipe_req_state *state = tevent_req_data(
1634 req, struct rpc_api_pipe_req_state);
1635 NTSTATUS status;
1637 if (tevent_req_is_nterror(req, &status)) {
1639 * We always have to initialize to reply pdu, even if there is
1640 * none. The rpccli_* caller routines expect this.
1642 *reply_pdu = data_blob_null;
1643 return status;
1646 /* return data to caller and assign it ownership of memory */
1647 reply_pdu->data = talloc_move(mem_ctx, &state->reply_pdu.data);
1648 reply_pdu->length = state->reply_pdu.length;
1649 state->reply_pdu.length = 0;
1651 return NT_STATUS_OK;
1654 /****************************************************************************
1655 Check the rpc bind acknowledge response.
1656 ****************************************************************************/
1658 static bool check_bind_response(const struct dcerpc_bind_ack *r,
1659 const struct ndr_syntax_id *transfer)
1661 struct dcerpc_ack_ctx ctx;
1662 bool equal;
1664 if (r->secondary_address_size == 0) {
1665 DEBUG(4,("Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly)"));
1668 if (r->num_results < 1 || !r->ctx_list) {
1669 return false;
1672 ctx = r->ctx_list[0];
1674 /* check the transfer syntax */
1675 equal = ndr_syntax_id_equal(&ctx.syntax, transfer);
1676 if (!equal) {
1677 DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n"));
1678 return False;
1681 if (r->num_results != 0x1 || ctx.result != 0) {
1682 DEBUG(2,("bind_rpc_pipe: bind denied results: %d reason: %x\n",
1683 r->num_results, ctx.reason.value));
1686 DEBUG(5,("check_bind_response: accepted!\n"));
1687 return True;
1690 /*******************************************************************
1691 Creates a DCE/RPC bind authentication response.
1692 This is the packet that is sent back to the server once we
1693 have received a BIND-ACK, to finish the third leg of
1694 the authentication handshake.
1695 ********************************************************************/
1697 static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
1698 struct rpc_pipe_client *cli,
1699 struct pipe_auth_data *auth,
1700 uint32_t rpc_call_id,
1701 DATA_BLOB *pauth_blob,
1702 DATA_BLOB *rpc_out)
1704 NTSTATUS status;
1705 union dcerpc_payload u = { .auth3._pad = 0, };
1707 status = dcerpc_push_dcerpc_auth(mem_ctx,
1708 auth->auth_type,
1709 auth->auth_level,
1710 0, /* auth_pad_length */
1711 auth->auth_context_id,
1712 pauth_blob,
1713 &u.auth3.auth_info);
1714 if (!NT_STATUS_IS_OK(status)) {
1715 return status;
1718 status = dcerpc_push_ncacn_packet(mem_ctx,
1719 DCERPC_PKT_AUTH3,
1720 DCERPC_PFC_FLAG_FIRST |
1721 DCERPC_PFC_FLAG_LAST,
1722 pauth_blob->length,
1723 rpc_call_id,
1725 rpc_out);
1726 data_blob_free(&u.auth3.auth_info);
1727 if (!NT_STATUS_IS_OK(status)) {
1728 DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR_RB.\n"));
1729 return status;
1732 return NT_STATUS_OK;
1735 /*******************************************************************
1736 Creates a DCE/RPC bind alter context authentication request which
1737 may contain a spnego auth blob
1738 ********************************************************************/
1740 static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
1741 struct pipe_auth_data *auth,
1742 uint32_t rpc_call_id,
1743 const struct ndr_syntax_id *abstract,
1744 const struct ndr_syntax_id *transfer,
1745 const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
1746 DATA_BLOB *rpc_out)
1748 DATA_BLOB auth_info;
1749 NTSTATUS status;
1751 status = dcerpc_push_dcerpc_auth(mem_ctx,
1752 auth->auth_type,
1753 auth->auth_level,
1754 0, /* auth_pad_length */
1755 auth->auth_context_id,
1756 pauth_blob,
1757 &auth_info);
1758 if (!NT_STATUS_IS_OK(status)) {
1759 return status;
1762 status = create_bind_or_alt_ctx_internal(mem_ctx,
1763 DCERPC_PKT_ALTER,
1764 rpc_call_id,
1765 abstract,
1766 transfer,
1767 &auth_info,
1768 false, /* client_hdr_signing */
1769 rpc_out);
1770 data_blob_free(&auth_info);
1771 return status;
1774 /****************************************************************************
1775 Do an rpc bind.
1776 ****************************************************************************/
1778 struct rpc_pipe_bind_state {
1779 struct tevent_context *ev;
1780 struct rpc_pipe_client *cli;
1781 DATA_BLOB rpc_out;
1782 bool auth3;
1783 uint32_t rpc_call_id;
1786 static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq);
1787 static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
1788 struct rpc_pipe_bind_state *state,
1789 DATA_BLOB *credentials);
1790 static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
1791 struct rpc_pipe_bind_state *state,
1792 DATA_BLOB *credentials);
1794 struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx,
1795 struct tevent_context *ev,
1796 struct rpc_pipe_client *cli,
1797 struct pipe_auth_data *auth)
1799 struct tevent_req *req, *subreq;
1800 struct rpc_pipe_bind_state *state;
1801 NTSTATUS status;
1803 req = tevent_req_create(mem_ctx, &state, struct rpc_pipe_bind_state);
1804 if (req == NULL) {
1805 return NULL;
1808 DEBUG(5,("Bind RPC Pipe: %s auth_type %u, auth_level %u\n",
1809 rpccli_pipe_txt(talloc_tos(), cli),
1810 (unsigned int)auth->auth_type,
1811 (unsigned int)auth->auth_level ));
1813 state->ev = ev;
1814 state->cli = cli;
1815 state->rpc_call_id = get_rpc_call_id();
1817 cli->auth = talloc_move(cli, &auth);
1819 /* Marshall the outgoing data. */
1820 status = create_rpc_bind_req(state, cli,
1821 cli->auth,
1822 state->rpc_call_id,
1823 &cli->abstract_syntax,
1824 &cli->transfer_syntax,
1825 &state->rpc_out);
1827 if (!NT_STATUS_IS_OK(status) &&
1828 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1829 tevent_req_nterror(req, status);
1830 return tevent_req_post(req, ev);
1833 subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
1834 DCERPC_PKT_BIND_ACK, state->rpc_call_id);
1835 if (tevent_req_nomem(subreq, req)) {
1836 return tevent_req_post(req, ev);
1838 tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
1839 return req;
1842 static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq)
1844 struct tevent_req *req = tevent_req_callback_data(
1845 subreq, struct tevent_req);
1846 struct rpc_pipe_bind_state *state = tevent_req_data(
1847 req, struct rpc_pipe_bind_state);
1848 struct pipe_auth_data *pauth = state->cli->auth;
1849 struct gensec_security *gensec_security;
1850 struct ncacn_packet *pkt = NULL;
1851 struct dcerpc_auth auth;
1852 DATA_BLOB auth_token = { .data = NULL };
1853 NTSTATUS status;
1855 status = rpc_api_pipe_recv(subreq, talloc_tos(), &pkt, NULL);
1856 TALLOC_FREE(subreq);
1857 if (tevent_req_nterror(req, status)) {
1858 DEBUG(3, ("rpc_pipe_bind: %s bind request returned %s\n",
1859 rpccli_pipe_txt(talloc_tos(), state->cli),
1860 nt_errstr(status)));
1861 return;
1864 if (state->auth3) {
1865 tevent_req_done(req);
1866 return;
1869 if (!check_bind_response(&pkt->u.bind_ack, &state->cli->transfer_syntax)) {
1870 DEBUG(2, ("rpc_pipe_bind: check_bind_response failed.\n"));
1871 tevent_req_nterror(req, NT_STATUS_BUFFER_TOO_SMALL);
1872 return;
1875 if (pkt->ptype == DCERPC_PKT_BIND_ACK) {
1876 if (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
1877 if (pauth->client_hdr_signing) {
1878 pauth->hdr_signing = true;
1883 state->cli->max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1885 if (pauth->auth_type == DCERPC_AUTH_TYPE_NONE) {
1886 /* Bind complete. */
1887 tevent_req_done(req);
1888 return;
1891 if (pkt->auth_length == 0) {
1892 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1893 return;
1896 /* get auth credentials */
1897 status = dcerpc_pull_auth_trailer(pkt, talloc_tos(),
1898 &pkt->u.bind_ack.auth_info,
1899 &auth, NULL, true);
1900 if (tevent_req_nterror(req, status)) {
1901 DEBUG(0, ("Failed to pull dcerpc auth: %s.\n",
1902 nt_errstr(status)));
1903 return;
1906 if (auth.auth_type != pauth->auth_type) {
1907 DBG_ERR("Auth type %u mismatch expected %u.\n",
1908 auth.auth_type, pauth->auth_type);
1909 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1910 return;
1913 if (auth.auth_level != pauth->auth_level) {
1914 DBG_ERR("Auth level %u mismatch expected %u.\n",
1915 auth.auth_level, pauth->auth_level);
1916 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1917 return;
1920 if (auth.auth_context_id != pauth->auth_context_id) {
1921 DBG_ERR("Auth context id %"PRIu32" mismatch "
1922 "expected %"PRIu32".\n",
1923 auth.auth_context_id,
1924 pauth->auth_context_id);
1925 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1926 return;
1930 * For authenticated binds we may need to do 3 or 4 leg binds.
1933 if (pauth->auth_type == DCERPC_AUTH_TYPE_NONE) {
1934 /* Bind complete. */
1935 tevent_req_done(req);
1936 return;
1939 gensec_security = pauth->auth_ctx;
1941 status = gensec_update(gensec_security, state,
1942 auth.credentials, &auth_token);
1943 if (NT_STATUS_EQUAL(status,
1944 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1945 status = rpc_bind_next_send(req, state,
1946 &auth_token);
1947 } else if (NT_STATUS_IS_OK(status)) {
1948 if (pauth->hdr_signing) {
1949 gensec_want_feature(gensec_security,
1950 GENSEC_FEATURE_SIGN_PKT_HEADER);
1953 if (auth_token.length == 0) {
1954 /* Bind complete. */
1955 tevent_req_done(req);
1956 return;
1958 status = rpc_bind_finish_send(req, state,
1959 &auth_token);
1962 if (!NT_STATUS_IS_OK(status)) {
1963 tevent_req_nterror(req, status);
1965 return;
1968 static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
1969 struct rpc_pipe_bind_state *state,
1970 DATA_BLOB *auth_token)
1972 struct pipe_auth_data *auth = state->cli->auth;
1973 struct tevent_req *subreq;
1974 NTSTATUS status;
1976 /* Now prepare the alter context pdu. */
1977 data_blob_free(&state->rpc_out);
1979 status = create_rpc_alter_context(state, auth,
1980 state->rpc_call_id,
1981 &state->cli->abstract_syntax,
1982 &state->cli->transfer_syntax,
1983 auth_token,
1984 &state->rpc_out);
1985 if (!NT_STATUS_IS_OK(status)) {
1986 return status;
1989 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
1990 &state->rpc_out, DCERPC_PKT_ALTER_RESP,
1991 state->rpc_call_id);
1992 if (subreq == NULL) {
1993 return NT_STATUS_NO_MEMORY;
1995 tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
1996 return NT_STATUS_OK;
1999 static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
2000 struct rpc_pipe_bind_state *state,
2001 DATA_BLOB *auth_token)
2003 struct pipe_auth_data *auth = state->cli->auth;
2004 struct tevent_req *subreq;
2005 NTSTATUS status;
2007 state->auth3 = true;
2009 /* Now prepare the auth3 context pdu. */
2010 data_blob_free(&state->rpc_out);
2012 status = create_rpc_bind_auth3(state, state->cli, auth,
2013 state->rpc_call_id,
2014 auth_token,
2015 &state->rpc_out);
2016 if (!NT_STATUS_IS_OK(status)) {
2017 return status;
2020 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
2021 &state->rpc_out, DCERPC_PKT_AUTH3,
2022 state->rpc_call_id);
2023 if (subreq == NULL) {
2024 return NT_STATUS_NO_MEMORY;
2026 tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
2027 return NT_STATUS_OK;
2030 NTSTATUS rpc_pipe_bind_recv(struct tevent_req *req)
2032 return tevent_req_simple_recv_ntstatus(req);
2035 NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
2036 struct pipe_auth_data *auth)
2038 TALLOC_CTX *frame = talloc_stackframe();
2039 struct tevent_context *ev;
2040 struct tevent_req *req;
2041 NTSTATUS status = NT_STATUS_OK;
2043 ev = samba_tevent_context_init(frame);
2044 if (ev == NULL) {
2045 status = NT_STATUS_NO_MEMORY;
2046 goto fail;
2049 req = rpc_pipe_bind_send(frame, ev, cli, auth);
2050 if (req == NULL) {
2051 status = NT_STATUS_NO_MEMORY;
2052 goto fail;
2055 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2056 goto fail;
2059 status = rpc_pipe_bind_recv(req);
2060 fail:
2061 TALLOC_FREE(frame);
2062 return status;
2065 #define RPCCLI_DEFAULT_TIMEOUT 10000 /* 10 seconds. */
2067 unsigned int rpccli_set_timeout(struct rpc_pipe_client *rpc_cli,
2068 unsigned int timeout)
2070 if (rpc_cli == NULL) {
2071 return RPCCLI_DEFAULT_TIMEOUT;
2074 if (rpc_cli->binding_handle == NULL) {
2075 return RPCCLI_DEFAULT_TIMEOUT;
2078 return dcerpc_binding_handle_set_timeout(rpc_cli->binding_handle,
2079 timeout);
2082 bool rpccli_is_connected(struct rpc_pipe_client *rpc_cli)
2084 if (rpc_cli == NULL) {
2085 return false;
2088 if (rpc_cli->binding_handle == NULL) {
2089 return false;
2092 return dcerpc_binding_handle_is_connected(rpc_cli->binding_handle);
2095 struct rpccli_bh_state {
2096 struct rpc_pipe_client *rpc_cli;
2099 static bool rpccli_bh_is_connected(struct dcerpc_binding_handle *h)
2101 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2102 struct rpccli_bh_state);
2103 struct rpc_cli_transport *transport = hs->rpc_cli->transport;
2105 if (transport == NULL) {
2106 return false;
2109 if (transport->is_connected == NULL) {
2110 return false;
2113 return transport->is_connected(transport->priv);
2116 static uint32_t rpccli_bh_set_timeout(struct dcerpc_binding_handle *h,
2117 uint32_t timeout)
2119 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2120 struct rpccli_bh_state);
2121 struct rpc_cli_transport *transport = hs->rpc_cli->transport;
2122 unsigned int old;
2124 if (transport == NULL) {
2125 return RPCCLI_DEFAULT_TIMEOUT;
2128 if (transport->set_timeout == NULL) {
2129 return RPCCLI_DEFAULT_TIMEOUT;
2132 old = transport->set_timeout(transport->priv, timeout);
2133 if (old == 0) {
2134 return RPCCLI_DEFAULT_TIMEOUT;
2137 return old;
2140 static void rpccli_bh_auth_info(struct dcerpc_binding_handle *h,
2141 enum dcerpc_AuthType *auth_type,
2142 enum dcerpc_AuthLevel *auth_level)
2144 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2145 struct rpccli_bh_state);
2147 if (hs->rpc_cli == NULL) {
2148 return;
2151 if (hs->rpc_cli->auth == NULL) {
2152 return;
2155 *auth_type = hs->rpc_cli->auth->auth_type;
2156 *auth_level = hs->rpc_cli->auth->auth_level;
2159 struct rpccli_bh_raw_call_state {
2160 DATA_BLOB in_data;
2161 DATA_BLOB out_data;
2162 uint32_t out_flags;
2165 static void rpccli_bh_raw_call_done(struct tevent_req *subreq);
2167 static struct tevent_req *rpccli_bh_raw_call_send(TALLOC_CTX *mem_ctx,
2168 struct tevent_context *ev,
2169 struct dcerpc_binding_handle *h,
2170 const struct GUID *object,
2171 uint32_t opnum,
2172 uint32_t in_flags,
2173 const uint8_t *in_data,
2174 size_t in_length)
2176 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2177 struct rpccli_bh_state);
2178 struct tevent_req *req;
2179 struct rpccli_bh_raw_call_state *state;
2180 bool ok;
2181 struct tevent_req *subreq;
2183 req = tevent_req_create(mem_ctx, &state,
2184 struct rpccli_bh_raw_call_state);
2185 if (req == NULL) {
2186 return NULL;
2188 state->in_data.data = discard_const_p(uint8_t, in_data);
2189 state->in_data.length = in_length;
2191 ok = rpccli_bh_is_connected(h);
2192 if (!ok) {
2193 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
2194 return tevent_req_post(req, ev);
2197 subreq = rpc_api_pipe_req_send(state, ev, hs->rpc_cli,
2198 opnum, object, &state->in_data);
2199 if (tevent_req_nomem(subreq, req)) {
2200 return tevent_req_post(req, ev);
2202 tevent_req_set_callback(subreq, rpccli_bh_raw_call_done, req);
2204 return req;
2207 static void rpccli_bh_raw_call_done(struct tevent_req *subreq)
2209 struct tevent_req *req =
2210 tevent_req_callback_data(subreq,
2211 struct tevent_req);
2212 struct rpccli_bh_raw_call_state *state =
2213 tevent_req_data(req,
2214 struct rpccli_bh_raw_call_state);
2215 NTSTATUS status;
2217 state->out_flags = 0;
2219 /* TODO: support bigendian responses */
2221 status = rpc_api_pipe_req_recv(subreq, state, &state->out_data);
2222 TALLOC_FREE(subreq);
2223 if (tevent_req_nterror(req, status)) {
2224 return;
2227 tevent_req_done(req);
2230 static NTSTATUS rpccli_bh_raw_call_recv(struct tevent_req *req,
2231 TALLOC_CTX *mem_ctx,
2232 uint8_t **out_data,
2233 size_t *out_length,
2234 uint32_t *out_flags)
2236 struct rpccli_bh_raw_call_state *state =
2237 tevent_req_data(req,
2238 struct rpccli_bh_raw_call_state);
2239 NTSTATUS status;
2241 if (tevent_req_is_nterror(req, &status)) {
2242 tevent_req_received(req);
2243 return status;
2246 *out_data = talloc_move(mem_ctx, &state->out_data.data);
2247 *out_length = state->out_data.length;
2248 *out_flags = state->out_flags;
2249 tevent_req_received(req);
2250 return NT_STATUS_OK;
2253 struct rpccli_bh_disconnect_state {
2254 uint8_t _dummy;
2257 static struct tevent_req *rpccli_bh_disconnect_send(TALLOC_CTX *mem_ctx,
2258 struct tevent_context *ev,
2259 struct dcerpc_binding_handle *h)
2261 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2262 struct rpccli_bh_state);
2263 struct tevent_req *req;
2264 struct rpccli_bh_disconnect_state *state;
2265 bool ok;
2267 req = tevent_req_create(mem_ctx, &state,
2268 struct rpccli_bh_disconnect_state);
2269 if (req == NULL) {
2270 return NULL;
2273 ok = rpccli_bh_is_connected(h);
2274 if (!ok) {
2275 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
2276 return tevent_req_post(req, ev);
2280 * TODO: do a real async disconnect ...
2282 * For now we do it sync...
2284 TALLOC_FREE(hs->rpc_cli->transport);
2285 hs->rpc_cli = NULL;
2287 tevent_req_done(req);
2288 return tevent_req_post(req, ev);
2291 static NTSTATUS rpccli_bh_disconnect_recv(struct tevent_req *req)
2293 return tevent_req_simple_recv_ntstatus(req);
2296 static bool rpccli_bh_ref_alloc(struct dcerpc_binding_handle *h)
2298 return true;
2301 static void rpccli_bh_do_ndr_print(struct dcerpc_binding_handle *h,
2302 int ndr_flags,
2303 const void *_struct_ptr,
2304 const struct ndr_interface_call *call)
2306 void *struct_ptr = discard_const(_struct_ptr);
2308 if (DEBUGLEVEL < 10) {
2309 return;
2312 if (ndr_flags & NDR_IN) {
2313 ndr_print_function_debug(call->ndr_print,
2314 call->name,
2315 ndr_flags,
2316 struct_ptr);
2318 if (ndr_flags & NDR_OUT) {
2319 ndr_print_function_debug(call->ndr_print,
2320 call->name,
2321 ndr_flags,
2322 struct_ptr);
2326 static const struct dcerpc_binding_handle_ops rpccli_bh_ops = {
2327 .name = "rpccli",
2328 .is_connected = rpccli_bh_is_connected,
2329 .set_timeout = rpccli_bh_set_timeout,
2330 .auth_info = rpccli_bh_auth_info,
2331 .raw_call_send = rpccli_bh_raw_call_send,
2332 .raw_call_recv = rpccli_bh_raw_call_recv,
2333 .disconnect_send = rpccli_bh_disconnect_send,
2334 .disconnect_recv = rpccli_bh_disconnect_recv,
2336 .ref_alloc = rpccli_bh_ref_alloc,
2337 .do_ndr_print = rpccli_bh_do_ndr_print,
2340 /* initialise a rpc_pipe_client binding handle */
2341 struct dcerpc_binding_handle *rpccli_bh_create(struct rpc_pipe_client *c,
2342 const struct GUID *object,
2343 const struct ndr_interface_table *table)
2345 struct dcerpc_binding_handle *h;
2346 struct rpccli_bh_state *hs;
2348 h = dcerpc_binding_handle_create(c,
2349 &rpccli_bh_ops,
2350 object,
2351 table,
2352 &hs,
2353 struct rpccli_bh_state,
2354 __location__);
2355 if (h == NULL) {
2356 return NULL;
2358 hs->rpc_cli = c;
2360 return h;
2363 NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
2364 struct pipe_auth_data **presult)
2366 struct pipe_auth_data *result;
2367 struct auth_generic_state *auth_generic_ctx;
2368 NTSTATUS status;
2370 result = talloc_zero(mem_ctx, struct pipe_auth_data);
2371 if (result == NULL) {
2372 return NT_STATUS_NO_MEMORY;
2375 result->auth_type = DCERPC_AUTH_TYPE_NONE;
2376 result->auth_level = DCERPC_AUTH_LEVEL_NONE;
2377 result->auth_context_id = 0;
2379 status = auth_generic_client_prepare(result,
2380 &auth_generic_ctx);
2381 if (!NT_STATUS_IS_OK(status)) {
2382 DEBUG(1, ("Failed to create auth_generic context: %s\n",
2383 nt_errstr(status)));
2386 status = auth_generic_set_username(auth_generic_ctx, "");
2387 if (!NT_STATUS_IS_OK(status)) {
2388 DEBUG(1, ("Failed to set username: %s\n",
2389 nt_errstr(status)));
2392 status = auth_generic_set_domain(auth_generic_ctx, "");
2393 if (!NT_STATUS_IS_OK(status)) {
2394 DEBUG(1, ("Failed to set domain: %s\n",
2395 nt_errstr(status)));
2396 return status;
2399 status = gensec_set_credentials(auth_generic_ctx->gensec_security,
2400 auth_generic_ctx->credentials);
2401 if (!NT_STATUS_IS_OK(status)) {
2402 DEBUG(1, ("Failed to set GENSEC credentials: %s\n",
2403 nt_errstr(status)));
2404 return status;
2406 talloc_unlink(auth_generic_ctx, auth_generic_ctx->credentials);
2407 auth_generic_ctx->credentials = NULL;
2409 result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2410 talloc_free(auth_generic_ctx);
2411 *presult = result;
2412 return NT_STATUS_OK;
2415 static NTSTATUS rpccli_generic_bind_data(TALLOC_CTX *mem_ctx,
2416 enum dcerpc_AuthType auth_type,
2417 enum dcerpc_AuthLevel auth_level,
2418 const char *server,
2419 const char *target_service,
2420 const char *domain,
2421 const char *username,
2422 const char *password,
2423 enum credentials_use_kerberos use_kerberos,
2424 struct netlogon_creds_CredentialState *creds,
2425 struct pipe_auth_data **presult)
2427 struct auth_generic_state *auth_generic_ctx;
2428 struct pipe_auth_data *result;
2429 NTSTATUS status;
2431 result = talloc_zero(mem_ctx, struct pipe_auth_data);
2432 if (result == NULL) {
2433 return NT_STATUS_NO_MEMORY;
2436 result->auth_type = auth_type;
2437 result->auth_level = auth_level;
2438 result->auth_context_id = 1;
2440 status = auth_generic_client_prepare(result,
2441 &auth_generic_ctx);
2442 if (!NT_STATUS_IS_OK(status)) {
2443 goto fail;
2446 status = auth_generic_set_username(auth_generic_ctx, username);
2447 if (!NT_STATUS_IS_OK(status)) {
2448 goto fail;
2451 status = auth_generic_set_domain(auth_generic_ctx, domain);
2452 if (!NT_STATUS_IS_OK(status)) {
2453 goto fail;
2456 status = auth_generic_set_password(auth_generic_ctx, password);
2457 if (!NT_STATUS_IS_OK(status)) {
2458 goto fail;
2461 status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
2462 if (!NT_STATUS_IS_OK(status)) {
2463 goto fail;
2466 status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
2467 if (!NT_STATUS_IS_OK(status)) {
2468 goto fail;
2471 cli_credentials_set_kerberos_state(auth_generic_ctx->credentials,
2472 use_kerberos,
2473 CRED_SPECIFIED);
2474 cli_credentials_set_netlogon_creds(auth_generic_ctx->credentials, creds);
2476 status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 goto fail;
2481 result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2482 talloc_free(auth_generic_ctx);
2483 *presult = result;
2484 return NT_STATUS_OK;
2486 fail:
2487 TALLOC_FREE(result);
2488 return status;
2491 /* This routine steals the creds pointer that is passed in */
2492 static NTSTATUS rpccli_generic_bind_data_from_creds(TALLOC_CTX *mem_ctx,
2493 enum dcerpc_AuthType auth_type,
2494 enum dcerpc_AuthLevel auth_level,
2495 const char *server,
2496 const char *target_service,
2497 struct cli_credentials *creds,
2498 struct pipe_auth_data **presult)
2500 struct auth_generic_state *auth_generic_ctx;
2501 struct pipe_auth_data *result;
2502 NTSTATUS status;
2504 result = talloc_zero(mem_ctx, struct pipe_auth_data);
2505 if (result == NULL) {
2506 return NT_STATUS_NO_MEMORY;
2509 result->auth_type = auth_type;
2510 result->auth_level = auth_level;
2511 result->auth_context_id = 1;
2513 status = auth_generic_client_prepare(result,
2514 &auth_generic_ctx);
2515 if (!NT_STATUS_IS_OK(status)) {
2516 goto fail;
2519 status = auth_generic_set_creds(auth_generic_ctx, creds);
2520 if (!NT_STATUS_IS_OK(status)) {
2521 goto fail;
2524 status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
2525 if (!NT_STATUS_IS_OK(status)) {
2526 goto fail;
2529 status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
2530 if (!NT_STATUS_IS_OK(status)) {
2531 goto fail;
2534 status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
2535 if (!NT_STATUS_IS_OK(status)) {
2536 goto fail;
2539 result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2540 talloc_free(auth_generic_ctx);
2541 *presult = result;
2542 return NT_STATUS_OK;
2544 fail:
2545 TALLOC_FREE(result);
2546 return status;
2549 NTSTATUS rpccli_ncalrpc_bind_data(TALLOC_CTX *mem_ctx,
2550 struct pipe_auth_data **presult)
2552 return rpccli_generic_bind_data(mem_ctx,
2553 DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM,
2554 DCERPC_AUTH_LEVEL_CONNECT,
2555 NULL, /* server */
2556 "host", /* target_service */
2557 NAME_NT_AUTHORITY, /* domain */
2558 "SYSTEM",
2559 NULL, /* password */
2560 CRED_USE_KERBEROS_DISABLED,
2561 NULL, /* netlogon_creds_CredentialState */
2562 presult);
2566 * Create an rpc pipe client struct, connecting to a tcp port.
2568 static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
2569 const struct sockaddr_storage *ss_addr,
2570 uint16_t port,
2571 const struct ndr_interface_table *table,
2572 struct rpc_pipe_client **presult)
2574 struct rpc_pipe_client *result;
2575 struct sockaddr_storage addr;
2576 NTSTATUS status;
2577 int fd;
2579 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
2580 if (result == NULL) {
2581 return NT_STATUS_NO_MEMORY;
2584 result->abstract_syntax = table->syntax_id;
2585 result->transfer_syntax = ndr_transfer_syntax_ndr;
2587 result->desthost = talloc_strdup(result, host);
2588 if (result->desthost == NULL) {
2589 status = NT_STATUS_NO_MEMORY;
2590 goto fail;
2593 result->srv_name_slash = talloc_asprintf_strupper_m(
2594 result, "\\\\%s", result->desthost);
2595 if (result->srv_name_slash == NULL) {
2596 status = NT_STATUS_NO_MEMORY;
2597 goto fail;
2600 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
2602 if (ss_addr == NULL) {
2603 if (!resolve_name(host, &addr, NBT_NAME_SERVER, false)) {
2604 status = NT_STATUS_NOT_FOUND;
2605 goto fail;
2607 } else {
2608 addr = *ss_addr;
2611 status = open_socket_out(&addr, port, 60*1000, &fd);
2612 if (!NT_STATUS_IS_OK(status)) {
2613 goto fail;
2615 set_socket_options(fd, lp_socket_options());
2617 status = rpc_transport_sock_init(result, fd, &result->transport);
2618 if (!NT_STATUS_IS_OK(status)) {
2619 close(fd);
2620 goto fail;
2623 result->transport->transport = NCACN_IP_TCP;
2625 result->binding_handle = rpccli_bh_create(result, NULL, table);
2626 if (result->binding_handle == NULL) {
2627 TALLOC_FREE(result);
2628 return NT_STATUS_NO_MEMORY;
2631 *presult = result;
2632 return NT_STATUS_OK;
2634 fail:
2635 TALLOC_FREE(result);
2636 return status;
2639 static NTSTATUS rpccli_epm_map_binding(
2640 struct dcerpc_binding_handle *epm_connection,
2641 struct dcerpc_binding *binding,
2642 TALLOC_CTX *mem_ctx,
2643 char **pendpoint)
2645 TALLOC_CTX *frame = talloc_stackframe();
2646 enum dcerpc_transport_t transport =
2647 dcerpc_binding_get_transport(binding);
2648 enum dcerpc_transport_t res_transport;
2649 struct dcerpc_binding *res_binding = NULL;
2650 struct epm_twr_t *map_tower = NULL;
2651 struct epm_twr_p_t res_towers = { .twr = NULL };
2652 struct policy_handle *entry_handle = NULL;
2653 uint32_t num_towers = 0;
2654 const uint32_t max_towers = 1;
2655 const char *endpoint = NULL;
2656 char *tmp = NULL;
2657 uint32_t result;
2658 NTSTATUS status;
2660 map_tower = talloc_zero(frame, struct epm_twr_t);
2661 if (map_tower == NULL) {
2662 goto nomem;
2665 status = dcerpc_binding_build_tower(
2666 frame, binding, &(map_tower->tower));
2667 if (!NT_STATUS_IS_OK(status)) {
2668 DBG_DEBUG("dcerpc_binding_build_tower failed: %s\n",
2669 nt_errstr(status));
2670 goto done;
2673 res_towers.twr = talloc_array(frame, struct epm_twr_t, max_towers);
2674 if (res_towers.twr == NULL) {
2675 goto nomem;
2678 entry_handle = talloc_zero(frame, struct policy_handle);
2679 if (entry_handle == NULL) {
2680 goto nomem;
2683 status = dcerpc_epm_Map(
2684 epm_connection,
2685 frame,
2686 NULL,
2687 map_tower,
2688 entry_handle,
2689 max_towers,
2690 &num_towers,
2691 &res_towers,
2692 &result);
2694 if (!NT_STATUS_IS_OK(status)) {
2695 DBG_DEBUG("dcerpc_epm_Map failed: %s\n", nt_errstr(status));
2696 goto done;
2699 if (result != EPMAPPER_STATUS_OK) {
2700 DBG_DEBUG("dcerpc_epm_Map returned %"PRIu32"\n", result);
2701 status = NT_STATUS_NOT_FOUND;
2702 goto done;
2705 if (num_towers != 1) {
2706 DBG_DEBUG("dcerpc_epm_Map returned %"PRIu32" towers\n",
2707 num_towers);
2708 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2709 goto done;
2712 status = dcerpc_binding_from_tower(
2713 frame, &(res_towers.twr->tower), &res_binding);
2714 if (!NT_STATUS_IS_OK(status)) {
2715 DBG_DEBUG("dcerpc_binding_from_tower failed: %s\n",
2716 nt_errstr(status));
2717 goto done;
2720 res_transport = dcerpc_binding_get_transport(res_binding);
2721 if (res_transport != transport) {
2722 DBG_DEBUG("dcerpc_epm_Map returned transport %d, "
2723 "expected %d\n",
2724 (int)res_transport,
2725 (int)transport);
2726 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2727 goto done;
2730 endpoint = dcerpc_binding_get_string_option(res_binding, "endpoint");
2731 if (endpoint == NULL) {
2732 DBG_DEBUG("dcerpc_epm_Map returned no endpoint\n");
2733 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2734 goto done;
2737 tmp = talloc_strdup(mem_ctx, endpoint);
2738 if (tmp == NULL) {
2739 goto nomem;
2741 *pendpoint = tmp;
2743 status = NT_STATUS_OK;
2744 goto done;
2746 nomem:
2747 status = NT_STATUS_NO_MEMORY;
2748 done:
2749 TALLOC_FREE(frame);
2750 return status;
2753 static NTSTATUS rpccli_epm_map_interface(
2754 struct dcerpc_binding_handle *epm_connection,
2755 enum dcerpc_transport_t transport,
2756 const struct ndr_syntax_id *iface,
2757 TALLOC_CTX *mem_ctx,
2758 char **pendpoint)
2760 struct dcerpc_binding *binding = NULL;
2761 char *endpoint = NULL;
2762 NTSTATUS status;
2764 status = dcerpc_parse_binding(mem_ctx, "", &binding);
2765 if (!NT_STATUS_IS_OK(status)) {
2766 DBG_DEBUG("dcerpc_parse_binding failed: %s\n",
2767 nt_errstr(status));
2768 goto done;
2771 status = dcerpc_binding_set_transport(binding, transport);
2772 if (!NT_STATUS_IS_OK(status)) {
2773 DBG_DEBUG("dcerpc_binding_set_transport failed: %s\n",
2774 nt_errstr(status));
2775 goto done;
2778 status = dcerpc_binding_set_abstract_syntax(binding, iface);
2779 if (!NT_STATUS_IS_OK(status)) {
2780 DBG_DEBUG("dcerpc_binding_set_abstract_syntax failed: %s\n",
2781 nt_errstr(status));
2782 goto done;
2785 status = rpccli_epm_map_binding(
2786 epm_connection, binding, mem_ctx, &endpoint);
2787 if (!NT_STATUS_IS_OK(status)) {
2788 DBG_DEBUG("rpccli_epm_map_binding failed: %s\n",
2789 nt_errstr(status));
2790 goto done;
2792 *pendpoint = endpoint;
2794 done:
2795 TALLOC_FREE(binding);
2796 return status;
2800 * Determine the tcp port on which a dcerpc interface is listening
2801 * for the ncacn_ip_tcp transport via the endpoint mapper of the
2802 * target host.
2804 static NTSTATUS rpc_pipe_get_tcp_port(const char *host,
2805 const struct sockaddr_storage *addr,
2806 const struct ndr_interface_table *table,
2807 uint16_t *pport)
2809 NTSTATUS status;
2810 struct rpc_pipe_client *epm_pipe = NULL;
2811 struct pipe_auth_data *auth = NULL;
2812 char *endpoint = NULL;
2813 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2815 if (pport == NULL) {
2816 status = NT_STATUS_INVALID_PARAMETER;
2817 goto done;
2820 if (ndr_syntax_id_equal(&table->syntax_id,
2821 &ndr_table_epmapper.syntax_id)) {
2822 *pport = 135;
2823 status = NT_STATUS_OK;
2824 goto done;
2827 /* open the connection to the endpoint mapper */
2828 status = rpc_pipe_open_tcp_port(tmp_ctx, host, addr, 135,
2829 &ndr_table_epmapper,
2830 &epm_pipe);
2832 if (!NT_STATUS_IS_OK(status)) {
2833 goto done;
2836 status = rpccli_anon_bind_data(tmp_ctx, &auth);
2837 if (!NT_STATUS_IS_OK(status)) {
2838 goto done;
2841 status = rpc_pipe_bind(epm_pipe, auth);
2842 if (!NT_STATUS_IS_OK(status)) {
2843 goto done;
2846 status = rpccli_epm_map_interface(
2847 epm_pipe->binding_handle,
2848 NCACN_IP_TCP,
2849 &table->syntax_id,
2850 tmp_ctx,
2851 &endpoint);
2852 if (!NT_STATUS_IS_OK(status)) {
2853 DBG_DEBUG("rpccli_epm_map_interface failed: %s\n",
2854 nt_errstr(status));
2855 goto done;
2858 *pport = (uint16_t)atoi(endpoint);
2860 done:
2861 TALLOC_FREE(tmp_ctx);
2862 return status;
2866 * Create a rpc pipe client struct, connecting to a host via tcp.
2867 * The port is determined by asking the endpoint mapper on the given
2868 * host.
2870 static NTSTATUS rpc_pipe_open_tcp(
2871 TALLOC_CTX *mem_ctx,
2872 const char *host,
2873 const struct sockaddr_storage *addr,
2874 const struct ndr_interface_table *table,
2875 struct rpc_pipe_client **presult)
2877 NTSTATUS status;
2878 uint16_t port = 0;
2880 status = rpc_pipe_get_tcp_port(host, addr, table, &port);
2881 if (!NT_STATUS_IS_OK(status)) {
2882 return status;
2885 return rpc_pipe_open_tcp_port(mem_ctx, host, addr, port,
2886 table, presult);
2889 static NTSTATUS rpc_pipe_get_ncalrpc_name(
2890 const struct ndr_syntax_id *iface,
2891 TALLOC_CTX *mem_ctx,
2892 char **psocket_name)
2894 TALLOC_CTX *frame = talloc_stackframe();
2895 struct rpc_pipe_client *epm_pipe = NULL;
2896 struct pipe_auth_data *auth = NULL;
2897 NTSTATUS status = NT_STATUS_OK;
2898 bool is_epm;
2900 is_epm = ndr_syntax_id_equal(iface, &ndr_table_epmapper.syntax_id);
2901 if (is_epm) {
2902 char *endpoint = talloc_strdup(mem_ctx, "EPMAPPER");
2903 if (endpoint == NULL) {
2904 status = NT_STATUS_NO_MEMORY;
2905 goto done;
2907 *psocket_name = endpoint;
2908 goto done;
2911 status = rpc_pipe_open_ncalrpc(
2912 frame, &ndr_table_epmapper, &epm_pipe);
2913 if (!NT_STATUS_IS_OK(status)) {
2914 DBG_DEBUG("rpc_pipe_open_ncalrpc failed: %s\n",
2915 nt_errstr(status));
2916 goto done;
2919 status = rpccli_anon_bind_data(epm_pipe, &auth);
2920 if (!NT_STATUS_IS_OK(status)) {
2921 DBG_DEBUG("rpccli_anon_bind_data failed: %s\n",
2922 nt_errstr(status));
2923 goto done;
2926 status = rpc_pipe_bind(epm_pipe, auth);
2927 if (!NT_STATUS_IS_OK(status)) {
2928 DBG_DEBUG("rpc_pipe_bind failed: %s\n", nt_errstr(status));
2929 goto done;
2932 status = rpccli_epm_map_interface(
2933 epm_pipe->binding_handle,
2934 NCALRPC,
2935 iface,
2936 mem_ctx,
2937 psocket_name);
2938 if (!NT_STATUS_IS_OK(status)) {
2939 DBG_DEBUG("rpccli_epm_map_interface failed: %s\n",
2940 nt_errstr(status));
2943 done:
2944 TALLOC_FREE(frame);
2945 return status;
2948 /********************************************************************
2949 Create a rpc pipe client struct, connecting to a unix domain socket
2950 ********************************************************************/
2951 NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx,
2952 const struct ndr_interface_table *table,
2953 struct rpc_pipe_client **presult)
2955 char *socket_name = NULL;
2956 struct rpc_pipe_client *result;
2957 struct sockaddr_un addr = { .sun_family = AF_UNIX };
2958 socklen_t salen = sizeof(addr);
2959 int pathlen;
2960 NTSTATUS status;
2961 int fd = -1;
2963 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
2964 if (result == NULL) {
2965 return NT_STATUS_NO_MEMORY;
2968 status = rpc_pipe_get_ncalrpc_name(
2969 &table->syntax_id, result, &socket_name);
2970 if (!NT_STATUS_IS_OK(status)) {
2971 DBG_DEBUG("rpc_pipe_get_ncalrpc_name failed: %s\n",
2972 nt_errstr(status));
2973 goto fail;
2976 pathlen = snprintf(
2977 addr.sun_path,
2978 sizeof(addr.sun_path),
2979 "%s/%s",
2980 lp_ncalrpc_dir(),
2981 socket_name);
2982 if ((pathlen < 0) || ((size_t)pathlen >= sizeof(addr.sun_path))) {
2983 DBG_DEBUG("socket_path for %s too long\n", socket_name);
2984 status = NT_STATUS_NAME_TOO_LONG;
2985 goto fail;
2987 TALLOC_FREE(socket_name);
2989 result->abstract_syntax = table->syntax_id;
2990 result->transfer_syntax = ndr_transfer_syntax_ndr;
2992 result->desthost = get_myname(result);
2993 if (result->desthost == NULL) {
2994 status = NT_STATUS_NO_MEMORY;
2995 goto fail;
2998 result->srv_name_slash = talloc_asprintf_strupper_m(
2999 result, "\\\\%s", result->desthost);
3000 if (result->srv_name_slash == NULL) {
3001 status = NT_STATUS_NO_MEMORY;
3002 goto fail;
3005 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
3007 fd = socket(AF_UNIX, SOCK_STREAM, 0);
3008 if (fd == -1) {
3009 status = map_nt_error_from_unix(errno);
3010 goto fail;
3013 if (connect(fd, (struct sockaddr *)(void *)&addr, salen) == -1) {
3014 DBG_WARNING("connect(%s) failed: %s\n",
3015 addr.sun_path,
3016 strerror(errno));
3017 status = map_nt_error_from_unix(errno);
3018 goto fail;
3021 status = rpc_transport_sock_init(result, fd, &result->transport);
3022 if (!NT_STATUS_IS_OK(status)) {
3023 goto fail;
3025 fd = -1;
3027 result->transport->transport = NCALRPC;
3029 result->binding_handle = rpccli_bh_create(result, NULL, table);
3030 if (result->binding_handle == NULL) {
3031 status = NT_STATUS_NO_MEMORY;
3032 goto fail;
3035 *presult = result;
3036 return NT_STATUS_OK;
3038 fail:
3039 if (fd != -1) {
3040 close(fd);
3042 TALLOC_FREE(result);
3043 return status;
3046 NTSTATUS rpc_pipe_open_local_np(
3047 TALLOC_CTX *mem_ctx,
3048 const struct ndr_interface_table *table,
3049 const char *remote_client_name,
3050 const struct tsocket_address *remote_client_addr,
3051 const char *local_server_name,
3052 const struct tsocket_address *local_server_addr,
3053 const struct auth_session_info *session_info,
3054 struct rpc_pipe_client **presult)
3056 struct rpc_pipe_client *result = NULL;
3057 struct pipe_auth_data *auth = NULL;
3058 const char *pipe_name = NULL;
3059 struct tstream_context *npa_stream = NULL;
3060 NTSTATUS status = NT_STATUS_NO_MEMORY;
3061 int ret;
3063 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
3064 if (result == NULL) {
3065 goto fail;
3067 result->abstract_syntax = table->syntax_id;
3068 result->transfer_syntax = ndr_transfer_syntax_ndr;
3069 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
3071 pipe_name = dcerpc_default_transport_endpoint(
3072 result, NCACN_NP, table);
3073 if (pipe_name == NULL) {
3074 DBG_DEBUG("dcerpc_default_transport_endpoint failed\n");
3075 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3076 goto fail;
3079 if (local_server_name == NULL) {
3080 result->desthost = get_myname(result);
3081 } else {
3082 result->desthost = talloc_strdup(result, local_server_name);
3084 if (result->desthost == NULL) {
3085 goto fail;
3087 result->srv_name_slash = talloc_asprintf_strupper_m(
3088 result, "\\\\%s", result->desthost);
3089 if (result->srv_name_slash == NULL) {
3090 goto fail;
3093 ret = local_np_connect(
3094 pipe_name,
3095 NCALRPC,
3096 remote_client_name,
3097 remote_client_addr,
3098 local_server_name,
3099 local_server_addr,
3100 session_info,
3101 true,
3102 result,
3103 &npa_stream);
3104 if (ret != 0) {
3105 DBG_DEBUG("local_np_connect for %s and "
3106 "user %s\\%s failed: %s\n",
3107 pipe_name,
3108 session_info->info->domain_name,
3109 session_info->info->account_name,
3110 strerror(ret));
3111 status = map_nt_error_from_unix(ret);
3112 goto fail;
3115 status = rpc_transport_tstream_init(
3116 result, &npa_stream, &result->transport);
3117 if (!NT_STATUS_IS_OK(status)) {
3118 DBG_DEBUG("rpc_transport_tstream_init failed: %s\n",
3119 nt_errstr(status));
3120 goto fail;
3123 result->binding_handle = rpccli_bh_create(result, NULL, table);
3124 if (result->binding_handle == NULL) {
3125 status = NT_STATUS_NO_MEMORY;
3126 DBG_DEBUG("Failed to create binding handle.\n");
3127 goto fail;
3130 status = rpccli_anon_bind_data(result, &auth);
3131 if (!NT_STATUS_IS_OK(status)) {
3132 DBG_DEBUG("rpccli_anon_bind_data failed: %s\n",
3133 nt_errstr(status));
3134 goto fail;
3137 status = rpc_pipe_bind(result, auth);
3138 if (!NT_STATUS_IS_OK(status)) {
3139 DBG_DEBUG("rpc_pipe_bind failed: %s\n", nt_errstr(status));
3140 goto fail;
3143 *presult = result;
3144 return NT_STATUS_OK;
3146 fail:
3147 TALLOC_FREE(result);
3148 return status;
3151 struct rpc_pipe_client_np_ref {
3152 struct cli_state *cli;
3153 struct rpc_pipe_client *pipe;
3156 static int rpc_pipe_client_np_ref_destructor(struct rpc_pipe_client_np_ref *np_ref)
3158 DLIST_REMOVE(np_ref->cli->pipe_list, np_ref->pipe);
3159 return 0;
3162 /****************************************************************************
3163 Open a named pipe over SMB to a remote server.
3165 * CAVEAT CALLER OF THIS FUNCTION:
3166 * The returned rpc_pipe_client saves a copy of the cli_state cli pointer,
3167 * so be sure that this function is called AFTER any structure (vs pointer)
3168 * assignment of the cli. In particular, libsmbclient does structure
3169 * assignments of cli, which invalidates the data in the returned
3170 * rpc_pipe_client if this function is called before the structure assignment
3171 * of cli.
3173 ****************************************************************************/
3175 static NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
3176 const struct ndr_interface_table *table,
3177 struct rpc_pipe_client **presult)
3179 struct rpc_pipe_client *result;
3180 NTSTATUS status;
3181 struct rpc_pipe_client_np_ref *np_ref;
3183 /* sanity check to protect against crashes */
3185 if ( !cli ) {
3186 return NT_STATUS_INVALID_HANDLE;
3189 result = talloc_zero(NULL, struct rpc_pipe_client);
3190 if (result == NULL) {
3191 return NT_STATUS_NO_MEMORY;
3194 result->abstract_syntax = table->syntax_id;
3195 result->transfer_syntax = ndr_transfer_syntax_ndr;
3197 result->desthost = talloc_strdup(
3198 result, smbXcli_conn_remote_name(cli->conn));
3199 if (result->desthost == NULL) {
3200 TALLOC_FREE(result);
3201 return NT_STATUS_NO_MEMORY;
3204 result->srv_name_slash = talloc_asprintf_strupper_m(
3205 result, "\\\\%s", result->desthost);
3206 if (result->srv_name_slash == NULL) {
3207 TALLOC_FREE(result);
3208 return NT_STATUS_NO_MEMORY;
3211 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
3213 status = rpc_transport_np_init(result, cli, table,
3214 &result->transport);
3215 if (!NT_STATUS_IS_OK(status)) {
3216 TALLOC_FREE(result);
3217 return status;
3220 result->transport->transport = NCACN_NP;
3222 np_ref = talloc(result->transport, struct rpc_pipe_client_np_ref);
3223 if (np_ref == NULL) {
3224 TALLOC_FREE(result);
3225 return NT_STATUS_NO_MEMORY;
3227 np_ref->cli = cli;
3228 np_ref->pipe = result;
3230 DLIST_ADD(np_ref->cli->pipe_list, np_ref->pipe);
3231 talloc_set_destructor(np_ref, rpc_pipe_client_np_ref_destructor);
3233 result->binding_handle = rpccli_bh_create(result, NULL, table);
3234 if (result->binding_handle == NULL) {
3235 TALLOC_FREE(result);
3236 return NT_STATUS_NO_MEMORY;
3239 *presult = result;
3240 return NT_STATUS_OK;
3243 /****************************************************************************
3244 Open a pipe to a remote server.
3245 ****************************************************************************/
3247 static NTSTATUS cli_rpc_pipe_open(struct cli_state *cli,
3248 enum dcerpc_transport_t transport,
3249 const struct ndr_interface_table *table,
3250 const char *remote_name,
3251 const struct sockaddr_storage *remote_sockaddr,
3252 struct rpc_pipe_client **presult)
3254 switch (transport) {
3255 case NCACN_IP_TCP:
3256 return rpc_pipe_open_tcp(NULL,
3257 remote_name,
3258 remote_sockaddr,
3259 table, presult);
3260 case NCACN_NP:
3261 return rpc_pipe_open_np(cli, table, presult);
3262 default:
3263 return NT_STATUS_NOT_IMPLEMENTED;
3267 /****************************************************************************
3268 Open a named pipe to an SMB server and bind anonymously.
3269 ****************************************************************************/
3271 NTSTATUS cli_rpc_pipe_open_noauth_transport(struct cli_state *cli,
3272 enum dcerpc_transport_t transport,
3273 const struct ndr_interface_table *table,
3274 const char *remote_name,
3275 const struct sockaddr_storage *remote_sockaddr,
3276 struct rpc_pipe_client **presult)
3278 struct rpc_pipe_client *result;
3279 struct pipe_auth_data *auth;
3280 NTSTATUS status;
3282 status = cli_rpc_pipe_open(cli,
3283 transport,
3284 table,
3285 remote_name,
3286 remote_sockaddr,
3287 &result);
3288 if (!NT_STATUS_IS_OK(status)) {
3289 return status;
3292 status = rpccli_anon_bind_data(result, &auth);
3293 if (!NT_STATUS_IS_OK(status)) {
3294 DEBUG(0, ("rpccli_anon_bind_data returned %s\n",
3295 nt_errstr(status)));
3296 TALLOC_FREE(result);
3297 return status;
3301 * This is a bit of an abstraction violation due to the fact that an
3302 * anonymous bind on an authenticated SMB inherits the user/domain
3303 * from the enclosing SMB creds
3306 if (transport == NCACN_NP) {
3307 struct smbXcli_session *session;
3309 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3310 session = cli->smb2.session;
3311 } else {
3312 session = cli->smb1.session;
3315 status = smbXcli_session_application_key(session, auth,
3316 &auth->transport_session_key);
3317 if (!NT_STATUS_IS_OK(status)) {
3318 auth->transport_session_key = data_blob_null;
3322 status = rpc_pipe_bind(result, auth);
3323 if (!NT_STATUS_IS_OK(status)) {
3324 int lvl = 0;
3325 if (ndr_syntax_id_equal(&table->syntax_id,
3326 &ndr_table_dssetup.syntax_id)) {
3327 /* non AD domains just don't have this pipe, avoid
3328 * level 0 statement in that case - gd */
3329 lvl = 3;
3331 DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe "
3332 "%s failed with error %s\n",
3333 table->name,
3334 nt_errstr(status) ));
3335 TALLOC_FREE(result);
3336 return status;
3339 DEBUG(10,("cli_rpc_pipe_open_noauth: opened pipe %s to machine "
3340 "%s and bound anonymously.\n",
3341 table->name,
3342 result->desthost));
3344 *presult = result;
3345 return NT_STATUS_OK;
3348 /****************************************************************************
3349 ****************************************************************************/
3351 NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli,
3352 const struct ndr_interface_table *table,
3353 struct rpc_pipe_client **presult)
3355 const char *remote_name = smbXcli_conn_remote_name(cli->conn);
3356 const struct sockaddr_storage *remote_sockaddr =
3357 smbXcli_conn_remote_sockaddr(cli->conn);
3359 return cli_rpc_pipe_open_noauth_transport(cli, NCACN_NP,
3360 table,
3361 remote_name,
3362 remote_sockaddr,
3363 presult);
3366 /****************************************************************************
3367 Open a named pipe to an SMB server and bind using the mech specified
3369 This routine references the creds pointer that is passed in
3370 ****************************************************************************/
3372 NTSTATUS cli_rpc_pipe_open_with_creds(struct cli_state *cli,
3373 const struct ndr_interface_table *table,
3374 enum dcerpc_transport_t transport,
3375 enum dcerpc_AuthType auth_type,
3376 enum dcerpc_AuthLevel auth_level,
3377 const char *server,
3378 const struct sockaddr_storage *remote_sockaddr,
3379 struct cli_credentials *creds,
3380 struct rpc_pipe_client **presult)
3382 struct rpc_pipe_client *result;
3383 struct pipe_auth_data *auth = NULL;
3384 const char *target_service = table->authservices->names[0];
3385 NTSTATUS status;
3387 status = cli_rpc_pipe_open(cli,
3388 transport,
3389 table,
3390 server,
3391 remote_sockaddr,
3392 &result);
3393 if (!NT_STATUS_IS_OK(status)) {
3394 return status;
3397 status = rpccli_generic_bind_data_from_creds(result,
3398 auth_type, auth_level,
3399 server, target_service,
3400 creds,
3401 &auth);
3402 if (!NT_STATUS_IS_OK(status)) {
3403 DBG_ERR("rpccli_generic_bind_data_from_creds returned %s\n",
3404 nt_errstr(status));
3405 goto err;
3408 status = rpc_pipe_bind(result, auth);
3409 if (!NT_STATUS_IS_OK(status)) {
3410 DBG_ERR("cli_rpc_pipe_bind failed with error %s\n",
3411 nt_errstr(status));
3412 goto err;
3415 DBG_DEBUG("opened pipe %s to machine %s and bound as user %s.\n",
3416 table->name,
3417 result->desthost,
3418 cli_credentials_get_unparsed_name(creds, talloc_tos()));
3420 *presult = result;
3421 return NT_STATUS_OK;
3423 err:
3425 TALLOC_FREE(result);
3426 return status;
3429 NTSTATUS cli_rpc_pipe_open_bind_schannel(
3430 struct cli_state *cli,
3431 const struct ndr_interface_table *table,
3432 enum dcerpc_transport_t transport,
3433 struct netlogon_creds_cli_context *netlogon_creds,
3434 const char *remote_name,
3435 const struct sockaddr_storage *remote_sockaddr,
3436 struct rpc_pipe_client **_rpccli)
3438 struct rpc_pipe_client *rpccli;
3439 struct pipe_auth_data *rpcauth;
3440 const char *target_service = table->authservices->names[0];
3441 struct cli_credentials *cli_creds;
3442 enum dcerpc_AuthLevel auth_level;
3443 NTSTATUS status;
3445 status = cli_rpc_pipe_open(cli,
3446 transport,
3447 table,
3448 remote_name,
3449 remote_sockaddr,
3450 &rpccli);
3451 if (!NT_STATUS_IS_OK(status)) {
3452 return status;
3455 auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
3457 status = netlogon_creds_bind_cli_credentials(
3458 netlogon_creds, rpccli, &cli_creds);
3459 if (!NT_STATUS_IS_OK(status)) {
3460 DBG_DEBUG("netlogon_creds_bind_cli_credentials failed: %s\n",
3461 nt_errstr(status));
3462 TALLOC_FREE(rpccli);
3463 return status;
3466 status = rpccli_generic_bind_data_from_creds(rpccli,
3467 DCERPC_AUTH_TYPE_SCHANNEL,
3468 auth_level,
3469 rpccli->desthost,
3470 target_service,
3471 cli_creds,
3472 &rpcauth);
3473 if (!NT_STATUS_IS_OK(status)) {
3474 DEBUG(0, ("rpccli_generic_bind_data_from_creds returned %s\n",
3475 nt_errstr(status)));
3476 TALLOC_FREE(rpccli);
3477 return status;
3480 status = rpc_pipe_bind(rpccli, rpcauth);
3482 /* No TALLOC_FREE, gensec takes references */
3483 talloc_unlink(rpccli, cli_creds);
3484 cli_creds = NULL;
3486 if (!NT_STATUS_IS_OK(status)) {
3487 DBG_DEBUG("rpc_pipe_bind failed with error %s\n",
3488 nt_errstr(status));
3489 TALLOC_FREE(rpccli);
3490 return status;
3493 *_rpccli = rpccli;
3495 return NT_STATUS_OK;
3498 NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
3499 const struct ndr_interface_table *table,
3500 enum dcerpc_transport_t transport,
3501 struct netlogon_creds_cli_context *netlogon_creds,
3502 const char *remote_name,
3503 const struct sockaddr_storage *remote_sockaddr,
3504 struct rpc_pipe_client **_rpccli)
3506 TALLOC_CTX *frame = talloc_stackframe();
3507 struct rpc_pipe_client *rpccli;
3508 struct netlogon_creds_cli_lck *lck;
3509 NTSTATUS status;
3511 status = netlogon_creds_cli_lck(
3512 netlogon_creds, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
3513 frame, &lck);
3514 if (!NT_STATUS_IS_OK(status)) {
3515 DBG_WARNING("netlogon_creds_cli_lck returned %s\n",
3516 nt_errstr(status));
3517 TALLOC_FREE(frame);
3518 return status;
3521 status = cli_rpc_pipe_open_bind_schannel(cli,
3522 table,
3523 transport,
3524 netlogon_creds,
3525 remote_name,
3526 remote_sockaddr,
3527 &rpccli);
3528 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
3529 netlogon_creds_cli_delete_lck(netlogon_creds);
3531 if (!NT_STATUS_IS_OK(status)) {
3532 DBG_DEBUG("cli_rpc_pipe_open_bind_schannel failed: %s\n",
3533 nt_errstr(status));
3534 TALLOC_FREE(frame);
3535 return status;
3538 if (ndr_syntax_id_equal(&table->syntax_id,
3539 &ndr_table_netlogon.syntax_id)) {
3540 status = netlogon_creds_cli_check(netlogon_creds,
3541 rpccli->binding_handle,
3542 NULL);
3543 if (!NT_STATUS_IS_OK(status)) {
3544 DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
3545 nt_errstr(status)));
3546 TALLOC_FREE(frame);
3547 return status;
3551 DBG_DEBUG("opened pipe %s to machine %s with key %s "
3552 "and bound using schannel.\n",
3553 table->name, rpccli->desthost,
3554 netlogon_creds_cli_debug_string(netlogon_creds, lck));
3556 TALLOC_FREE(frame);
3558 *_rpccli = rpccli;
3559 return NT_STATUS_OK;
3562 NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
3563 struct rpc_pipe_client *cli,
3564 DATA_BLOB *session_key)
3566 NTSTATUS status;
3567 struct pipe_auth_data *a;
3568 struct gensec_security *gensec_security;
3569 DATA_BLOB sk = { .data = NULL };
3570 bool make_dup = false;
3572 if (!session_key || !cli) {
3573 return NT_STATUS_INVALID_PARAMETER;
3576 a = cli->auth;
3578 if (a == NULL) {
3579 return NT_STATUS_INVALID_PARAMETER;
3582 switch (cli->auth->auth_type) {
3583 case DCERPC_AUTH_TYPE_NONE:
3584 sk = data_blob_const(a->transport_session_key.data,
3585 a->transport_session_key.length);
3586 make_dup = true;
3587 break;
3588 default:
3589 gensec_security = a->auth_ctx;
3590 status = gensec_session_key(gensec_security, mem_ctx, &sk);
3591 if (!NT_STATUS_IS_OK(status)) {
3592 return status;
3594 make_dup = false;
3595 break;
3598 if (!sk.data) {
3599 return NT_STATUS_NO_USER_SESSION_KEY;
3602 if (make_dup) {
3603 *session_key = data_blob_dup_talloc(mem_ctx, sk);
3604 } else {
3605 *session_key = sk;
3608 return NT_STATUS_OK;