s3:printing: Allow to run samba-bgqd as a standalone systemd service
[Samba.git] / source3 / rpc_client / cli_pipe.c
blobcf551f6f548fa9c63867d16369c1104bc142b5e9
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 endianness;
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->endianness = 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->endianness = 0x00; /* BIG ENDIAN */
971 * Check endianness on subsequent packets.
973 if (state->endianness != state->pkt->drep[0]) {
974 DEBUG(0,("rpc_api_pipe: Error : Endianness changed from %s to "
975 "%s\n",
976 state->endianness?"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 ndr_syntax_id bind_time_features = dcerpc_construct_bind_time_features(
1134 DCERPC_BIND_TIME_SECURITY_CONTEXT_MULTIPLEXING |
1135 DCERPC_BIND_TIME_KEEP_CONNECTION_ON_ORPHAN);
1136 struct dcerpc_ctx_list ctx_list[2] = {
1137 [0] = {
1138 .context_id = 0,
1139 .num_transfer_syntaxes = 1,
1140 .abstract_syntax = *abstract,
1141 .transfer_syntaxes = (struct ndr_syntax_id *)discard_const(transfer),
1143 [1] = {
1144 .context_id = 1,
1145 .num_transfer_syntaxes = 1,
1146 .abstract_syntax = *abstract,
1147 .transfer_syntaxes = &bind_time_features,
1150 union dcerpc_payload u = {
1151 .bind.max_xmit_frag = RPC_MAX_PDU_FRAG_LEN,
1152 .bind.max_recv_frag = RPC_MAX_PDU_FRAG_LEN,
1153 .bind.num_contexts = ptype == DCERPC_PKT_BIND ? 2 : 1,
1154 .bind.ctx_list = ctx_list,
1155 .bind.auth_info = *auth_info,
1157 uint8_t pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
1159 if (auth_len) {
1160 auth_len -= DCERPC_AUTH_TRAILER_LENGTH;
1163 if (client_hdr_signing) {
1164 pfc_flags |= DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN;
1167 status = dcerpc_push_ncacn_packet(mem_ctx,
1168 ptype, pfc_flags,
1169 auth_len,
1170 rpc_call_id,
1172 blob);
1173 if (!NT_STATUS_IS_OK(status)) {
1174 DEBUG(0, ("Failed to marshall bind/alter ncacn_packet.\n"));
1175 return status;
1178 return NT_STATUS_OK;
1181 /*******************************************************************
1182 Creates a DCE/RPC bind request.
1183 ********************************************************************/
1185 static NTSTATUS create_rpc_bind_req(TALLOC_CTX *mem_ctx,
1186 struct rpc_pipe_client *cli,
1187 struct pipe_auth_data *auth,
1188 uint32_t rpc_call_id,
1189 const struct ndr_syntax_id *abstract,
1190 const struct ndr_syntax_id *transfer,
1191 DATA_BLOB *rpc_out)
1193 DATA_BLOB auth_token = { .data = NULL };
1194 DATA_BLOB auth_info = { .data = NULL };
1195 NTSTATUS ret;
1197 if (auth->auth_type != DCERPC_AUTH_TYPE_NONE) {
1198 ret = create_generic_auth_rpc_bind_req(
1199 cli, mem_ctx, &auth_token, &auth->client_hdr_signing);
1201 if (!NT_STATUS_IS_OK(ret) &&
1202 !NT_STATUS_EQUAL(ret, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1203 return ret;
1207 if (auth_token.length != 0) {
1208 ret = dcerpc_push_dcerpc_auth(cli,
1209 auth->auth_type,
1210 auth->auth_level,
1211 0, /* auth_pad_length */
1212 auth->auth_context_id,
1213 &auth_token,
1214 &auth_info);
1215 if (!NT_STATUS_IS_OK(ret)) {
1216 return ret;
1218 data_blob_free(&auth_token);
1221 ret = create_bind_or_alt_ctx_internal(mem_ctx,
1222 DCERPC_PKT_BIND,
1223 rpc_call_id,
1224 abstract,
1225 transfer,
1226 &auth_info,
1227 auth->client_hdr_signing,
1228 rpc_out);
1229 data_blob_free(&auth_info);
1231 return ret;
1234 /*******************************************************************
1235 External interface.
1236 Does an rpc request on a pipe. Incoming data is NDR encoded in in_data.
1237 Reply is NDR encoded in out_data. Splits the data stream into RPC PDU's
1238 and deals with signing/sealing details.
1239 ********************************************************************/
1241 struct rpc_api_pipe_req_state {
1242 struct tevent_context *ev;
1243 struct rpc_pipe_client *cli;
1244 uint8_t op_num;
1245 uint32_t call_id;
1246 const DATA_BLOB *req_data;
1247 const struct GUID *object_uuid;
1248 uint32_t req_data_sent;
1249 DATA_BLOB req_trailer;
1250 uint32_t req_trailer_sent;
1251 bool verify_bitmask1;
1252 bool verify_pcontext;
1253 DATA_BLOB rpc_out;
1254 DATA_BLOB reply_pdu;
1257 static void rpc_api_pipe_req_write_done(struct tevent_req *subreq);
1258 static void rpc_api_pipe_req_done(struct tevent_req *subreq);
1259 static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state);
1260 static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
1261 bool *is_last_frag);
1263 static struct tevent_req *rpc_api_pipe_req_send(TALLOC_CTX *mem_ctx,
1264 struct tevent_context *ev,
1265 struct rpc_pipe_client *cli,
1266 uint8_t op_num,
1267 const struct GUID *object_uuid,
1268 const DATA_BLOB *req_data)
1270 struct tevent_req *req, *subreq;
1271 struct rpc_api_pipe_req_state *state;
1272 NTSTATUS status;
1273 bool is_last_frag;
1275 req = tevent_req_create(mem_ctx, &state,
1276 struct rpc_api_pipe_req_state);
1277 if (req == NULL) {
1278 return NULL;
1280 state->ev = ev;
1281 state->cli = cli;
1282 state->op_num = op_num;
1283 state->object_uuid = object_uuid;
1284 state->req_data = req_data;
1285 state->call_id = get_rpc_call_id();
1287 if (cli->max_xmit_frag < DCERPC_REQUEST_LENGTH
1288 + RPC_MAX_SIGN_SIZE) {
1289 /* Server is screwed up ! */
1290 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1291 return tevent_req_post(req, ev);
1294 status = prepare_verification_trailer(state);
1295 if (tevent_req_nterror(req, status)) {
1296 return tevent_req_post(req, ev);
1299 status = prepare_next_frag(state, &is_last_frag);
1300 if (tevent_req_nterror(req, status)) {
1301 return tevent_req_post(req, ev);
1304 if (is_last_frag) {
1305 subreq = rpc_api_pipe_send(state, ev, state->cli,
1306 &state->rpc_out,
1307 DCERPC_PKT_RESPONSE,
1308 state->call_id);
1309 if (tevent_req_nomem(subreq, req)) {
1310 return tevent_req_post(req, ev);
1312 tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req);
1313 } else {
1314 subreq = rpc_write_send(state, ev, cli->transport,
1315 state->rpc_out.data,
1316 state->rpc_out.length);
1317 if (tevent_req_nomem(subreq, req)) {
1318 return tevent_req_post(req, ev);
1320 tevent_req_set_callback(subreq, rpc_api_pipe_req_write_done,
1321 req);
1323 return req;
1326 static NTSTATUS prepare_verification_trailer(struct rpc_api_pipe_req_state *state)
1328 struct pipe_auth_data *a = state->cli->auth;
1329 struct dcerpc_sec_verification_trailer *t;
1330 struct ndr_push *ndr = NULL;
1331 enum ndr_err_code ndr_err;
1332 size_t align = 0;
1333 size_t pad = 0;
1335 if (a == NULL) {
1336 return NT_STATUS_OK;
1339 if (a->auth_level < DCERPC_AUTH_LEVEL_PACKET) {
1340 return NT_STATUS_OK;
1343 t = talloc_zero(state, struct dcerpc_sec_verification_trailer);
1344 if (t == NULL) {
1345 return NT_STATUS_NO_MEMORY;
1348 if (!a->verified_bitmask1) {
1349 t->commands = talloc_realloc(t, t->commands,
1350 struct dcerpc_sec_vt,
1351 t->count.count + 1);
1352 if (t->commands == NULL) {
1353 return NT_STATUS_NO_MEMORY;
1355 t->commands[t->count.count++] = (struct dcerpc_sec_vt) {
1356 .command = DCERPC_SEC_VT_COMMAND_BITMASK1,
1357 .u.bitmask1 = (a->client_hdr_signing) ?
1358 DCERPC_SEC_VT_CLIENT_SUPPORTS_HEADER_SIGNING :
1361 state->verify_bitmask1 = true;
1364 if (!state->cli->verified_pcontext) {
1365 t->commands = talloc_realloc(t, t->commands,
1366 struct dcerpc_sec_vt,
1367 t->count.count + 1);
1368 if (t->commands == NULL) {
1369 return NT_STATUS_NO_MEMORY;
1371 t->commands[t->count.count++] = (struct dcerpc_sec_vt) {
1372 .command = DCERPC_SEC_VT_COMMAND_PCONTEXT,
1373 .u.pcontext.abstract_syntax =
1374 state->cli->abstract_syntax,
1375 .u.pcontext.transfer_syntax =
1376 state->cli->transfer_syntax,
1378 state->verify_pcontext = true;
1381 if (!a->hdr_signing) {
1382 t->commands = talloc_realloc(t, t->commands,
1383 struct dcerpc_sec_vt,
1384 t->count.count + 1);
1385 if (t->commands == NULL) {
1386 return NT_STATUS_NO_MEMORY;
1388 t->commands[t->count.count++] = (struct dcerpc_sec_vt) {
1389 .command = DCERPC_SEC_VT_COMMAND_HEADER2,
1390 .u.header2.ptype = DCERPC_PKT_REQUEST,
1391 .u.header2.drep[0] = DCERPC_DREP_LE,
1392 .u.header2.call_id = state->call_id,
1393 .u.header2.context_id = 0,
1394 .u.header2.opnum = state->op_num,
1398 if (t->count.count == 0) {
1399 TALLOC_FREE(t);
1400 return NT_STATUS_OK;
1403 t->commands[t->count.count - 1].command |= DCERPC_SEC_VT_COMMAND_END;
1405 if (DEBUGLEVEL >= 10) {
1406 NDR_PRINT_DEBUG(dcerpc_sec_verification_trailer, t);
1409 ndr = ndr_push_init_ctx(state);
1410 if (ndr == NULL) {
1411 return NT_STATUS_NO_MEMORY;
1414 ndr_err = ndr_push_dcerpc_sec_verification_trailer(ndr,
1415 NDR_SCALARS | NDR_BUFFERS,
1417 TALLOC_FREE(t);
1418 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1419 return ndr_map_error2ntstatus(ndr_err);
1421 state->req_trailer = ndr_push_blob(ndr);
1423 align = state->req_data->length & 0x3;
1424 if (align > 0) {
1425 pad = 4 - align;
1427 if (pad > 0) {
1428 bool ok;
1429 uint8_t *p;
1430 const uint8_t zeros[4] = { 0, };
1432 ok = data_blob_append(ndr, &state->req_trailer, zeros, pad);
1433 if (!ok) {
1434 return NT_STATUS_NO_MEMORY;
1437 /* move the padding to the start */
1438 p = state->req_trailer.data;
1439 memmove(p + pad, p, state->req_trailer.length - pad);
1440 memset(p, 0, pad);
1443 return NT_STATUS_OK;
1446 static NTSTATUS prepare_next_frag(struct rpc_api_pipe_req_state *state,
1447 bool *is_last_frag)
1449 size_t auth_len;
1450 size_t frag_len;
1451 uint8_t flags = 0;
1452 size_t pad_len;
1453 size_t data_left;
1454 size_t data_thistime;
1455 size_t trailer_left;
1456 size_t trailer_thistime = 0;
1457 size_t total_left;
1458 size_t total_thistime;
1459 NTSTATUS status;
1460 bool ok;
1461 union dcerpc_payload u;
1463 data_left = state->req_data->length - state->req_data_sent;
1464 trailer_left = state->req_trailer.length - state->req_trailer_sent;
1465 total_left = data_left + trailer_left;
1466 if ((total_left < data_left) || (total_left < trailer_left)) {
1468 * overflow
1470 return NT_STATUS_INVALID_PARAMETER_MIX;
1473 status = dcerpc_guess_sizes(state->cli->auth,
1474 DCERPC_REQUEST_LENGTH, total_left,
1475 state->cli->max_xmit_frag,
1476 &total_thistime,
1477 &frag_len, &auth_len, &pad_len);
1478 if (!NT_STATUS_IS_OK(status)) {
1479 return status;
1482 if (state->req_data_sent == 0) {
1483 flags = DCERPC_PFC_FLAG_FIRST;
1486 if (total_thistime == total_left) {
1487 flags |= DCERPC_PFC_FLAG_LAST;
1490 data_thistime = MIN(total_thistime, data_left);
1491 if (data_thistime < total_thistime) {
1492 trailer_thistime = total_thistime - data_thistime;
1495 data_blob_free(&state->rpc_out);
1497 u = (union dcerpc_payload) {
1498 .request.alloc_hint = total_left,
1499 .request.context_id = 0,
1500 .request.opnum = state->op_num,
1503 if (state->object_uuid) {
1504 flags |= DCERPC_PFC_FLAG_OBJECT_UUID;
1505 u.request.object.object = *state->object_uuid;
1506 frag_len += ndr_size_GUID(state->object_uuid, 0);
1509 status = dcerpc_push_ncacn_packet(state,
1510 DCERPC_PKT_REQUEST,
1511 flags,
1512 auth_len,
1513 state->call_id,
1515 &state->rpc_out);
1516 if (!NT_STATUS_IS_OK(status)) {
1517 return status;
1520 /* explicitly set frag_len here as dcerpc_push_ncacn_packet() can't
1521 * compute it right for requests because the auth trailer is missing
1522 * at this stage */
1523 dcerpc_set_frag_length(&state->rpc_out, frag_len);
1525 if (data_thistime > 0) {
1526 /* Copy in the data. */
1527 ok = data_blob_append(NULL, &state->rpc_out,
1528 state->req_data->data + state->req_data_sent,
1529 data_thistime);
1530 if (!ok) {
1531 return NT_STATUS_NO_MEMORY;
1533 state->req_data_sent += data_thistime;
1536 if (trailer_thistime > 0) {
1537 /* Copy in the verification trailer. */
1538 ok = data_blob_append(NULL, &state->rpc_out,
1539 state->req_trailer.data + state->req_trailer_sent,
1540 trailer_thistime);
1541 if (!ok) {
1542 return NT_STATUS_NO_MEMORY;
1544 state->req_trailer_sent += trailer_thistime;
1547 switch (state->cli->auth->auth_level) {
1548 case DCERPC_AUTH_LEVEL_NONE:
1549 case DCERPC_AUTH_LEVEL_CONNECT:
1550 break;
1551 case DCERPC_AUTH_LEVEL_PACKET:
1552 case DCERPC_AUTH_LEVEL_INTEGRITY:
1553 case DCERPC_AUTH_LEVEL_PRIVACY:
1554 status = dcerpc_add_auth_footer(state->cli->auth, pad_len,
1555 &state->rpc_out);
1556 if (!NT_STATUS_IS_OK(status)) {
1557 return status;
1559 break;
1560 default:
1561 return NT_STATUS_INVALID_PARAMETER;
1564 *is_last_frag = ((flags & DCERPC_PFC_FLAG_LAST) != 0);
1566 return status;
1569 static void rpc_api_pipe_req_write_done(struct tevent_req *subreq)
1571 struct tevent_req *req = tevent_req_callback_data(
1572 subreq, struct tevent_req);
1573 struct rpc_api_pipe_req_state *state = tevent_req_data(
1574 req, struct rpc_api_pipe_req_state);
1575 NTSTATUS status;
1576 bool is_last_frag;
1578 status = rpc_write_recv(subreq);
1579 TALLOC_FREE(subreq);
1580 if (tevent_req_nterror(req, status)) {
1581 return;
1584 status = prepare_next_frag(state, &is_last_frag);
1585 if (tevent_req_nterror(req, status)) {
1586 return;
1589 if (is_last_frag) {
1590 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
1591 &state->rpc_out,
1592 DCERPC_PKT_RESPONSE,
1593 state->call_id);
1594 if (tevent_req_nomem(subreq, req)) {
1595 return;
1597 tevent_req_set_callback(subreq, rpc_api_pipe_req_done, req);
1598 } else {
1599 subreq = rpc_write_send(state, state->ev,
1600 state->cli->transport,
1601 state->rpc_out.data,
1602 state->rpc_out.length);
1603 if (tevent_req_nomem(subreq, req)) {
1604 return;
1606 tevent_req_set_callback(subreq, rpc_api_pipe_req_write_done,
1607 req);
1611 static void rpc_api_pipe_req_done(struct tevent_req *subreq)
1613 struct tevent_req *req = tevent_req_callback_data(
1614 subreq, struct tevent_req);
1615 struct rpc_api_pipe_req_state *state = tevent_req_data(
1616 req, struct rpc_api_pipe_req_state);
1617 NTSTATUS status;
1619 status = rpc_api_pipe_recv(subreq, state, NULL, &state->reply_pdu);
1620 TALLOC_FREE(subreq);
1621 if (tevent_req_nterror(req, status)) {
1622 return;
1625 if (state->cli->auth == NULL) {
1626 tevent_req_done(req);
1627 return;
1630 if (state->verify_bitmask1) {
1631 state->cli->auth->verified_bitmask1 = true;
1634 if (state->verify_pcontext) {
1635 state->cli->verified_pcontext = true;
1638 tevent_req_done(req);
1641 static NTSTATUS rpc_api_pipe_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1642 DATA_BLOB *reply_pdu)
1644 struct rpc_api_pipe_req_state *state = tevent_req_data(
1645 req, struct rpc_api_pipe_req_state);
1646 NTSTATUS status;
1648 if (tevent_req_is_nterror(req, &status)) {
1650 * We always have to initialize to reply pdu, even if there is
1651 * none. The rpccli_* caller routines expect this.
1653 *reply_pdu = data_blob_null;
1654 return status;
1657 /* return data to caller and assign it ownership of memory */
1658 reply_pdu->data = talloc_move(mem_ctx, &state->reply_pdu.data);
1659 reply_pdu->length = state->reply_pdu.length;
1660 state->reply_pdu.length = 0;
1662 return NT_STATUS_OK;
1665 /****************************************************************************
1666 Check the rpc bind acknowledge response.
1667 ****************************************************************************/
1669 static bool check_bind_response(const struct dcerpc_bind_ack *r,
1670 struct rpc_pipe_client *cli)
1672 const struct ndr_syntax_id *transfer = &cli->transfer_syntax;
1673 struct dcerpc_ack_ctx ctx;
1674 bool equal;
1676 if (r->secondary_address_size == 0) {
1677 DEBUG(4,("Ignoring length check -- ASU bug (server didn't fill in the pipe name correctly)\n"));
1680 if (r->num_results < 1 || !r->ctx_list) {
1681 return false;
1684 ctx = r->ctx_list[0];
1686 /* check the transfer syntax */
1687 equal = ndr_syntax_id_equal(&ctx.syntax, transfer);
1688 if (!equal) {
1689 DEBUG(2,("bind_rpc_pipe: transfer syntax differs\n"));
1690 return False;
1693 if (ctx.result != DCERPC_BIND_ACK_RESULT_ACCEPTANCE) {
1694 DBG_NOTICE("bind denied result: %d reason: %x\n",
1695 ctx.result, ctx.reason.value);
1696 return false;
1699 if (r->num_results >= 2) {
1700 const struct dcerpc_ack_ctx *neg = &r->ctx_list[1];
1702 if (neg->result == DCERPC_BIND_ACK_RESULT_NEGOTIATE_ACK) {
1703 cli->bind_time_features = neg->reason.negotiate;
1704 } else {
1705 DBG_DEBUG("bind_time_feature failed - "
1706 "result: %d reason %x\n",
1707 neg->result, neg->reason.value);
1711 DEBUG(5,("check_bind_response: accepted!\n"));
1712 return True;
1715 /*******************************************************************
1716 Creates a DCE/RPC bind authentication response.
1717 This is the packet that is sent back to the server once we
1718 have received a BIND-ACK, to finish the third leg of
1719 the authentication handshake.
1720 ********************************************************************/
1722 static NTSTATUS create_rpc_bind_auth3(TALLOC_CTX *mem_ctx,
1723 struct rpc_pipe_client *cli,
1724 struct pipe_auth_data *auth,
1725 uint32_t rpc_call_id,
1726 DATA_BLOB *pauth_blob,
1727 DATA_BLOB *rpc_out)
1729 NTSTATUS status;
1730 union dcerpc_payload u = { .auth3._pad = 0, };
1732 status = dcerpc_push_dcerpc_auth(mem_ctx,
1733 auth->auth_type,
1734 auth->auth_level,
1735 0, /* auth_pad_length */
1736 auth->auth_context_id,
1737 pauth_blob,
1738 &u.auth3.auth_info);
1739 if (!NT_STATUS_IS_OK(status)) {
1740 return status;
1743 status = dcerpc_push_ncacn_packet(mem_ctx,
1744 DCERPC_PKT_AUTH3,
1745 DCERPC_PFC_FLAG_FIRST |
1746 DCERPC_PFC_FLAG_LAST,
1747 pauth_blob->length,
1748 rpc_call_id,
1750 rpc_out);
1751 data_blob_free(&u.auth3.auth_info);
1752 if (!NT_STATUS_IS_OK(status)) {
1753 DEBUG(0,("create_bind_or_alt_ctx_internal: failed to marshall RPC_HDR_RB.\n"));
1754 return status;
1757 return NT_STATUS_OK;
1760 /*******************************************************************
1761 Creates a DCE/RPC bind alter context authentication request which
1762 may contain a spnego auth blob
1763 ********************************************************************/
1765 static NTSTATUS create_rpc_alter_context(TALLOC_CTX *mem_ctx,
1766 struct pipe_auth_data *auth,
1767 uint32_t rpc_call_id,
1768 const struct ndr_syntax_id *abstract,
1769 const struct ndr_syntax_id *transfer,
1770 const DATA_BLOB *pauth_blob, /* spnego auth blob already created. */
1771 DATA_BLOB *rpc_out)
1773 DATA_BLOB auth_info;
1774 NTSTATUS status;
1776 status = dcerpc_push_dcerpc_auth(mem_ctx,
1777 auth->auth_type,
1778 auth->auth_level,
1779 0, /* auth_pad_length */
1780 auth->auth_context_id,
1781 pauth_blob,
1782 &auth_info);
1783 if (!NT_STATUS_IS_OK(status)) {
1784 return status;
1787 status = create_bind_or_alt_ctx_internal(mem_ctx,
1788 DCERPC_PKT_ALTER,
1789 rpc_call_id,
1790 abstract,
1791 transfer,
1792 &auth_info,
1793 false, /* client_hdr_signing */
1794 rpc_out);
1795 data_blob_free(&auth_info);
1796 return status;
1799 /****************************************************************************
1800 Do an rpc bind.
1801 ****************************************************************************/
1803 struct rpc_pipe_bind_state {
1804 struct tevent_context *ev;
1805 struct rpc_pipe_client *cli;
1806 DATA_BLOB rpc_out;
1807 bool auth3;
1808 uint32_t rpc_call_id;
1811 static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq);
1812 static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
1813 struct rpc_pipe_bind_state *state,
1814 DATA_BLOB *credentials);
1815 static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
1816 struct rpc_pipe_bind_state *state,
1817 DATA_BLOB *credentials);
1819 struct tevent_req *rpc_pipe_bind_send(TALLOC_CTX *mem_ctx,
1820 struct tevent_context *ev,
1821 struct rpc_pipe_client *cli,
1822 struct pipe_auth_data *auth)
1824 struct tevent_req *req, *subreq;
1825 struct rpc_pipe_bind_state *state;
1826 NTSTATUS status;
1828 req = tevent_req_create(mem_ctx, &state, struct rpc_pipe_bind_state);
1829 if (req == NULL) {
1830 return NULL;
1833 DEBUG(5,("Bind RPC Pipe: %s auth_type %u, auth_level %u\n",
1834 rpccli_pipe_txt(talloc_tos(), cli),
1835 (unsigned int)auth->auth_type,
1836 (unsigned int)auth->auth_level ));
1838 state->ev = ev;
1839 state->cli = cli;
1840 state->rpc_call_id = get_rpc_call_id();
1842 cli->auth = talloc_move(cli, &auth);
1844 /* Marshall the outgoing data. */
1845 status = create_rpc_bind_req(state, cli,
1846 cli->auth,
1847 state->rpc_call_id,
1848 &cli->abstract_syntax,
1849 &cli->transfer_syntax,
1850 &state->rpc_out);
1852 if (!NT_STATUS_IS_OK(status) &&
1853 !NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1854 tevent_req_nterror(req, status);
1855 return tevent_req_post(req, ev);
1858 subreq = rpc_api_pipe_send(state, ev, cli, &state->rpc_out,
1859 DCERPC_PKT_BIND_ACK, state->rpc_call_id);
1860 if (tevent_req_nomem(subreq, req)) {
1861 return tevent_req_post(req, ev);
1863 tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
1864 return req;
1867 static void rpc_pipe_bind_step_one_done(struct tevent_req *subreq)
1869 struct tevent_req *req = tevent_req_callback_data(
1870 subreq, struct tevent_req);
1871 struct rpc_pipe_bind_state *state = tevent_req_data(
1872 req, struct rpc_pipe_bind_state);
1873 struct pipe_auth_data *pauth = state->cli->auth;
1874 struct gensec_security *gensec_security;
1875 struct ncacn_packet *pkt = NULL;
1876 struct dcerpc_auth auth;
1877 DATA_BLOB auth_token = { .data = NULL };
1878 NTSTATUS status;
1880 status = rpc_api_pipe_recv(subreq, talloc_tos(), &pkt, NULL);
1881 TALLOC_FREE(subreq);
1882 if (tevent_req_nterror(req, status)) {
1883 DEBUG(3, ("rpc_pipe_bind: %s bind request returned %s\n",
1884 rpccli_pipe_txt(talloc_tos(), state->cli),
1885 nt_errstr(status)));
1886 return;
1889 if (state->auth3) {
1890 tevent_req_done(req);
1891 return;
1894 if (!check_bind_response(&pkt->u.bind_ack, state->cli)) {
1895 DEBUG(2, ("rpc_pipe_bind: check_bind_response failed.\n"));
1896 tevent_req_nterror(req, NT_STATUS_BUFFER_TOO_SMALL);
1897 return;
1900 if (pkt->ptype == DCERPC_PKT_BIND_ACK) {
1901 if (pkt->pfc_flags & DCERPC_PFC_FLAG_SUPPORT_HEADER_SIGN) {
1902 if (pauth->client_hdr_signing) {
1903 pauth->hdr_signing = true;
1908 state->cli->max_xmit_frag = pkt->u.bind_ack.max_xmit_frag;
1910 if (pauth->auth_type == DCERPC_AUTH_TYPE_NONE) {
1911 /* Bind complete. */
1912 tevent_req_done(req);
1913 return;
1916 if (pkt->auth_length == 0) {
1917 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1918 return;
1921 /* get auth credentials */
1922 status = dcerpc_pull_auth_trailer(pkt, talloc_tos(),
1923 &pkt->u.bind_ack.auth_info,
1924 &auth, NULL, true);
1925 if (tevent_req_nterror(req, status)) {
1926 DEBUG(0, ("Failed to pull dcerpc auth: %s.\n",
1927 nt_errstr(status)));
1928 return;
1931 if (auth.auth_type != pauth->auth_type) {
1932 DBG_ERR("Auth type %u mismatch expected %u.\n",
1933 auth.auth_type, pauth->auth_type);
1934 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1935 return;
1938 if (auth.auth_level != pauth->auth_level) {
1939 DBG_ERR("Auth level %u mismatch expected %u.\n",
1940 auth.auth_level, pauth->auth_level);
1941 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1942 return;
1945 if (auth.auth_context_id != pauth->auth_context_id) {
1946 DBG_ERR("Auth context id %"PRIu32" mismatch "
1947 "expected %"PRIu32".\n",
1948 auth.auth_context_id,
1949 pauth->auth_context_id);
1950 tevent_req_nterror(req, NT_STATUS_RPC_PROTOCOL_ERROR);
1951 return;
1955 * For authenticated binds we may need to do 3 or 4 leg binds.
1958 if (pauth->auth_type == DCERPC_AUTH_TYPE_NONE) {
1959 /* Bind complete. */
1960 tevent_req_done(req);
1961 return;
1964 gensec_security = pauth->auth_ctx;
1966 status = gensec_update(gensec_security, state,
1967 auth.credentials, &auth_token);
1968 if (NT_STATUS_EQUAL(status,
1969 NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1970 status = rpc_bind_next_send(req, state,
1971 &auth_token);
1972 } else if (NT_STATUS_IS_OK(status)) {
1973 if (pauth->hdr_signing) {
1974 gensec_want_feature(gensec_security,
1975 GENSEC_FEATURE_SIGN_PKT_HEADER);
1978 if (auth_token.length == 0) {
1979 /* Bind complete. */
1980 tevent_req_done(req);
1981 return;
1983 status = rpc_bind_finish_send(req, state,
1984 &auth_token);
1987 if (!NT_STATUS_IS_OK(status)) {
1988 tevent_req_nterror(req, status);
1990 return;
1993 static NTSTATUS rpc_bind_next_send(struct tevent_req *req,
1994 struct rpc_pipe_bind_state *state,
1995 DATA_BLOB *auth_token)
1997 struct pipe_auth_data *auth = state->cli->auth;
1998 struct tevent_req *subreq;
1999 NTSTATUS status;
2001 /* Now prepare the alter context pdu. */
2002 data_blob_free(&state->rpc_out);
2004 status = create_rpc_alter_context(state, auth,
2005 state->rpc_call_id,
2006 &state->cli->abstract_syntax,
2007 &state->cli->transfer_syntax,
2008 auth_token,
2009 &state->rpc_out);
2010 if (!NT_STATUS_IS_OK(status)) {
2011 return status;
2014 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
2015 &state->rpc_out, DCERPC_PKT_ALTER_RESP,
2016 state->rpc_call_id);
2017 if (subreq == NULL) {
2018 return NT_STATUS_NO_MEMORY;
2020 tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
2021 return NT_STATUS_OK;
2024 static NTSTATUS rpc_bind_finish_send(struct tevent_req *req,
2025 struct rpc_pipe_bind_state *state,
2026 DATA_BLOB *auth_token)
2028 struct pipe_auth_data *auth = state->cli->auth;
2029 struct tevent_req *subreq;
2030 NTSTATUS status;
2032 state->auth3 = true;
2034 /* Now prepare the auth3 context pdu. */
2035 data_blob_free(&state->rpc_out);
2037 status = create_rpc_bind_auth3(state, state->cli, auth,
2038 state->rpc_call_id,
2039 auth_token,
2040 &state->rpc_out);
2041 if (!NT_STATUS_IS_OK(status)) {
2042 return status;
2045 subreq = rpc_api_pipe_send(state, state->ev, state->cli,
2046 &state->rpc_out, DCERPC_PKT_AUTH3,
2047 state->rpc_call_id);
2048 if (subreq == NULL) {
2049 return NT_STATUS_NO_MEMORY;
2051 tevent_req_set_callback(subreq, rpc_pipe_bind_step_one_done, req);
2052 return NT_STATUS_OK;
2055 NTSTATUS rpc_pipe_bind_recv(struct tevent_req *req)
2057 return tevent_req_simple_recv_ntstatus(req);
2060 NTSTATUS rpc_pipe_bind(struct rpc_pipe_client *cli,
2061 struct pipe_auth_data *auth)
2063 TALLOC_CTX *frame = talloc_stackframe();
2064 struct tevent_context *ev;
2065 struct tevent_req *req;
2066 NTSTATUS status = NT_STATUS_OK;
2068 ev = samba_tevent_context_init(frame);
2069 if (ev == NULL) {
2070 status = NT_STATUS_NO_MEMORY;
2071 goto fail;
2074 req = rpc_pipe_bind_send(frame, ev, cli, auth);
2075 if (req == NULL) {
2076 status = NT_STATUS_NO_MEMORY;
2077 goto fail;
2080 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
2081 goto fail;
2084 status = rpc_pipe_bind_recv(req);
2085 fail:
2086 TALLOC_FREE(frame);
2087 return status;
2090 #define RPCCLI_DEFAULT_TIMEOUT 10000 /* 10 seconds. */
2092 unsigned int rpccli_set_timeout(struct rpc_pipe_client *rpc_cli,
2093 unsigned int timeout)
2095 if (rpc_cli == NULL) {
2096 return RPCCLI_DEFAULT_TIMEOUT;
2099 if (rpc_cli->binding_handle == NULL) {
2100 return RPCCLI_DEFAULT_TIMEOUT;
2103 return dcerpc_binding_handle_set_timeout(rpc_cli->binding_handle,
2104 timeout);
2107 bool rpccli_is_connected(struct rpc_pipe_client *rpc_cli)
2109 if (rpc_cli == NULL) {
2110 return false;
2113 if (rpc_cli->binding_handle == NULL) {
2114 return false;
2117 return dcerpc_binding_handle_is_connected(rpc_cli->binding_handle);
2120 struct rpccli_bh_state {
2121 struct rpc_pipe_client *rpc_cli;
2124 static bool rpccli_bh_is_connected(struct dcerpc_binding_handle *h)
2126 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2127 struct rpccli_bh_state);
2128 struct rpc_cli_transport *transport = hs->rpc_cli->transport;
2130 if (transport == NULL) {
2131 return false;
2134 if (transport->is_connected == NULL) {
2135 return false;
2138 return transport->is_connected(transport->priv);
2141 static uint32_t rpccli_bh_set_timeout(struct dcerpc_binding_handle *h,
2142 uint32_t timeout)
2144 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2145 struct rpccli_bh_state);
2146 struct rpc_cli_transport *transport = hs->rpc_cli->transport;
2147 unsigned int old;
2149 if (transport == NULL) {
2150 return RPCCLI_DEFAULT_TIMEOUT;
2153 if (transport->set_timeout == NULL) {
2154 return RPCCLI_DEFAULT_TIMEOUT;
2157 old = transport->set_timeout(transport->priv, timeout);
2158 if (old == 0) {
2159 return RPCCLI_DEFAULT_TIMEOUT;
2162 return old;
2165 static void rpccli_bh_auth_info(struct dcerpc_binding_handle *h,
2166 enum dcerpc_AuthType *auth_type,
2167 enum dcerpc_AuthLevel *auth_level)
2169 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2170 struct rpccli_bh_state);
2172 if (hs->rpc_cli == NULL) {
2173 return;
2176 if (hs->rpc_cli->auth == NULL) {
2177 return;
2180 *auth_type = hs->rpc_cli->auth->auth_type;
2181 *auth_level = hs->rpc_cli->auth->auth_level;
2184 struct rpccli_bh_raw_call_state {
2185 DATA_BLOB in_data;
2186 DATA_BLOB out_data;
2187 uint32_t out_flags;
2190 static void rpccli_bh_raw_call_done(struct tevent_req *subreq);
2192 static struct tevent_req *rpccli_bh_raw_call_send(TALLOC_CTX *mem_ctx,
2193 struct tevent_context *ev,
2194 struct dcerpc_binding_handle *h,
2195 const struct GUID *object,
2196 uint32_t opnum,
2197 uint32_t in_flags,
2198 const uint8_t *in_data,
2199 size_t in_length)
2201 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2202 struct rpccli_bh_state);
2203 struct tevent_req *req;
2204 struct rpccli_bh_raw_call_state *state;
2205 bool ok;
2206 struct tevent_req *subreq;
2208 req = tevent_req_create(mem_ctx, &state,
2209 struct rpccli_bh_raw_call_state);
2210 if (req == NULL) {
2211 return NULL;
2213 state->in_data.data = discard_const_p(uint8_t, in_data);
2214 state->in_data.length = in_length;
2216 ok = rpccli_bh_is_connected(h);
2217 if (!ok) {
2218 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
2219 return tevent_req_post(req, ev);
2222 subreq = rpc_api_pipe_req_send(state, ev, hs->rpc_cli,
2223 opnum, object, &state->in_data);
2224 if (tevent_req_nomem(subreq, req)) {
2225 return tevent_req_post(req, ev);
2227 tevent_req_set_callback(subreq, rpccli_bh_raw_call_done, req);
2229 return req;
2232 static void rpccli_bh_raw_call_done(struct tevent_req *subreq)
2234 struct tevent_req *req =
2235 tevent_req_callback_data(subreq,
2236 struct tevent_req);
2237 struct rpccli_bh_raw_call_state *state =
2238 tevent_req_data(req,
2239 struct rpccli_bh_raw_call_state);
2240 NTSTATUS status;
2242 state->out_flags = 0;
2244 /* TODO: support bigendian responses */
2246 status = rpc_api_pipe_req_recv(subreq, state, &state->out_data);
2247 TALLOC_FREE(subreq);
2248 if (tevent_req_nterror(req, status)) {
2249 return;
2252 tevent_req_done(req);
2255 static NTSTATUS rpccli_bh_raw_call_recv(struct tevent_req *req,
2256 TALLOC_CTX *mem_ctx,
2257 uint8_t **out_data,
2258 size_t *out_length,
2259 uint32_t *out_flags)
2261 struct rpccli_bh_raw_call_state *state =
2262 tevent_req_data(req,
2263 struct rpccli_bh_raw_call_state);
2264 NTSTATUS status;
2266 if (tevent_req_is_nterror(req, &status)) {
2267 tevent_req_received(req);
2268 return status;
2271 *out_data = talloc_move(mem_ctx, &state->out_data.data);
2272 *out_length = state->out_data.length;
2273 *out_flags = state->out_flags;
2274 tevent_req_received(req);
2275 return NT_STATUS_OK;
2278 struct rpccli_bh_disconnect_state {
2279 uint8_t _dummy;
2282 static struct tevent_req *rpccli_bh_disconnect_send(TALLOC_CTX *mem_ctx,
2283 struct tevent_context *ev,
2284 struct dcerpc_binding_handle *h)
2286 struct rpccli_bh_state *hs = dcerpc_binding_handle_data(h,
2287 struct rpccli_bh_state);
2288 struct tevent_req *req;
2289 struct rpccli_bh_disconnect_state *state;
2290 bool ok;
2292 req = tevent_req_create(mem_ctx, &state,
2293 struct rpccli_bh_disconnect_state);
2294 if (req == NULL) {
2295 return NULL;
2298 ok = rpccli_bh_is_connected(h);
2299 if (!ok) {
2300 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
2301 return tevent_req_post(req, ev);
2305 * TODO: do a real async disconnect ...
2307 * For now we do it sync...
2309 TALLOC_FREE(hs->rpc_cli->transport);
2310 hs->rpc_cli = NULL;
2312 tevent_req_done(req);
2313 return tevent_req_post(req, ev);
2316 static NTSTATUS rpccli_bh_disconnect_recv(struct tevent_req *req)
2318 return tevent_req_simple_recv_ntstatus(req);
2321 static bool rpccli_bh_ref_alloc(struct dcerpc_binding_handle *h)
2323 return true;
2326 static void rpccli_bh_do_ndr_print(struct dcerpc_binding_handle *h,
2327 ndr_flags_type ndr_flags,
2328 const void *_struct_ptr,
2329 const struct ndr_interface_call *call)
2331 void *struct_ptr = discard_const(_struct_ptr);
2333 if (DEBUGLEVEL < 10) {
2334 return;
2337 if (ndr_flags & NDR_IN) {
2338 ndr_print_function_debug(call->ndr_print,
2339 call->name,
2340 ndr_flags,
2341 struct_ptr);
2343 if (ndr_flags & NDR_OUT) {
2344 ndr_print_function_debug(call->ndr_print,
2345 call->name,
2346 ndr_flags,
2347 struct_ptr);
2351 static const struct dcerpc_binding_handle_ops rpccli_bh_ops = {
2352 .name = "rpccli",
2353 .is_connected = rpccli_bh_is_connected,
2354 .set_timeout = rpccli_bh_set_timeout,
2355 .auth_info = rpccli_bh_auth_info,
2356 .raw_call_send = rpccli_bh_raw_call_send,
2357 .raw_call_recv = rpccli_bh_raw_call_recv,
2358 .disconnect_send = rpccli_bh_disconnect_send,
2359 .disconnect_recv = rpccli_bh_disconnect_recv,
2361 .ref_alloc = rpccli_bh_ref_alloc,
2362 .do_ndr_print = rpccli_bh_do_ndr_print,
2365 /* initialise a rpc_pipe_client binding handle */
2366 struct dcerpc_binding_handle *rpccli_bh_create(struct rpc_pipe_client *c,
2367 const struct GUID *object,
2368 const struct ndr_interface_table *table)
2370 struct dcerpc_binding_handle *h;
2371 struct rpccli_bh_state *hs;
2373 h = dcerpc_binding_handle_create(c,
2374 &rpccli_bh_ops,
2375 object,
2376 table,
2377 &hs,
2378 struct rpccli_bh_state,
2379 __location__);
2380 if (h == NULL) {
2381 return NULL;
2383 hs->rpc_cli = c;
2385 return h;
2388 NTSTATUS rpccli_anon_bind_data(TALLOC_CTX *mem_ctx,
2389 struct pipe_auth_data **presult)
2391 struct pipe_auth_data *result;
2392 struct auth_generic_state *auth_generic_ctx;
2393 NTSTATUS status;
2395 result = talloc_zero(mem_ctx, struct pipe_auth_data);
2396 if (result == NULL) {
2397 return NT_STATUS_NO_MEMORY;
2400 result->auth_type = DCERPC_AUTH_TYPE_NONE;
2401 result->auth_level = DCERPC_AUTH_LEVEL_NONE;
2402 result->auth_context_id = 0;
2404 status = auth_generic_client_prepare(result,
2405 &auth_generic_ctx);
2406 if (!NT_STATUS_IS_OK(status)) {
2407 DEBUG(1, ("Failed to create auth_generic context: %s\n",
2408 nt_errstr(status)));
2411 status = auth_generic_set_username(auth_generic_ctx, "");
2412 if (!NT_STATUS_IS_OK(status)) {
2413 DEBUG(1, ("Failed to set username: %s\n",
2414 nt_errstr(status)));
2417 status = auth_generic_set_domain(auth_generic_ctx, "");
2418 if (!NT_STATUS_IS_OK(status)) {
2419 DEBUG(1, ("Failed to set domain: %s\n",
2420 nt_errstr(status)));
2421 return status;
2424 status = gensec_set_credentials(auth_generic_ctx->gensec_security,
2425 auth_generic_ctx->credentials);
2426 if (!NT_STATUS_IS_OK(status)) {
2427 DEBUG(1, ("Failed to set GENSEC credentials: %s\n",
2428 nt_errstr(status)));
2429 return status;
2431 talloc_unlink(auth_generic_ctx, auth_generic_ctx->credentials);
2432 auth_generic_ctx->credentials = NULL;
2434 result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2435 talloc_free(auth_generic_ctx);
2436 *presult = result;
2437 return NT_STATUS_OK;
2440 static NTSTATUS rpccli_generic_bind_data(TALLOC_CTX *mem_ctx,
2441 enum dcerpc_AuthType auth_type,
2442 enum dcerpc_AuthLevel auth_level,
2443 const char *server,
2444 const char *target_service,
2445 const char *domain,
2446 const char *username,
2447 const char *password,
2448 enum credentials_use_kerberos use_kerberos,
2449 struct netlogon_creds_CredentialState *creds,
2450 struct pipe_auth_data **presult)
2452 struct auth_generic_state *auth_generic_ctx;
2453 struct pipe_auth_data *result;
2454 NTSTATUS status;
2456 result = talloc_zero(mem_ctx, struct pipe_auth_data);
2457 if (result == NULL) {
2458 return NT_STATUS_NO_MEMORY;
2461 result->auth_type = auth_type;
2462 result->auth_level = auth_level;
2463 result->auth_context_id = 1;
2465 status = auth_generic_client_prepare(result,
2466 &auth_generic_ctx);
2467 if (!NT_STATUS_IS_OK(status)) {
2468 goto fail;
2471 status = auth_generic_set_username(auth_generic_ctx, username);
2472 if (!NT_STATUS_IS_OK(status)) {
2473 goto fail;
2476 status = auth_generic_set_domain(auth_generic_ctx, domain);
2477 if (!NT_STATUS_IS_OK(status)) {
2478 goto fail;
2481 status = auth_generic_set_password(auth_generic_ctx, password);
2482 if (!NT_STATUS_IS_OK(status)) {
2483 goto fail;
2486 status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
2487 if (!NT_STATUS_IS_OK(status)) {
2488 goto fail;
2491 status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
2492 if (!NT_STATUS_IS_OK(status)) {
2493 goto fail;
2496 cli_credentials_set_kerberos_state(auth_generic_ctx->credentials,
2497 use_kerberos,
2498 CRED_SPECIFIED);
2499 cli_credentials_set_netlogon_creds(auth_generic_ctx->credentials, creds);
2501 status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
2502 if (!NT_STATUS_IS_OK(status)) {
2503 goto fail;
2506 result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2507 talloc_free(auth_generic_ctx);
2508 *presult = result;
2509 return NT_STATUS_OK;
2511 fail:
2512 TALLOC_FREE(result);
2513 return status;
2516 /* This routine steals the creds pointer that is passed in */
2517 static NTSTATUS rpccli_generic_bind_data_from_creds(TALLOC_CTX *mem_ctx,
2518 enum dcerpc_AuthType auth_type,
2519 enum dcerpc_AuthLevel auth_level,
2520 const char *server,
2521 const char *target_service,
2522 struct cli_credentials *creds,
2523 struct pipe_auth_data **presult)
2525 struct auth_generic_state *auth_generic_ctx;
2526 struct pipe_auth_data *result;
2527 NTSTATUS status;
2529 result = talloc_zero(mem_ctx, struct pipe_auth_data);
2530 if (result == NULL) {
2531 return NT_STATUS_NO_MEMORY;
2534 result->auth_type = auth_type;
2535 result->auth_level = auth_level;
2536 result->auth_context_id = 1;
2538 status = auth_generic_client_prepare(result,
2539 &auth_generic_ctx);
2540 if (!NT_STATUS_IS_OK(status)) {
2541 goto fail;
2544 status = auth_generic_set_creds(auth_generic_ctx, creds);
2545 if (!NT_STATUS_IS_OK(status)) {
2546 goto fail;
2549 status = gensec_set_target_service(auth_generic_ctx->gensec_security, target_service);
2550 if (!NT_STATUS_IS_OK(status)) {
2551 goto fail;
2554 status = gensec_set_target_hostname(auth_generic_ctx->gensec_security, server);
2555 if (!NT_STATUS_IS_OK(status)) {
2556 goto fail;
2559 status = auth_generic_client_start_by_authtype(auth_generic_ctx, auth_type, auth_level);
2560 if (!NT_STATUS_IS_OK(status)) {
2561 goto fail;
2564 result->auth_ctx = talloc_move(result, &auth_generic_ctx->gensec_security);
2565 talloc_free(auth_generic_ctx);
2566 *presult = result;
2567 return NT_STATUS_OK;
2569 fail:
2570 TALLOC_FREE(result);
2571 return status;
2574 NTSTATUS rpccli_ncalrpc_bind_data(TALLOC_CTX *mem_ctx,
2575 struct pipe_auth_data **presult)
2577 return rpccli_generic_bind_data(mem_ctx,
2578 DCERPC_AUTH_TYPE_NCALRPC_AS_SYSTEM,
2579 DCERPC_AUTH_LEVEL_CONNECT,
2580 NULL, /* server */
2581 "host", /* target_service */
2582 NAME_NT_AUTHORITY, /* domain */
2583 "SYSTEM",
2584 NULL, /* password */
2585 CRED_USE_KERBEROS_DISABLED,
2586 NULL, /* netlogon_creds_CredentialState */
2587 presult);
2591 * Create an rpc pipe client struct, connecting to a tcp port.
2593 static NTSTATUS rpc_pipe_open_tcp_port(TALLOC_CTX *mem_ctx, const char *host,
2594 const struct sockaddr_storage *ss_addr,
2595 uint16_t port,
2596 const struct ndr_interface_table *table,
2597 struct rpc_pipe_client **presult)
2599 struct rpc_pipe_client *result;
2600 struct sockaddr_storage addr;
2601 NTSTATUS status;
2602 int fd;
2604 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
2605 if (result == NULL) {
2606 return NT_STATUS_NO_MEMORY;
2609 result->abstract_syntax = table->syntax_id;
2610 result->transfer_syntax = ndr_transfer_syntax_ndr;
2612 result->desthost = talloc_strdup(result, host);
2613 if (result->desthost == NULL) {
2614 status = NT_STATUS_NO_MEMORY;
2615 goto fail;
2618 result->srv_name_slash = talloc_asprintf_strupper_m(
2619 result, "\\\\%s", result->desthost);
2620 if (result->srv_name_slash == NULL) {
2621 status = NT_STATUS_NO_MEMORY;
2622 goto fail;
2625 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
2627 if (ss_addr == NULL) {
2628 if (!resolve_name(host, &addr, NBT_NAME_SERVER, false)) {
2629 status = NT_STATUS_NOT_FOUND;
2630 goto fail;
2632 } else {
2633 addr = *ss_addr;
2636 status = open_socket_out(&addr, port, 60*1000, &fd);
2637 if (!NT_STATUS_IS_OK(status)) {
2638 goto fail;
2640 set_socket_options(fd, lp_socket_options());
2642 status = rpc_transport_sock_init(result, fd, &result->transport);
2643 if (!NT_STATUS_IS_OK(status)) {
2644 close(fd);
2645 goto fail;
2648 result->transport->transport = NCACN_IP_TCP;
2650 result->binding_handle = rpccli_bh_create(result, NULL, table);
2651 if (result->binding_handle == NULL) {
2652 TALLOC_FREE(result);
2653 return NT_STATUS_NO_MEMORY;
2656 *presult = result;
2657 return NT_STATUS_OK;
2659 fail:
2660 TALLOC_FREE(result);
2661 return status;
2664 static NTSTATUS rpccli_epm_map_binding(
2665 struct dcerpc_binding_handle *epm_connection,
2666 struct dcerpc_binding *binding,
2667 TALLOC_CTX *mem_ctx,
2668 char **pendpoint)
2670 TALLOC_CTX *frame = talloc_stackframe();
2671 enum dcerpc_transport_t transport =
2672 dcerpc_binding_get_transport(binding);
2673 enum dcerpc_transport_t res_transport;
2674 struct dcerpc_binding *res_binding = NULL;
2675 struct epm_twr_t *map_tower = NULL;
2676 struct epm_twr_p_t res_towers = { .twr = NULL };
2677 struct policy_handle *entry_handle = NULL;
2678 uint32_t num_towers = 0;
2679 const uint32_t max_towers = 1;
2680 const char *endpoint = NULL;
2681 char *tmp = NULL;
2682 uint32_t result;
2683 NTSTATUS status;
2685 map_tower = talloc_zero(frame, struct epm_twr_t);
2686 if (map_tower == NULL) {
2687 goto nomem;
2690 status = dcerpc_binding_build_tower(
2691 frame, binding, &(map_tower->tower));
2692 if (!NT_STATUS_IS_OK(status)) {
2693 DBG_DEBUG("dcerpc_binding_build_tower failed: %s\n",
2694 nt_errstr(status));
2695 goto done;
2698 res_towers.twr = talloc_array(frame, struct epm_twr_t, max_towers);
2699 if (res_towers.twr == NULL) {
2700 goto nomem;
2703 entry_handle = talloc_zero(frame, struct policy_handle);
2704 if (entry_handle == NULL) {
2705 goto nomem;
2708 status = dcerpc_epm_Map(
2709 epm_connection,
2710 frame,
2711 NULL,
2712 map_tower,
2713 entry_handle,
2714 max_towers,
2715 &num_towers,
2716 &res_towers,
2717 &result);
2719 if (!NT_STATUS_IS_OK(status)) {
2720 DBG_DEBUG("dcerpc_epm_Map failed: %s\n", nt_errstr(status));
2721 goto done;
2724 if (result != EPMAPPER_STATUS_OK) {
2725 DBG_DEBUG("dcerpc_epm_Map returned %"PRIu32"\n", result);
2726 status = NT_STATUS_NOT_FOUND;
2727 goto done;
2730 if (num_towers != 1) {
2731 DBG_DEBUG("dcerpc_epm_Map returned %"PRIu32" towers\n",
2732 num_towers);
2733 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2734 goto done;
2737 status = dcerpc_binding_from_tower(
2738 frame, &(res_towers.twr->tower), &res_binding);
2739 if (!NT_STATUS_IS_OK(status)) {
2740 DBG_DEBUG("dcerpc_binding_from_tower failed: %s\n",
2741 nt_errstr(status));
2742 goto done;
2745 res_transport = dcerpc_binding_get_transport(res_binding);
2746 if (res_transport != transport) {
2747 DBG_DEBUG("dcerpc_epm_Map returned transport %d, "
2748 "expected %d\n",
2749 (int)res_transport,
2750 (int)transport);
2751 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2752 goto done;
2755 endpoint = dcerpc_binding_get_string_option(res_binding, "endpoint");
2756 if (endpoint == NULL) {
2757 DBG_DEBUG("dcerpc_epm_Map returned no endpoint\n");
2758 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
2759 goto done;
2762 tmp = talloc_strdup(mem_ctx, endpoint);
2763 if (tmp == NULL) {
2764 goto nomem;
2766 *pendpoint = tmp;
2768 status = NT_STATUS_OK;
2769 goto done;
2771 nomem:
2772 status = NT_STATUS_NO_MEMORY;
2773 done:
2774 TALLOC_FREE(frame);
2775 return status;
2778 static NTSTATUS rpccli_epm_map_interface(
2779 struct dcerpc_binding_handle *epm_connection,
2780 enum dcerpc_transport_t transport,
2781 const struct ndr_syntax_id *iface,
2782 TALLOC_CTX *mem_ctx,
2783 char **pendpoint)
2785 struct dcerpc_binding *binding = NULL;
2786 char *endpoint = NULL;
2787 NTSTATUS status;
2789 status = dcerpc_parse_binding(mem_ctx, "", &binding);
2790 if (!NT_STATUS_IS_OK(status)) {
2791 DBG_DEBUG("dcerpc_parse_binding failed: %s\n",
2792 nt_errstr(status));
2793 goto done;
2796 status = dcerpc_binding_set_transport(binding, transport);
2797 if (!NT_STATUS_IS_OK(status)) {
2798 DBG_DEBUG("dcerpc_binding_set_transport failed: %s\n",
2799 nt_errstr(status));
2800 goto done;
2803 status = dcerpc_binding_set_abstract_syntax(binding, iface);
2804 if (!NT_STATUS_IS_OK(status)) {
2805 DBG_DEBUG("dcerpc_binding_set_abstract_syntax failed: %s\n",
2806 nt_errstr(status));
2807 goto done;
2810 status = rpccli_epm_map_binding(
2811 epm_connection, binding, mem_ctx, &endpoint);
2812 if (!NT_STATUS_IS_OK(status)) {
2813 DBG_DEBUG("rpccli_epm_map_binding failed: %s\n",
2814 nt_errstr(status));
2815 goto done;
2817 *pendpoint = endpoint;
2819 done:
2820 TALLOC_FREE(binding);
2821 return status;
2825 * Determine the tcp port on which a dcerpc interface is listening
2826 * for the ncacn_ip_tcp transport via the endpoint mapper of the
2827 * target host.
2829 static NTSTATUS rpc_pipe_get_tcp_port(const char *host,
2830 const struct sockaddr_storage *addr,
2831 const struct ndr_interface_table *table,
2832 uint16_t *pport)
2834 NTSTATUS status;
2835 struct rpc_pipe_client *epm_pipe = NULL;
2836 struct pipe_auth_data *auth = NULL;
2837 char *endpoint = NULL;
2838 TALLOC_CTX *tmp_ctx = talloc_stackframe();
2840 if (pport == NULL) {
2841 status = NT_STATUS_INVALID_PARAMETER;
2842 goto done;
2845 if (ndr_syntax_id_equal(&table->syntax_id,
2846 &ndr_table_epmapper.syntax_id)) {
2847 *pport = 135;
2848 status = NT_STATUS_OK;
2849 goto done;
2852 /* open the connection to the endpoint mapper */
2853 status = rpc_pipe_open_tcp_port(tmp_ctx, host, addr, 135,
2854 &ndr_table_epmapper,
2855 &epm_pipe);
2857 if (!NT_STATUS_IS_OK(status)) {
2858 goto done;
2861 status = rpccli_anon_bind_data(tmp_ctx, &auth);
2862 if (!NT_STATUS_IS_OK(status)) {
2863 goto done;
2866 status = rpc_pipe_bind(epm_pipe, auth);
2867 if (!NT_STATUS_IS_OK(status)) {
2868 goto done;
2871 status = rpccli_epm_map_interface(
2872 epm_pipe->binding_handle,
2873 NCACN_IP_TCP,
2874 &table->syntax_id,
2875 tmp_ctx,
2876 &endpoint);
2877 if (!NT_STATUS_IS_OK(status)) {
2878 DBG_DEBUG("rpccli_epm_map_interface failed: %s\n",
2879 nt_errstr(status));
2880 goto done;
2883 *pport = (uint16_t)atoi(endpoint);
2885 done:
2886 TALLOC_FREE(tmp_ctx);
2887 return status;
2891 * Create a rpc pipe client struct, connecting to a host via tcp.
2892 * The port is determined by asking the endpoint mapper on the given
2893 * host.
2895 static NTSTATUS rpc_pipe_open_tcp(
2896 TALLOC_CTX *mem_ctx,
2897 const char *host,
2898 const struct sockaddr_storage *addr,
2899 const struct ndr_interface_table *table,
2900 struct rpc_pipe_client **presult)
2902 NTSTATUS status;
2903 uint16_t port = 0;
2905 status = rpc_pipe_get_tcp_port(host, addr, table, &port);
2906 if (!NT_STATUS_IS_OK(status)) {
2907 return status;
2910 return rpc_pipe_open_tcp_port(mem_ctx, host, addr, port,
2911 table, presult);
2914 static NTSTATUS rpc_pipe_get_ncalrpc_name(
2915 const struct ndr_syntax_id *iface,
2916 TALLOC_CTX *mem_ctx,
2917 char **psocket_name)
2919 TALLOC_CTX *frame = talloc_stackframe();
2920 struct rpc_pipe_client *epm_pipe = NULL;
2921 struct pipe_auth_data *auth = NULL;
2922 NTSTATUS status = NT_STATUS_OK;
2923 bool is_epm;
2925 is_epm = ndr_syntax_id_equal(iface, &ndr_table_epmapper.syntax_id);
2926 if (is_epm) {
2927 char *endpoint = talloc_strdup(mem_ctx, "EPMAPPER");
2928 if (endpoint == NULL) {
2929 status = NT_STATUS_NO_MEMORY;
2930 goto done;
2932 *psocket_name = endpoint;
2933 goto done;
2936 status = rpc_pipe_open_ncalrpc(
2937 frame, &ndr_table_epmapper, &epm_pipe);
2938 if (!NT_STATUS_IS_OK(status)) {
2939 DBG_DEBUG("rpc_pipe_open_ncalrpc failed: %s\n",
2940 nt_errstr(status));
2941 goto done;
2944 status = rpccli_anon_bind_data(epm_pipe, &auth);
2945 if (!NT_STATUS_IS_OK(status)) {
2946 DBG_DEBUG("rpccli_anon_bind_data failed: %s\n",
2947 nt_errstr(status));
2948 goto done;
2951 status = rpc_pipe_bind(epm_pipe, auth);
2952 if (!NT_STATUS_IS_OK(status)) {
2953 DBG_DEBUG("rpc_pipe_bind failed: %s\n", nt_errstr(status));
2954 goto done;
2957 status = rpccli_epm_map_interface(
2958 epm_pipe->binding_handle,
2959 NCALRPC,
2960 iface,
2961 mem_ctx,
2962 psocket_name);
2963 if (!NT_STATUS_IS_OK(status)) {
2964 DBG_DEBUG("rpccli_epm_map_interface failed: %s\n",
2965 nt_errstr(status));
2968 done:
2969 TALLOC_FREE(frame);
2970 return status;
2973 /********************************************************************
2974 Create a rpc pipe client struct, connecting to a unix domain socket
2975 ********************************************************************/
2976 NTSTATUS rpc_pipe_open_ncalrpc(TALLOC_CTX *mem_ctx,
2977 const struct ndr_interface_table *table,
2978 struct rpc_pipe_client **presult)
2980 char *socket_name = NULL;
2981 struct rpc_pipe_client *result;
2982 struct sockaddr_un addr = { .sun_family = AF_UNIX };
2983 socklen_t salen = sizeof(addr);
2984 int pathlen;
2985 NTSTATUS status;
2986 int fd = -1;
2988 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
2989 if (result == NULL) {
2990 return NT_STATUS_NO_MEMORY;
2993 status = rpc_pipe_get_ncalrpc_name(
2994 &table->syntax_id, result, &socket_name);
2995 if (!NT_STATUS_IS_OK(status)) {
2996 DBG_DEBUG("rpc_pipe_get_ncalrpc_name failed: %s\n",
2997 nt_errstr(status));
2998 goto fail;
3001 pathlen = snprintf(
3002 addr.sun_path,
3003 sizeof(addr.sun_path),
3004 "%s/%s",
3005 lp_ncalrpc_dir(),
3006 socket_name);
3007 if ((pathlen < 0) || ((size_t)pathlen >= sizeof(addr.sun_path))) {
3008 DBG_DEBUG("socket_path for %s too long\n", socket_name);
3009 status = NT_STATUS_NAME_TOO_LONG;
3010 goto fail;
3012 TALLOC_FREE(socket_name);
3014 result->abstract_syntax = table->syntax_id;
3015 result->transfer_syntax = ndr_transfer_syntax_ndr;
3017 result->desthost = get_myname(result);
3018 if (result->desthost == NULL) {
3019 status = NT_STATUS_NO_MEMORY;
3020 goto fail;
3023 result->srv_name_slash = talloc_asprintf_strupper_m(
3024 result, "\\\\%s", result->desthost);
3025 if (result->srv_name_slash == NULL) {
3026 status = NT_STATUS_NO_MEMORY;
3027 goto fail;
3030 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
3032 fd = socket(AF_UNIX, SOCK_STREAM, 0);
3033 if (fd == -1) {
3034 status = map_nt_error_from_unix(errno);
3035 goto fail;
3038 if (connect(fd, (struct sockaddr *)(void *)&addr, salen) == -1) {
3039 DBG_WARNING("connect(%s) failed: %s\n",
3040 addr.sun_path,
3041 strerror(errno));
3042 status = map_nt_error_from_unix(errno);
3043 goto fail;
3046 status = rpc_transport_sock_init(result, fd, &result->transport);
3047 if (!NT_STATUS_IS_OK(status)) {
3048 goto fail;
3050 fd = -1;
3052 result->transport->transport = NCALRPC;
3054 result->binding_handle = rpccli_bh_create(result, NULL, table);
3055 if (result->binding_handle == NULL) {
3056 status = NT_STATUS_NO_MEMORY;
3057 goto fail;
3060 *presult = result;
3061 return NT_STATUS_OK;
3063 fail:
3064 if (fd != -1) {
3065 close(fd);
3067 TALLOC_FREE(result);
3068 return status;
3071 NTSTATUS rpc_pipe_open_local_np(
3072 TALLOC_CTX *mem_ctx,
3073 const struct ndr_interface_table *table,
3074 const char *remote_client_name,
3075 const struct tsocket_address *remote_client_addr,
3076 const char *local_server_name,
3077 const struct tsocket_address *local_server_addr,
3078 const struct auth_session_info *session_info,
3079 struct rpc_pipe_client **presult)
3081 struct rpc_pipe_client *result = NULL;
3082 struct pipe_auth_data *auth = NULL;
3083 const char *pipe_name = NULL;
3084 struct tstream_context *npa_stream = NULL;
3085 NTSTATUS status = NT_STATUS_NO_MEMORY;
3086 int ret;
3088 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
3089 if (result == NULL) {
3090 goto fail;
3092 result->abstract_syntax = table->syntax_id;
3093 result->transfer_syntax = ndr_transfer_syntax_ndr;
3094 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
3096 pipe_name = dcerpc_default_transport_endpoint(
3097 result, NCACN_NP, table);
3098 if (pipe_name == NULL) {
3099 DBG_DEBUG("dcerpc_default_transport_endpoint failed\n");
3100 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
3101 goto fail;
3104 if (local_server_name == NULL) {
3105 result->desthost = get_myname(result);
3106 } else {
3107 result->desthost = talloc_strdup(result, local_server_name);
3109 if (result->desthost == NULL) {
3110 goto fail;
3112 result->srv_name_slash = talloc_asprintf_strupper_m(
3113 result, "\\\\%s", result->desthost);
3114 if (result->srv_name_slash == NULL) {
3115 goto fail;
3118 ret = local_np_connect(
3119 pipe_name,
3120 NCALRPC,
3121 remote_client_name,
3122 remote_client_addr,
3123 local_server_name,
3124 local_server_addr,
3125 session_info,
3126 true,
3127 result,
3128 &npa_stream);
3129 if (ret != 0) {
3130 DBG_DEBUG("local_np_connect for %s and "
3131 "user %s\\%s failed: %s\n",
3132 pipe_name,
3133 session_info->info->domain_name,
3134 session_info->info->account_name,
3135 strerror(ret));
3136 status = map_nt_error_from_unix(ret);
3137 goto fail;
3140 status = rpc_transport_tstream_init(
3141 result, &npa_stream, &result->transport);
3142 if (!NT_STATUS_IS_OK(status)) {
3143 DBG_DEBUG("rpc_transport_tstream_init failed: %s\n",
3144 nt_errstr(status));
3145 goto fail;
3148 result->binding_handle = rpccli_bh_create(result, NULL, table);
3149 if (result->binding_handle == NULL) {
3150 status = NT_STATUS_NO_MEMORY;
3151 DBG_DEBUG("Failed to create binding handle.\n");
3152 goto fail;
3155 status = rpccli_anon_bind_data(result, &auth);
3156 if (!NT_STATUS_IS_OK(status)) {
3157 DBG_DEBUG("rpccli_anon_bind_data failed: %s\n",
3158 nt_errstr(status));
3159 goto fail;
3162 status = rpc_pipe_bind(result, auth);
3163 if (!NT_STATUS_IS_OK(status)) {
3164 DBG_DEBUG("rpc_pipe_bind failed: %s\n", nt_errstr(status));
3165 goto fail;
3168 *presult = result;
3169 return NT_STATUS_OK;
3171 fail:
3172 TALLOC_FREE(result);
3173 return status;
3176 struct rpc_pipe_client_np_ref {
3177 struct cli_state *cli;
3178 struct rpc_pipe_client *pipe;
3181 static int rpc_pipe_client_np_ref_destructor(struct rpc_pipe_client_np_ref *np_ref)
3183 DLIST_REMOVE(np_ref->cli->pipe_list, np_ref->pipe);
3184 return 0;
3187 /****************************************************************************
3188 Open a named pipe over SMB to a remote server.
3190 * CAVEAT CALLER OF THIS FUNCTION:
3191 * The returned rpc_pipe_client saves a copy of the cli_state cli pointer,
3192 * so be sure that this function is called AFTER any structure (vs pointer)
3193 * assignment of the cli. In particular, libsmbclient does structure
3194 * assignments of cli, which invalidates the data in the returned
3195 * rpc_pipe_client if this function is called before the structure assignment
3196 * of cli.
3198 ****************************************************************************/
3200 struct rpc_pipe_open_np_state {
3201 struct cli_state *cli;
3202 const struct ndr_interface_table *table;
3203 struct rpc_pipe_client *result;
3206 static void rpc_pipe_open_np_done(struct tevent_req *subreq);
3208 struct tevent_req *rpc_pipe_open_np_send(
3209 TALLOC_CTX *mem_ctx,
3210 struct tevent_context *ev,
3211 struct cli_state *cli,
3212 const struct ndr_interface_table *table)
3214 struct tevent_req *req = NULL, *subreq = NULL;
3215 struct rpc_pipe_open_np_state *state = NULL;
3216 struct rpc_pipe_client *result = NULL;
3218 req = tevent_req_create(
3219 mem_ctx, &state, struct rpc_pipe_open_np_state);
3220 if (req == NULL) {
3221 return NULL;
3223 state->cli = cli;
3224 state->table = table;
3226 state->result = talloc_zero(state, struct rpc_pipe_client);
3227 if (tevent_req_nomem(state->result, req)) {
3228 return tevent_req_post(req, ev);
3230 result = state->result;
3232 result->abstract_syntax = table->syntax_id;
3233 result->transfer_syntax = ndr_transfer_syntax_ndr;
3235 result->desthost = talloc_strdup(
3236 result, smbXcli_conn_remote_name(cli->conn));
3237 if (tevent_req_nomem(result->desthost, req)) {
3238 return tevent_req_post(req, ev);
3241 result->srv_name_slash = talloc_asprintf_strupper_m(
3242 result, "\\\\%s", result->desthost);
3243 if (tevent_req_nomem(result->srv_name_slash, req)) {
3244 return tevent_req_post(req, ev);
3247 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
3249 subreq = rpc_transport_np_init_send(state, ev, cli, table);
3250 if (tevent_req_nomem(subreq, req)) {
3251 return tevent_req_post(req, ev);
3253 tevent_req_set_callback(subreq, rpc_pipe_open_np_done, req);
3254 return req;
3257 static void rpc_pipe_open_np_done(struct tevent_req *subreq)
3259 struct tevent_req *req = tevent_req_callback_data(
3260 subreq, struct tevent_req);
3261 struct rpc_pipe_open_np_state *state = tevent_req_data(
3262 req, struct rpc_pipe_open_np_state);
3263 struct rpc_pipe_client *result = state->result;
3264 struct rpc_pipe_client_np_ref *np_ref = NULL;
3265 NTSTATUS status;
3267 status = rpc_transport_np_init_recv(
3268 subreq, result, &result->transport);
3269 TALLOC_FREE(subreq);
3270 if (tevent_req_nterror(req, status)) {
3271 return;
3274 result->transport->transport = NCACN_NP;
3276 np_ref = talloc(result->transport, struct rpc_pipe_client_np_ref);
3277 if (tevent_req_nomem(np_ref, req)) {
3278 return;
3280 np_ref->cli = state->cli;
3281 np_ref->pipe = result;
3283 DLIST_ADD(np_ref->cli->pipe_list, np_ref->pipe);
3284 talloc_set_destructor(np_ref, rpc_pipe_client_np_ref_destructor);
3286 result->binding_handle = rpccli_bh_create(result, NULL, state->table);
3287 if (tevent_req_nomem(result->binding_handle, req)) {
3288 return;
3291 tevent_req_done(req);
3294 NTSTATUS rpc_pipe_open_np_recv(
3295 struct tevent_req *req,
3296 TALLOC_CTX *mem_ctx,
3297 struct rpc_pipe_client **_result)
3299 struct rpc_pipe_open_np_state *state = tevent_req_data(
3300 req, struct rpc_pipe_open_np_state);
3301 NTSTATUS status;
3303 if (tevent_req_is_nterror(req, &status)) {
3304 return status;
3306 *_result = talloc_move(mem_ctx, &state->result);
3307 return NT_STATUS_OK;
3310 NTSTATUS rpc_pipe_open_np(struct cli_state *cli,
3311 const struct ndr_interface_table *table,
3312 struct rpc_pipe_client **presult)
3314 struct tevent_context *ev = NULL;
3315 struct tevent_req *req = NULL;
3316 NTSTATUS status = NT_STATUS_NO_MEMORY;
3318 ev = samba_tevent_context_init(cli);
3319 if (ev == NULL) {
3320 goto fail;
3322 req = rpc_pipe_open_np_send(ev, ev, cli, table);
3323 if (req == NULL) {
3324 goto fail;
3326 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
3327 goto fail;
3329 status = rpc_pipe_open_np_recv(req, NULL, presult);
3330 fail:
3331 TALLOC_FREE(req);
3332 TALLOC_FREE(ev);
3333 return status;
3336 /****************************************************************************
3337 Open a pipe to a remote server.
3338 ****************************************************************************/
3340 static NTSTATUS cli_rpc_pipe_open(struct cli_state *cli,
3341 enum dcerpc_transport_t transport,
3342 const struct ndr_interface_table *table,
3343 const char *remote_name,
3344 const struct sockaddr_storage *remote_sockaddr,
3345 struct rpc_pipe_client **presult)
3347 switch (transport) {
3348 case NCACN_IP_TCP:
3349 return rpc_pipe_open_tcp(NULL,
3350 remote_name,
3351 remote_sockaddr,
3352 table, presult);
3353 case NCACN_NP:
3354 return rpc_pipe_open_np(cli, table, presult);
3355 default:
3356 return NT_STATUS_NOT_IMPLEMENTED;
3360 /****************************************************************************
3361 Open a named pipe to an SMB server and bind anonymously.
3362 ****************************************************************************/
3364 NTSTATUS cli_rpc_pipe_open_noauth_transport(struct cli_state *cli,
3365 enum dcerpc_transport_t transport,
3366 const struct ndr_interface_table *table,
3367 const char *remote_name,
3368 const struct sockaddr_storage *remote_sockaddr,
3369 struct rpc_pipe_client **presult)
3371 struct rpc_pipe_client *result;
3372 struct pipe_auth_data *auth;
3373 NTSTATUS status;
3375 status = cli_rpc_pipe_open(cli,
3376 transport,
3377 table,
3378 remote_name,
3379 remote_sockaddr,
3380 &result);
3381 if (!NT_STATUS_IS_OK(status)) {
3382 return status;
3385 status = rpccli_anon_bind_data(result, &auth);
3386 if (!NT_STATUS_IS_OK(status)) {
3387 DEBUG(0, ("rpccli_anon_bind_data returned %s\n",
3388 nt_errstr(status)));
3389 TALLOC_FREE(result);
3390 return status;
3394 * This is a bit of an abstraction violation due to the fact that an
3395 * anonymous bind on an authenticated SMB inherits the user/domain
3396 * from the enclosing SMB creds
3399 if (transport == NCACN_NP) {
3400 struct smbXcli_session *session;
3402 if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
3403 session = cli->smb2.session;
3404 } else {
3405 session = cli->smb1.session;
3408 status = smbXcli_session_application_key(session, auth,
3409 &auth->transport_session_key);
3410 if (!NT_STATUS_IS_OK(status)) {
3411 auth->transport_session_key = data_blob_null;
3415 status = rpc_pipe_bind(result, auth);
3416 if (!NT_STATUS_IS_OK(status)) {
3417 int lvl = 0;
3418 if (ndr_syntax_id_equal(&table->syntax_id,
3419 &ndr_table_dssetup.syntax_id)) {
3420 /* non AD domains just don't have this pipe, avoid
3421 * level 0 statement in that case - gd */
3422 lvl = 3;
3424 DEBUG(lvl, ("cli_rpc_pipe_open_noauth: rpc_pipe_bind for pipe "
3425 "%s failed with error %s\n",
3426 table->name,
3427 nt_errstr(status) ));
3428 TALLOC_FREE(result);
3429 return status;
3432 DEBUG(10,("cli_rpc_pipe_open_noauth: opened pipe %s to machine "
3433 "%s and bound anonymously.\n",
3434 table->name,
3435 result->desthost));
3437 *presult = result;
3438 return NT_STATUS_OK;
3441 /****************************************************************************
3442 ****************************************************************************/
3444 NTSTATUS cli_rpc_pipe_open_noauth(struct cli_state *cli,
3445 const struct ndr_interface_table *table,
3446 struct rpc_pipe_client **presult)
3448 const char *remote_name = smbXcli_conn_remote_name(cli->conn);
3449 const struct sockaddr_storage *remote_sockaddr =
3450 smbXcli_conn_remote_sockaddr(cli->conn);
3452 return cli_rpc_pipe_open_noauth_transport(cli, NCACN_NP,
3453 table,
3454 remote_name,
3455 remote_sockaddr,
3456 presult);
3459 /****************************************************************************
3460 Open a named pipe to an SMB server and bind using the mech specified
3462 This routine references the creds pointer that is passed in
3463 ****************************************************************************/
3465 NTSTATUS cli_rpc_pipe_open_with_creds(struct cli_state *cli,
3466 const struct ndr_interface_table *table,
3467 enum dcerpc_transport_t transport,
3468 enum dcerpc_AuthType auth_type,
3469 enum dcerpc_AuthLevel auth_level,
3470 const char *server,
3471 const struct sockaddr_storage *remote_sockaddr,
3472 struct cli_credentials *creds,
3473 struct rpc_pipe_client **presult)
3475 struct rpc_pipe_client *result;
3476 struct pipe_auth_data *auth = NULL;
3477 const char *target_service = table->authservices->names[0];
3478 NTSTATUS status;
3480 status = cli_rpc_pipe_open(cli,
3481 transport,
3482 table,
3483 server,
3484 remote_sockaddr,
3485 &result);
3486 if (!NT_STATUS_IS_OK(status)) {
3487 return status;
3490 status = rpccli_generic_bind_data_from_creds(result,
3491 auth_type, auth_level,
3492 server, target_service,
3493 creds,
3494 &auth);
3495 if (!NT_STATUS_IS_OK(status)) {
3496 DBG_ERR("rpccli_generic_bind_data_from_creds returned %s\n",
3497 nt_errstr(status));
3498 goto err;
3501 status = rpc_pipe_bind(result, auth);
3502 if (!NT_STATUS_IS_OK(status)) {
3503 DBG_ERR("cli_rpc_pipe_bind failed with error %s\n",
3504 nt_errstr(status));
3505 goto err;
3508 DBG_DEBUG("opened pipe %s to machine %s and bound as user %s.\n",
3509 table->name,
3510 result->desthost,
3511 cli_credentials_get_unparsed_name(creds, talloc_tos()));
3513 *presult = result;
3514 return NT_STATUS_OK;
3516 err:
3518 TALLOC_FREE(result);
3519 return status;
3522 NTSTATUS cli_rpc_pipe_open_bind_schannel(
3523 struct cli_state *cli,
3524 const struct ndr_interface_table *table,
3525 enum dcerpc_transport_t transport,
3526 struct netlogon_creds_cli_context *netlogon_creds,
3527 const char *remote_name,
3528 const struct sockaddr_storage *remote_sockaddr,
3529 struct rpc_pipe_client **_rpccli)
3531 struct rpc_pipe_client *rpccli;
3532 struct pipe_auth_data *rpcauth;
3533 const char *target_service = table->authservices->names[0];
3534 struct cli_credentials *cli_creds;
3535 enum dcerpc_AuthLevel auth_level;
3536 NTSTATUS status;
3538 status = cli_rpc_pipe_open(cli,
3539 transport,
3540 table,
3541 remote_name,
3542 remote_sockaddr,
3543 &rpccli);
3544 if (!NT_STATUS_IS_OK(status)) {
3545 return status;
3548 auth_level = netlogon_creds_cli_auth_level(netlogon_creds);
3550 status = netlogon_creds_bind_cli_credentials(
3551 netlogon_creds, rpccli, &cli_creds);
3552 if (!NT_STATUS_IS_OK(status)) {
3553 DBG_DEBUG("netlogon_creds_bind_cli_credentials failed: %s\n",
3554 nt_errstr(status));
3555 TALLOC_FREE(rpccli);
3556 return status;
3559 status = rpccli_generic_bind_data_from_creds(rpccli,
3560 DCERPC_AUTH_TYPE_SCHANNEL,
3561 auth_level,
3562 rpccli->desthost,
3563 target_service,
3564 cli_creds,
3565 &rpcauth);
3566 if (!NT_STATUS_IS_OK(status)) {
3567 DEBUG(0, ("rpccli_generic_bind_data_from_creds returned %s\n",
3568 nt_errstr(status)));
3569 TALLOC_FREE(rpccli);
3570 return status;
3573 status = rpc_pipe_bind(rpccli, rpcauth);
3575 /* No TALLOC_FREE, gensec takes references */
3576 talloc_unlink(rpccli, cli_creds);
3577 cli_creds = NULL;
3579 if (!NT_STATUS_IS_OK(status)) {
3580 DBG_DEBUG("rpc_pipe_bind failed with error %s\n",
3581 nt_errstr(status));
3582 TALLOC_FREE(rpccli);
3583 return status;
3586 *_rpccli = rpccli;
3588 return NT_STATUS_OK;
3591 NTSTATUS cli_rpc_pipe_open_schannel_with_creds(struct cli_state *cli,
3592 const struct ndr_interface_table *table,
3593 enum dcerpc_transport_t transport,
3594 struct netlogon_creds_cli_context *netlogon_creds,
3595 const char *remote_name,
3596 const struct sockaddr_storage *remote_sockaddr,
3597 struct rpc_pipe_client **_rpccli)
3599 TALLOC_CTX *frame = talloc_stackframe();
3600 struct rpc_pipe_client *rpccli;
3601 struct netlogon_creds_cli_lck *lck;
3602 NTSTATUS status;
3604 status = netlogon_creds_cli_lck(
3605 netlogon_creds, NETLOGON_CREDS_CLI_LCK_EXCLUSIVE,
3606 frame, &lck);
3607 if (!NT_STATUS_IS_OK(status)) {
3608 DBG_WARNING("netlogon_creds_cli_lck returned %s\n",
3609 nt_errstr(status));
3610 TALLOC_FREE(frame);
3611 return status;
3614 status = cli_rpc_pipe_open_bind_schannel(cli,
3615 table,
3616 transport,
3617 netlogon_creds,
3618 remote_name,
3619 remote_sockaddr,
3620 &rpccli);
3621 if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
3622 netlogon_creds_cli_delete_lck(netlogon_creds);
3624 if (!NT_STATUS_IS_OK(status)) {
3625 DBG_DEBUG("cli_rpc_pipe_open_bind_schannel failed: %s\n",
3626 nt_errstr(status));
3627 TALLOC_FREE(frame);
3628 return status;
3631 if (ndr_syntax_id_equal(&table->syntax_id,
3632 &ndr_table_netlogon.syntax_id)) {
3633 status = netlogon_creds_cli_check(netlogon_creds,
3634 rpccli->binding_handle,
3635 NULL);
3636 if (!NT_STATUS_IS_OK(status)) {
3637 DEBUG(0, ("netlogon_creds_cli_check failed with %s\n",
3638 nt_errstr(status)));
3639 TALLOC_FREE(frame);
3640 return status;
3644 DBG_DEBUG("opened pipe %s to machine %s with key %s "
3645 "and bound using schannel.\n",
3646 table->name, rpccli->desthost,
3647 netlogon_creds_cli_debug_string(netlogon_creds, lck));
3649 TALLOC_FREE(frame);
3651 *_rpccli = rpccli;
3652 return NT_STATUS_OK;
3655 NTSTATUS cli_get_session_key(TALLOC_CTX *mem_ctx,
3656 struct rpc_pipe_client *cli,
3657 DATA_BLOB *session_key)
3659 NTSTATUS status;
3660 struct pipe_auth_data *a;
3661 struct gensec_security *gensec_security;
3662 DATA_BLOB sk = { .data = NULL };
3663 bool make_dup = false;
3665 if (!session_key || !cli) {
3666 return NT_STATUS_INVALID_PARAMETER;
3669 a = cli->auth;
3671 if (a == NULL) {
3672 return NT_STATUS_INVALID_PARAMETER;
3675 switch (cli->auth->auth_type) {
3676 case DCERPC_AUTH_TYPE_NONE:
3677 sk = data_blob_const(a->transport_session_key.data,
3678 a->transport_session_key.length);
3679 make_dup = true;
3680 break;
3681 default:
3682 gensec_security = a->auth_ctx;
3683 status = gensec_session_key(gensec_security, mem_ctx, &sk);
3684 if (!NT_STATUS_IS_OK(status)) {
3685 return status;
3687 make_dup = false;
3688 break;
3691 if (!sk.data) {
3692 return NT_STATUS_NO_USER_SESSION_KEY;
3695 if (make_dup) {
3696 *session_key = data_blob_dup_talloc(mem_ctx, sk);
3697 } else {
3698 *session_key = sk;
3701 return NT_STATUS_OK;