2 * Unix SMB/CIFS implementation.
3 * RPC Pipe client / server routines
4 * Copyright (C) Andrew Tridgell 1992-1998,
5 * Largely re-written : 2005
6 * Copyright (C) Jeremy Allison 1998 - 2005
7 * Copyright (C) Simo Sorce 2010
8 * Copyright (C) Andrew Bartlett 2011
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 3 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see <http://www.gnu.org/licenses/>.
25 #include "rpc_client/cli_pipe.h"
27 #include "../libcli/named_pipe_auth/npa_tstream.h"
28 #include "rpc_server/rpc_ncacn_np.h"
29 #include "librpc/gen_ndr/netlogon.h"
30 #include "librpc/gen_ndr/auth.h"
31 #include "../auth/auth_sam_reply.h"
32 #include "../auth/auth_util.h"
34 #include "rpc_server/rpc_pipes.h"
35 #include "../lib/tsocket/tsocket.h"
36 #include "../lib/util/tevent_ntstatus.h"
37 #include "rpc_server/rpc_config.h"
38 #include "librpc/ndr/ndr_table.h"
39 #include "rpc_server/rpc_server.h"
40 #include "librpc/rpc/dcerpc_util.h"
43 #define DBGC_CLASS DBGC_RPC_SRV
45 struct np_proxy_state {
47 uint16_t device_state;
48 uint64_t allocation_size;
49 struct tstream_context *npipe;
50 struct tevent_queue *read_queue;
51 struct tevent_queue *write_queue;
54 static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
55 const char *pipe_name,
56 const struct tsocket_address *remote_address,
57 const struct tsocket_address *local_address,
58 const struct auth_session_info *session_info);
60 static struct npa_state *npa_state_init(TALLOC_CTX *mem_ctx)
62 struct npa_state *npa;
64 npa = talloc_zero(mem_ctx, struct npa_state);
69 npa->read_queue = tevent_queue_create(npa, "npa_cli_read");
70 if (npa->read_queue == NULL) {
71 DEBUG(0, ("tevent_queue_create failed\n"));
75 npa->write_queue = tevent_queue_create(npa, "npa_cli_write");
76 if (npa->write_queue == NULL) {
77 DEBUG(0, ("tevent_queue_create failed\n"));
87 NTSTATUS make_internal_rpc_pipe_socketpair(
89 struct tevent_context *ev_ctx,
90 struct messaging_context *msg_ctx,
91 struct dcesrv_context *dce_ctx,
92 struct dcesrv_endpoint *endpoint,
93 const struct tsocket_address *remote_address,
94 const struct tsocket_address *local_address,
95 const struct auth_session_info *session_info,
96 struct npa_state **pnpa)
98 TALLOC_CTX *tmp_ctx = talloc_stackframe();
99 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
100 struct dcesrv_connection *dcesrv_conn = NULL;
101 struct npa_state *npa;
104 enum dcerpc_transport_t transport = dcerpc_binding_get_transport(
105 endpoint->ep_description);
106 const char *pipe_name = dcerpc_binding_get_string_option(
107 endpoint->ep_description, "endpoint");
109 DEBUG(4, ("Create of internal pipe %s requested\n", pipe_name));
111 npa = npa_state_init(tmp_ctx);
113 status = NT_STATUS_NO_MEMORY;
117 npa->file_type = FILE_TYPE_MESSAGE_MODE_PIPE;
118 npa->device_state = 0xff | 0x0400 | 0x0100;
119 npa->allocation_size = 4096;
121 status = dcerpc_ncacn_conn_init(npa,
126 NULL, /* termination fn */
127 NULL, /* termination data */
129 if (!NT_STATUS_IS_OK(status)) {
133 npa->private_data = (void*)ncacn_conn;
135 rc = tstream_npa_socketpair(npa->file_type,
139 &ncacn_conn->tstream);
141 status = map_nt_error_from_unix(errno);
145 ncacn_conn->remote_client_addr = tsocket_address_copy(remote_address,
147 if (ncacn_conn->remote_client_addr == NULL) {
148 status = NT_STATUS_NO_MEMORY;
152 ncacn_conn->remote_client_name = tsocket_address_inet_addr_string(
153 ncacn_conn->remote_client_addr, ncacn_conn);
154 if (ncacn_conn->remote_client_name == NULL) {
155 status = NT_STATUS_NO_MEMORY;
159 ncacn_conn->local_server_addr = tsocket_address_copy(local_address,
161 if (ncacn_conn->local_server_addr == NULL) {
162 status = NT_STATUS_NO_MEMORY;
166 ncacn_conn->local_server_name = tsocket_address_inet_addr_string(
167 ncacn_conn->local_server_addr, ncacn_conn);
168 if (ncacn_conn->local_server_name == NULL) {
169 status = NT_STATUS_NO_MEMORY;
173 ncacn_conn->session_info = copy_session_info(ncacn_conn, session_info);
174 if (ncacn_conn->session_info == NULL) {
175 status = NT_STATUS_NO_MEMORY;
179 rc = make_base_pipes_struct(ncacn_conn,
183 ncacn_conn->remote_client_addr,
184 ncacn_conn->local_server_addr,
187 status = map_nt_error_from_unix(rc);
192 * This fills in dcesrv_conn->endpoint with the endpoint
193 * associated with the socket. From this point on we know
194 * which (group of) services we are handling, but not the
195 * specific interface.
197 status = dcesrv_endpoint_connect(ncacn_conn->dce_ctx,
199 ncacn_conn->endpoint,
200 ncacn_conn->session_info,
202 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
204 if (!NT_STATUS_IS_OK(status)) {
205 DBG_ERR("Failed to connect to endpoint: %s\n",
210 dcesrv_conn->transport.private_data = ncacn_conn;
211 dcesrv_conn->transport.report_output_data =
212 dcesrv_sock_report_output_data;
213 dcesrv_conn->transport.terminate_connection =
214 dcesrv_transport_terminate_connection;
215 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn,
216 "dcesrv send queue");
217 if (dcesrv_conn->send_queue == NULL) {
218 status = NT_STATUS_NO_MEMORY;
219 DBG_ERR("Failed to create send queue: %s\n",
224 dcesrv_conn->stream = talloc_move(dcesrv_conn, &ncacn_conn->tstream);
225 dcesrv_conn->local_address = ncacn_conn->local_server_addr;
226 dcesrv_conn->remote_address = ncacn_conn->remote_client_addr;
228 status = dcesrv_connection_loop_start(dcesrv_conn);
229 if (!NT_STATUS_IS_OK(status)) {
230 DBG_ERR("Failed to start dcesrv_connection loop: %s\n",
235 *pnpa = talloc_move(mem_ctx, &npa);
236 status = NT_STATUS_OK;
238 talloc_free(tmp_ctx);
242 static NTSTATUS make_internal_ncacn_conn(TALLOC_CTX *mem_ctx,
243 const struct ndr_interface_table *table,
244 const struct tsocket_address *remote_address,
245 const struct tsocket_address *local_address,
246 const struct auth_session_info *session_info,
247 struct messaging_context *msg_ctx,
248 struct dcerpc_ncacn_conn **_out)
250 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
251 const char *pipe_name = NULL;
255 pipe_name = dcerpc_default_transport_endpoint(mem_ctx,
259 DBG_INFO("Create pipe requested %s\n", pipe_name);
261 ncacn_conn = talloc_zero(mem_ctx, struct dcerpc_ncacn_conn);
262 if (ncacn_conn == NULL) {
263 return NT_STATUS_NO_MEMORY;
266 ncacn_conn->msg_ctx = msg_ctx;
268 if (remote_address != NULL) {
269 ncacn_conn->remote_client_addr =
270 tsocket_address_copy(remote_address, ncacn_conn);
271 if (ncacn_conn->remote_client_addr == NULL) {
272 status = NT_STATUS_NO_MEMORY;
277 if (local_address != NULL) {
278 ncacn_conn->local_server_addr =
279 tsocket_address_copy(local_address, ncacn_conn);
280 if (ncacn_conn->local_server_addr == NULL) {
281 status = NT_STATUS_NO_MEMORY;
286 ncacn_conn->session_info = copy_session_info(ncacn_conn, session_info);
287 if (ncacn_conn->session_info == NULL) {
288 status = NT_STATUS_NO_MEMORY;
292 ret = make_base_pipes_struct(ncacn_conn,
296 ncacn_conn->remote_client_addr,
297 ncacn_conn->local_server_addr,
300 DBG_ERR("No memory for pipes_struct!\n");
301 status = NT_STATUS_NO_MEMORY;
305 DEBUG(4,("Created internal pipe %s\n", pipe_name));
312 talloc_free(ncacn_conn);
316 static NTSTATUS find_ncalrpc_default_endpoint(struct dcesrv_context *dce_ctx,
317 const struct ndr_interface_table *ndr_table,
318 struct dcesrv_endpoint **ep)
320 TALLOC_CTX *tmp_ctx = NULL;
321 struct dcerpc_binding *binding = NULL;
322 const char *ep_description = NULL;
325 tmp_ctx = talloc_new(dce_ctx);
326 if (tmp_ctx == NULL) {
327 return NT_STATUS_NO_MEMORY;
330 if (rpc_service_mode(ndr_table->name) == RPC_SERVICE_MODE_EXTERNAL) {
331 ep_description = talloc_asprintf(tmp_ctx, "ncalrpc:[%s]",
332 talloc_strdup_upper(tmp_ctx, ndr_table->name));
333 if (ep_description == NULL) {
334 status = NT_STATUS_NO_MEMORY;
338 status = dcerpc_parse_binding(tmp_ctx, ep_description, &binding);
339 if (!NT_STATUS_IS_OK(status)) {
343 status = dcesrv_find_endpoint(dce_ctx, binding, ep);
344 if (NT_STATUS_IS_OK(status)) {
350 * Some services use a rpcint binding handle in their initialization,
351 * before the server is fully initialized. Search the NCALRPC endpoint
352 * with and without endpoint
354 status = dcerpc_parse_binding(tmp_ctx, "ncalrpc:", &binding);
355 if (!NT_STATUS_IS_OK(status)) {
359 status = dcesrv_find_endpoint(dce_ctx, binding, ep);
360 if (NT_STATUS_IS_OK(status)) {
364 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
365 ep_description = "ncalrpc:[SMBD]";
367 ep_description = "ncalrpc:[DEFAULT]";
370 status = dcerpc_parse_binding(tmp_ctx, ep_description, &binding);
371 if (!NT_STATUS_IS_OK(status)) {
375 status = dcesrv_find_endpoint(dce_ctx, binding, ep);
376 if (!NT_STATUS_IS_OK(status)) {
381 talloc_free(tmp_ctx);
385 static NTSTATUS make_internal_dcesrv_connection(TALLOC_CTX *mem_ctx,
386 const struct ndr_interface_table *ndr_table,
387 struct dcerpc_ncacn_conn *ncacn_conn,
388 struct dcesrv_connection **_out)
390 struct dcesrv_connection *conn = NULL;
391 struct dcesrv_connection_context *context = NULL;
392 struct dcesrv_endpoint *endpoint = NULL;
395 conn = talloc_zero(mem_ctx, struct dcesrv_connection);
397 return NT_STATUS_NO_MEMORY;
399 conn->dce_ctx = global_dcesrv_context();
400 conn->preferred_transfer = &ndr_transfer_syntax_ndr;
401 conn->transport.private_data = ncacn_conn;
403 status = find_ncalrpc_default_endpoint(conn->dce_ctx, ndr_table, &endpoint);
404 if (!NT_STATUS_IS_OK(status)) {
407 conn->endpoint = endpoint;
409 conn->default_auth_state = talloc_zero(conn, struct dcesrv_auth);
410 if (conn->default_auth_state == NULL) {
411 status = NT_STATUS_NO_MEMORY;
414 conn->default_auth_state->session_info = ncacn_conn->session_info;
415 conn->default_auth_state->auth_finished = true;
417 context = talloc_zero(conn, struct dcesrv_connection_context);
418 if (context == NULL) {
419 status = NT_STATUS_NO_MEMORY;
422 context->conn = conn;
423 context->context_id = 0;
424 context->transfer_syntax = *(conn->preferred_transfer);
425 context->iface = find_interface_by_syntax_id(
426 conn->endpoint, &ndr_table->syntax_id);
427 if (context->iface == NULL) {
428 status = NT_STATUS_RPC_INTERFACE_NOT_FOUND;
432 DLIST_ADD(conn->contexts, context);
442 struct rpcint_bh_state {
443 struct dcesrv_connection *conn;
446 static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h)
448 struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
449 struct rpcint_bh_state);
451 if (hs->conn == NULL) {
458 static uint32_t rpcint_bh_set_timeout(struct dcerpc_binding_handle *h,
461 /* TODO: implement timeouts */
465 struct rpcint_bh_raw_call_state {
466 struct dcesrv_call_state *call;
469 static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
470 struct tevent_context *ev,
471 struct dcerpc_binding_handle *h,
472 const struct GUID *object,
475 const uint8_t *in_data,
478 struct rpcint_bh_state *hs =
479 dcerpc_binding_handle_data(h,
480 struct rpcint_bh_state);
481 struct tevent_req *req;
482 struct rpcint_bh_raw_call_state *state;
483 struct dcesrv_context *dce_ctx = global_dcesrv_context();
487 req = tevent_req_create(mem_ctx, &state,
488 struct rpcint_bh_raw_call_state);
493 ok = rpcint_bh_is_connected(h);
495 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
496 return tevent_req_post(req, ev);
499 state->call = talloc_zero(state, struct dcesrv_call_state);
500 if (tevent_req_nomem(state->call, req)) {
501 return tevent_req_post(req, ev);
504 state->call->event_ctx = ev;
505 state->call->conn = hs->conn;
506 state->call->context = hs->conn->contexts;
507 state->call->auth_state = hs->conn->default_auth_state;
509 if (hs->conn->assoc_group == NULL) {
510 ZERO_STRUCT(state->call->pkt);
511 state->call->pkt.u.bind.assoc_group_id = 0;
512 status = dce_ctx->callbacks->assoc_group.find(
514 dce_ctx->callbacks->assoc_group.private_data);
515 if (tevent_req_nterror(req, status)) {
516 return tevent_req_post(req, ev);
520 ZERO_STRUCT(state->call->pkt);
521 state->call->pkt.u.request.opnum = opnum;
522 state->call->pkt.u.request.context_id = 0;
523 state->call->pkt.u.request.stub_and_verifier.data = discard_const_p(uint8_t, in_data);
524 state->call->pkt.u.request.stub_and_verifier.length = in_length;
526 /* TODO: allow async */
527 status = dcesrv_call_dispatch_local(state->call);
528 if (!NT_STATUS_IS_OK(status)) {
529 tevent_req_nterror(req, status);
530 return tevent_req_post(req, ev);
533 tevent_req_done(req);
534 return tevent_req_post(req, ev);
537 static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req,
543 struct rpcint_bh_raw_call_state *state =
545 struct rpcint_bh_raw_call_state);
546 struct data_blob_list_item *rep = NULL;
549 if (tevent_req_is_nterror(req, &status)) {
550 tevent_req_received(req);
554 rep = state->call->replies;
555 DLIST_REMOVE(state->call->replies, rep);
557 *out_data = talloc_steal(mem_ctx, rep->blob.data);
558 *out_length = rep->blob.length;
563 tevent_req_received(req);
567 struct rpcint_bh_disconnect_state {
571 static struct tevent_req *rpcint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
572 struct tevent_context *ev,
573 struct dcerpc_binding_handle *h)
575 struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
576 struct rpcint_bh_state);
577 struct tevent_req *req;
578 struct rpcint_bh_disconnect_state *state;
581 req = tevent_req_create(mem_ctx, &state,
582 struct rpcint_bh_disconnect_state);
587 ok = rpcint_bh_is_connected(h);
589 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
590 return tevent_req_post(req, ev);
594 * TODO: do a real async disconnect ...
596 * For now the caller needs to free dcesrv_connection
600 tevent_req_done(req);
601 return tevent_req_post(req, ev);
604 static NTSTATUS rpcint_bh_disconnect_recv(struct tevent_req *req)
608 if (tevent_req_is_nterror(req, &status)) {
609 tevent_req_received(req);
613 tevent_req_received(req);
617 static bool rpcint_bh_ref_alloc(struct dcerpc_binding_handle *h)
622 static void rpcint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
624 const void *_struct_ptr,
625 const struct ndr_interface_call *call)
627 void *struct_ptr = discard_const(_struct_ptr);
629 if (DEBUGLEVEL < 11) {
633 if (ndr_flags & NDR_IN) {
634 ndr_print_function_debug(call->ndr_print,
639 if (ndr_flags & NDR_OUT) {
640 ndr_print_function_debug(call->ndr_print,
647 static const struct dcerpc_binding_handle_ops rpcint_bh_ops = {
649 .is_connected = rpcint_bh_is_connected,
650 .set_timeout = rpcint_bh_set_timeout,
651 .raw_call_send = rpcint_bh_raw_call_send,
652 .raw_call_recv = rpcint_bh_raw_call_recv,
653 .disconnect_send = rpcint_bh_disconnect_send,
654 .disconnect_recv = rpcint_bh_disconnect_recv,
656 .ref_alloc = rpcint_bh_ref_alloc,
657 .do_ndr_print = rpcint_bh_do_ndr_print,
660 static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
661 const struct ndr_syntax_id *abstract_syntax,
662 const struct ndr_interface_table *ndr_table,
663 const struct tsocket_address *remote_address,
664 const struct tsocket_address *local_address,
665 const struct auth_session_info *session_info,
666 struct messaging_context *msg_ctx,
667 struct dcerpc_binding_handle **binding_handle)
669 struct dcerpc_binding_handle *h;
670 struct rpcint_bh_state *hs;
671 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
674 h = dcerpc_binding_handle_create(mem_ctx,
679 struct rpcint_bh_state,
682 return NT_STATUS_NO_MEMORY;
685 status = make_internal_ncacn_conn(hs,
692 if (!NT_STATUS_IS_OK(status)) {
697 status = make_internal_dcesrv_connection(ncacn_conn,
701 if (!NT_STATUS_IS_OK(status)) {
710 * @brief Create a new DCERPC Binding Handle which uses a local dispatch function.
712 * @param[in] mem_ctx The memory context to use.
714 * @param[in] ndr_table Normally the ndr_table_<name>.
716 * @param[in] remote_address The info about the connected client.
718 * @param[in] serversupplied_info The server supplied authentication function.
720 * @param[in] msg_ctx The messaging context that can be used by the server
722 * @param[out] binding_handle A pointer to store the connected
723 * dcerpc_binding_handle
725 * @return NT_STATUS_OK on success, a corresponding NT status if an
729 * struct dcerpc_binding_handle *winreg_binding;
732 * status = rpcint_binding_handle(tmp_ctx,
740 NTSTATUS rpcint_binding_handle(TALLOC_CTX *mem_ctx,
741 const struct ndr_interface_table *ndr_table,
742 const struct tsocket_address *remote_address,
743 const struct tsocket_address *local_address,
744 const struct auth_session_info *session_info,
745 struct messaging_context *msg_ctx,
746 struct dcerpc_binding_handle **binding_handle)
748 return rpcint_binding_handle_ex(mem_ctx, NULL, ndr_table, remote_address,
749 local_address, session_info,
750 msg_ctx, binding_handle);
756 * @brief Create a new RPC client context which uses a local transport.
758 * This creates a local transport. It is a shortcut to directly call the server
759 * functions and avoid marshalling.
760 * NOTE: this function should be used only by rpc_pipe_open_interface()
762 * @param[in] mem_ctx The memory context to use.
764 * @param[in] ndr_table the ndr_table_<name> structure.
766 * @param[in] serversupplied_info The server supplied authentication function.
768 * @param[in] remote_address The client address information.
770 * @param[in] msg_ctx The messaging context to use.
772 * @param[out] presult A pointer to store the connected rpc client pipe.
774 * @return NT_STATUS_OK on success, a corresponding NT status if an
777 NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
778 const struct ndr_interface_table *ndr_table,
779 const struct auth_session_info *session_info,
780 const struct tsocket_address *remote_address,
781 const struct tsocket_address *local_address,
782 struct messaging_context *msg_ctx,
783 struct rpc_pipe_client **presult)
785 struct rpc_pipe_client *result;
788 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
789 if (result == NULL) {
790 return NT_STATUS_NO_MEMORY;
793 result->abstract_syntax = ndr_table->syntax_id;
794 result->transfer_syntax = ndr_transfer_syntax_ndr;
796 if (remote_address == NULL) {
797 struct tsocket_address *local;
800 rc = tsocket_address_inet_from_strings(mem_ctx,
807 return NT_STATUS_NO_MEMORY;
810 remote_address = local;
813 result->max_xmit_frag = -1;
815 status = rpcint_binding_handle(result,
821 &result->binding_handle);
822 if (!NT_STATUS_IS_OK(status)) {
831 /****************************************************************************
832 * External pipes functions
833 ***************************************************************************/
835 NTSTATUS make_external_rpc_pipe(TALLOC_CTX *mem_ctx,
836 const char *pipe_name,
837 const struct tsocket_address *remote_client_address,
838 const struct tsocket_address *local_server_address,
839 const struct auth_session_info *session_info,
840 struct npa_state **pnpa)
842 TALLOC_CTX *tmp_ctx = talloc_stackframe();
843 struct auth_session_info_transport *session_info_t;
844 struct tevent_context *ev_ctx;
845 struct tevent_req *subreq;
846 const char *socket_np_dir;
847 const char *socket_dir;
848 struct npa_state *npa;
854 npa = npa_state_init(tmp_ctx);
856 status = NT_STATUS_NO_MEMORY;
860 socket_dir = lp_parm_const_string(GLOBAL_SECTION_SNUM,
864 if (socket_dir == NULL) {
865 DEBUG(0, ("external_rpc_pipe: socket_dir not set\n"));
866 status = NT_STATUS_PIPE_NOT_AVAILABLE;
870 socket_np_dir = talloc_asprintf(tmp_ctx, "%s/np", socket_dir);
871 if (socket_np_dir == NULL) {
872 DEBUG(0, ("talloc_asprintf failed\n"));
873 status = NT_STATUS_NO_MEMORY;
877 session_info_t = talloc_zero(tmp_ctx,
878 struct auth_session_info_transport);
879 if (session_info_t == NULL) {
880 DEBUG(0, ("talloc failed\n"));
881 status = NT_STATUS_NO_MEMORY;
885 session_info_t->session_info = copy_session_info(session_info_t,
887 if (session_info_t->session_info == NULL) {
888 DEBUG(0, ("copy_session_info failed\n"));
889 status = NT_STATUS_NO_MEMORY;
893 ev_ctx = samba_tevent_context_init(tmp_ctx);
894 if (ev_ctx == NULL) {
895 DEBUG(0, ("samba_tevent_context_init failed\n"));
896 status = NT_STATUS_NO_MEMORY;
901 subreq = tstream_npa_connect_send(tmp_ctx,
905 remote_client_address,
906 NULL, /* client_name */
907 local_server_address,
908 NULL, /* server_name */
910 if (subreq == NULL) {
912 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
913 "user %s\\%s failed\n",
914 socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
915 session_info_t->session_info->info->account_name));
916 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
919 ok = tevent_req_poll(subreq, ev_ctx);
922 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
923 "failed for tstream_npa_connect: %s\n",
926 session_info_t->session_info->info->domain_name,
927 session_info_t->session_info->info->account_name,
929 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
933 rc = tstream_npa_connect_recv(subreq,
939 &npa->allocation_size);
944 if (errno == ENOENT) {
948 DEBUG(l, ("tstream_npa_connect_recv to %s for pipe %s and "
949 "user %s\\%s failed: %s\n",
952 session_info_t->session_info->info->domain_name,
953 session_info_t->session_info->info->account_name,
954 strerror(sys_errno)));
955 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
959 *pnpa = talloc_steal(mem_ctx, npa);
960 status = NT_STATUS_OK;
962 talloc_free(tmp_ctx);
967 static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
968 const char *pipe_name,
969 const struct tsocket_address *remote_address,
970 const struct tsocket_address *local_address,
971 const struct auth_session_info *session_info)
973 struct np_proxy_state *result;
975 const char *socket_dir;
976 struct tevent_context *ev;
977 struct tevent_req *subreq;
978 struct auth_session_info_transport *session_info_t;
983 result = talloc(mem_ctx, struct np_proxy_state);
984 if (result == NULL) {
985 DEBUG(0, ("talloc failed\n"));
989 result->read_queue = tevent_queue_create(result, "np_read");
990 if (result->read_queue == NULL) {
991 DEBUG(0, ("tevent_queue_create failed\n"));
995 result->write_queue = tevent_queue_create(result, "np_write");
996 if (result->write_queue == NULL) {
997 DEBUG(0, ("tevent_queue_create failed\n"));
1001 ev = samba_tevent_context_init(talloc_tos());
1003 DEBUG(0, ("samba_tevent_context_init failed\n"));
1007 socket_dir = lp_parm_const_string(
1008 GLOBAL_SECTION_SNUM, "external_rpc_pipe", "socket_dir",
1010 if (socket_dir == NULL) {
1011 DEBUG(0, ("external_rpc_pipe:socket_dir not set\n"));
1014 socket_np_dir = talloc_asprintf(talloc_tos(), "%s/np", socket_dir);
1015 if (socket_np_dir == NULL) {
1016 DEBUG(0, ("talloc_asprintf failed\n"));
1020 session_info_t = talloc_zero(talloc_tos(), struct auth_session_info_transport);
1021 if (session_info_t == NULL) {
1022 DEBUG(0, ("talloc failed\n"));
1026 session_info_t->session_info = copy_session_info(session_info_t,
1028 if (session_info_t->session_info == NULL) {
1029 DEBUG(0, ("copy_session_info failed\n"));
1034 subreq = tstream_npa_connect_send(talloc_tos(), ev,
1038 NULL, /* client_name */
1040 NULL, /* server_name */
1042 if (subreq == NULL) {
1044 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
1045 "user %s\\%s failed\n",
1046 socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
1047 session_info_t->session_info->info->account_name));
1050 ok = tevent_req_poll(subreq, ev);
1053 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
1054 "failed for tstream_npa_connect: %s\n",
1055 socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
1056 session_info_t->session_info->info->account_name,
1061 ret = tstream_npa_connect_recv(subreq, &sys_errno,
1065 &result->device_state,
1066 &result->allocation_size);
1067 TALLOC_FREE(subreq);
1070 if (sys_errno == ENOENT) {
1073 DEBUG(l, ("tstream_npa_connect_recv to %s for pipe %s and "
1074 "user %s\\%s failed: %s\n",
1075 socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
1076 session_info_t->session_info->info->account_name,
1077 strerror(sys_errno)));
1084 TALLOC_FREE(result);
1088 static NTSTATUS rpc_pipe_open_external(TALLOC_CTX *mem_ctx,
1089 const char *pipe_name,
1090 const struct ndr_interface_table *table,
1091 const struct auth_session_info *session_info,
1092 const struct tsocket_address *remote_client_address,
1093 const struct tsocket_address *local_server_address,
1094 struct rpc_pipe_client **_result)
1096 struct rpc_pipe_client *result = NULL;
1097 struct np_proxy_state *proxy_state = NULL;
1098 struct pipe_auth_data *auth;
1099 struct tsocket_address *remote_client_addr;
1100 struct tsocket_address *local_server_addr;
1104 if (local_server_address == NULL) {
1105 /* this is an internal connection, fake up ip addresses */
1106 ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
1107 NULL, 0, &local_server_addr);
1109 return NT_STATUS_NO_MEMORY;
1111 local_server_address = local_server_addr;
1114 if (remote_client_address == NULL) {
1115 /* this is an internal connection, fake up ip addresses */
1116 ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
1117 NULL, 0, &remote_client_addr);
1119 return NT_STATUS_NO_MEMORY;
1121 remote_client_address = remote_client_addr;
1124 proxy_state = make_external_rpc_pipe_p(mem_ctx, pipe_name,
1125 remote_client_address,
1126 local_server_address,
1129 DEBUG(1, ("Unable to make proxy_state for connection to %s.\n", pipe_name));
1130 return NT_STATUS_UNSUCCESSFUL;
1133 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
1134 if (result == NULL) {
1135 status = NT_STATUS_NO_MEMORY;
1139 result->abstract_syntax = table->syntax_id;
1140 result->transfer_syntax = ndr_transfer_syntax_ndr;
1142 result->desthost = get_myname(result);
1143 result->srv_name_slash = talloc_asprintf_strupper_m(
1144 result, "\\\\%s", result->desthost);
1145 if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
1146 status = NT_STATUS_NO_MEMORY;
1150 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
1152 status = rpc_transport_tstream_init(result,
1153 &proxy_state->npipe,
1154 &result->transport);
1155 if (!NT_STATUS_IS_OK(status)) {
1159 result->binding_handle = rpccli_bh_create(result, NULL, table);
1160 if (result->binding_handle == NULL) {
1161 status = NT_STATUS_NO_MEMORY;
1162 DEBUG(0, ("Failed to create binding handle.\n"));
1166 result->auth = talloc_zero(result, struct pipe_auth_data);
1167 if (!result->auth) {
1168 status = NT_STATUS_NO_MEMORY;
1171 result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
1172 result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
1173 result->auth->auth_context_id = 0;
1175 status = rpccli_anon_bind_data(result, &auth);
1176 if (!NT_STATUS_IS_OK(status)) {
1177 DEBUG(0, ("Failed to initialize anonymous bind.\n"));
1181 status = rpc_pipe_bind(result, auth);
1182 if (!NT_STATUS_IS_OK(status)) {
1183 DEBUG(0, ("Failed to bind external pipe.\n"));
1188 if (!NT_STATUS_IS_OK(status)) {
1189 TALLOC_FREE(result);
1191 TALLOC_FREE(proxy_state);
1197 * @brief Create a new RPC client context which uses a local dispatch function
1198 * or a remote transport, depending on rpc_server configuration for the
1201 * @param[in] mem_ctx The memory context to use.
1203 * @param[in] abstract_syntax Normally the syntax_id of the autogenerated
1206 * @param[in] serversupplied_info The server supplied authentication function.
1208 * @param[in] remote_address The client address information.
1210 * @param[in] msg_ctx The messaging context to use.
1212 * @param[out] presult A pointer to store the connected rpc client pipe.
1214 * @return NT_STATUS_OK on success, a corresponding NT status if an
1218 * struct rpc_pipe_client *winreg_pipe;
1221 * status = rpc_pipe_open_interface(tmp_ctx,
1222 * &ndr_table_winreg.syntax_id,
1229 NTSTATUS rpc_pipe_open_interface(TALLOC_CTX *mem_ctx,
1230 const struct ndr_interface_table *table,
1231 const struct auth_session_info *session_info,
1232 const struct tsocket_address *remote_address,
1233 const struct tsocket_address *local_address,
1234 struct messaging_context *msg_ctx,
1235 struct rpc_pipe_client **cli_pipe)
1237 struct rpc_pipe_client *cli = NULL;
1238 enum rpc_service_mode_e pipe_mode;
1239 const char *pipe_name;
1241 TALLOC_CTX *tmp_ctx;
1243 if (cli_pipe != NULL) {
1244 if (rpccli_is_connected(*cli_pipe)) {
1245 return NT_STATUS_OK;
1247 TALLOC_FREE(*cli_pipe);
1251 tmp_ctx = talloc_stackframe();
1252 if (tmp_ctx == NULL) {
1253 return NT_STATUS_NO_MEMORY;
1256 pipe_name = dcerpc_default_transport_endpoint(mem_ctx, NCACN_NP, table);
1257 if (pipe_name == NULL) {
1258 DEBUG(1, ("Unable to find pipe name to forward %s to.\n", table->name));
1259 status = NT_STATUS_INVALID_PARAMETER;
1263 while (pipe_name[0] == '\\') {
1267 DEBUG(5, ("Connecting to %s pipe.\n", pipe_name));
1269 pipe_mode = rpc_service_mode(pipe_name);
1271 switch (pipe_mode) {
1272 case RPC_SERVICE_MODE_EMBEDDED:
1273 status = rpc_pipe_open_internal(tmp_ctx,
1274 table, session_info,
1275 remote_address, local_address,
1278 if (!NT_STATUS_IS_OK(status)) {
1282 case RPC_SERVICE_MODE_EXTERNAL:
1283 /* It would be nice to just use rpc_pipe_open_ncalrpc() but
1284 * for now we need to use the special proxy setup to connect
1287 status = rpc_pipe_open_external(tmp_ctx,
1290 remote_address, local_address,
1292 if (!NT_STATUS_IS_OK(status)) {
1296 case RPC_SERVICE_MODE_DISABLED:
1297 status = NT_STATUS_NOT_IMPLEMENTED;
1298 DEBUG(0, ("Service pipe %s is disabled in config file: %s",
1299 pipe_name, nt_errstr(status)));
1303 status = NT_STATUS_OK;
1305 if (NT_STATUS_IS_OK(status) && cli_pipe != NULL) {
1306 *cli_pipe = talloc_move(mem_ctx, &cli);
1308 TALLOC_FREE(tmp_ctx);