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"
42 #define DBGC_CLASS DBGC_RPC_SRV
44 struct np_proxy_state {
46 uint16_t device_state;
47 uint64_t allocation_size;
48 struct tstream_context *npipe;
49 struct tevent_queue *read_queue;
50 struct tevent_queue *write_queue;
53 static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
54 const char *pipe_name,
55 const struct tsocket_address *remote_address,
56 const struct tsocket_address *local_address,
57 const struct auth_session_info *session_info);
59 static struct npa_state *npa_state_init(TALLOC_CTX *mem_ctx)
61 struct npa_state *npa;
63 npa = talloc_zero(mem_ctx, struct npa_state);
68 npa->read_queue = tevent_queue_create(npa, "npa_cli_read");
69 if (npa->read_queue == NULL) {
70 DEBUG(0, ("tevent_queue_create failed\n"));
74 npa->write_queue = tevent_queue_create(npa, "npa_cli_write");
75 if (npa->write_queue == NULL) {
76 DEBUG(0, ("tevent_queue_create failed\n"));
86 NTSTATUS make_internal_rpc_pipe_socketpair(
88 struct tevent_context *ev_ctx,
89 struct messaging_context *msg_ctx,
90 struct dcesrv_context *dce_ctx,
91 struct dcesrv_endpoint *endpoint,
92 const struct tsocket_address *remote_address,
93 const struct tsocket_address *local_address,
94 const struct auth_session_info *session_info,
95 struct npa_state **pnpa)
97 TALLOC_CTX *tmp_ctx = talloc_stackframe();
98 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
99 struct dcesrv_connection *dcesrv_conn = NULL;
100 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_server_pipes_struct(ncacn_conn,
183 ncacn_conn->remote_client_addr,
184 ncacn_conn->local_server_addr,
188 status = map_nt_error_from_unix(error);
193 * This fills in dcesrv_conn->endpoint with the endpoint
194 * associated with the socket. From this point on we know
195 * which (group of) services we are handling, but not the
196 * specific interface.
198 status = dcesrv_endpoint_connect(ncacn_conn->dce_ctx,
200 ncacn_conn->endpoint,
201 ncacn_conn->session_info,
203 DCESRV_CALL_STATE_FLAG_MAY_ASYNC,
205 if (!NT_STATUS_IS_OK(status)) {
206 DBG_ERR("Failed to connect to endpoint: %s\n",
211 dcesrv_conn->transport.private_data = ncacn_conn;
212 dcesrv_conn->transport.report_output_data =
213 dcesrv_sock_report_output_data;
214 dcesrv_conn->transport.terminate_connection =
215 dcesrv_transport_terminate_connection;
216 dcesrv_conn->send_queue = tevent_queue_create(dcesrv_conn,
217 "dcesrv send queue");
218 if (dcesrv_conn->send_queue == NULL) {
219 status = NT_STATUS_NO_MEMORY;
220 DBG_ERR("Failed to create send queue: %s\n",
225 dcesrv_conn->stream = talloc_move(dcesrv_conn, &ncacn_conn->tstream);
226 dcesrv_conn->local_address = ncacn_conn->local_server_addr;
227 dcesrv_conn->remote_address = ncacn_conn->remote_client_addr;
229 status = dcesrv_connection_loop_start(dcesrv_conn);
230 if (!NT_STATUS_IS_OK(status)) {
231 DBG_ERR("Failed to start dcesrv_connection loop: %s\n",
236 *pnpa = talloc_move(mem_ctx, &npa);
237 status = NT_STATUS_OK;
239 talloc_free(tmp_ctx);
243 static NTSTATUS make_internal_ncacn_conn(TALLOC_CTX *mem_ctx,
244 const struct ndr_interface_table *table,
245 const struct tsocket_address *remote_address,
246 const struct tsocket_address *local_address,
247 const struct auth_session_info *session_info,
248 struct messaging_context *msg_ctx,
249 struct dcerpc_ncacn_conn **_out)
251 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
252 const char *pipe_name = NULL;
256 pipe_name = dcerpc_default_transport_endpoint(mem_ctx,
260 DBG_INFO("Create pipe requested %s\n", pipe_name);
262 ncacn_conn = talloc_zero(mem_ctx, struct dcerpc_ncacn_conn);
263 if (ncacn_conn == NULL) {
264 return NT_STATUS_NO_MEMORY;
267 ncacn_conn->msg_ctx = msg_ctx;
269 if (remote_address != NULL) {
270 ncacn_conn->remote_client_addr =
271 tsocket_address_copy(remote_address, ncacn_conn);
272 if (ncacn_conn->remote_client_addr == NULL) {
273 status = NT_STATUS_NO_MEMORY;
278 if (local_address != NULL) {
279 ncacn_conn->local_server_addr =
280 tsocket_address_copy(local_address, ncacn_conn);
281 if (ncacn_conn->local_server_addr == NULL) {
282 status = NT_STATUS_NO_MEMORY;
287 ncacn_conn->session_info = copy_session_info(ncacn_conn, session_info);
288 if (ncacn_conn->session_info == NULL) {
289 status = NT_STATUS_NO_MEMORY;
293 ret = make_base_pipes_struct(ncacn_conn,
297 ncacn_conn->remote_client_addr,
298 ncacn_conn->local_server_addr,
301 DBG_ERR("No memory for pipes_struct!\n");
302 status = NT_STATUS_NO_MEMORY;
306 DEBUG(4,("Created internal pipe %s\n", pipe_name));
313 talloc_free(ncacn_conn);
317 static NTSTATUS find_ncalrpc_default_endpoint(struct dcesrv_context *dce_ctx,
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;
331 * Some services use a rpcint binding handle in their initialization,
332 * before the server is fully initialized. Search the NCALRPC endpoint
333 * with and without endpoint
335 status = dcerpc_parse_binding(tmp_ctx, "ncalrpc:", &binding);
336 if (!NT_STATUS_IS_OK(status)) {
340 status = dcesrv_find_endpoint(dce_ctx, binding, ep);
341 if (NT_STATUS_IS_OK(status)) {
345 if (lp_server_role() == ROLE_ACTIVE_DIRECTORY_DC) {
346 ep_description = "ncalrpc:[SMBD]";
348 ep_description = "ncalrpc:[DEFAULT]";
351 status = dcerpc_parse_binding(tmp_ctx, ep_description, &binding);
352 if (!NT_STATUS_IS_OK(status)) {
356 status = dcesrv_find_endpoint(dce_ctx, binding, ep);
357 if (!NT_STATUS_IS_OK(status)) {
362 talloc_free(tmp_ctx);
366 static NTSTATUS make_internal_dcesrv_connection(TALLOC_CTX *mem_ctx,
367 const struct ndr_interface_table *ndr_table,
368 struct dcerpc_ncacn_conn *ncacn_conn,
369 struct dcesrv_connection **_out)
371 struct dcesrv_connection *conn = NULL;
372 struct dcesrv_connection_context *context = NULL;
373 struct dcesrv_endpoint *endpoint = NULL;
376 conn = talloc_zero(mem_ctx, struct dcesrv_connection);
378 return NT_STATUS_NO_MEMORY;
380 conn->dce_ctx = global_dcesrv_context();
381 conn->preferred_transfer = &ndr_transfer_syntax_ndr;
382 conn->transport.private_data = ncacn_conn;
384 status = find_ncalrpc_default_endpoint(conn->dce_ctx, &endpoint);
385 if (!NT_STATUS_IS_OK(status)) {
388 conn->endpoint = endpoint;
390 conn->default_auth_state = talloc_zero(conn, struct dcesrv_auth);
391 if (conn->default_auth_state == NULL) {
392 status = NT_STATUS_NO_MEMORY;
395 conn->default_auth_state->session_info = ncacn_conn->session_info;
396 conn->default_auth_state->auth_finished = true;
398 context = talloc_zero(conn, struct dcesrv_connection_context);
399 if (context == NULL) {
400 status = NT_STATUS_NO_MEMORY;
403 context->conn = conn;
404 context->context_id = 0;
405 context->transfer_syntax = *(conn->preferred_transfer);
406 context->iface = find_interface_by_uuid(conn->endpoint,
407 &ndr_table->syntax_id.uuid,
408 ndr_table->syntax_id.if_version);
409 if (context->iface == NULL) {
410 status = NT_STATUS_RPC_INTERFACE_NOT_FOUND;
414 DLIST_ADD(conn->contexts, context);
424 struct rpcint_bh_state {
425 struct dcesrv_connection *conn;
428 static bool rpcint_bh_is_connected(struct dcerpc_binding_handle *h)
430 struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
431 struct rpcint_bh_state);
433 if (hs->conn == NULL) {
440 static uint32_t rpcint_bh_set_timeout(struct dcerpc_binding_handle *h,
443 /* TODO: implement timeouts */
447 struct rpcint_bh_raw_call_state {
448 struct dcesrv_call_state *call;
451 static struct tevent_req *rpcint_bh_raw_call_send(TALLOC_CTX *mem_ctx,
452 struct tevent_context *ev,
453 struct dcerpc_binding_handle *h,
454 const struct GUID *object,
457 const uint8_t *in_data,
460 struct rpcint_bh_state *hs =
461 dcerpc_binding_handle_data(h,
462 struct rpcint_bh_state);
463 struct tevent_req *req;
464 struct rpcint_bh_raw_call_state *state;
465 struct dcesrv_context *dce_ctx = global_dcesrv_context();
469 req = tevent_req_create(mem_ctx, &state,
470 struct rpcint_bh_raw_call_state);
475 ok = rpcint_bh_is_connected(h);
477 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
478 return tevent_req_post(req, ev);
481 state->call = talloc_zero(hs->conn, struct dcesrv_call_state);
482 if (tevent_req_nomem(state->call, req)) {
483 return tevent_req_post(req, ev);
486 state->call->event_ctx = ev;
487 state->call->conn = hs->conn;
488 state->call->context = hs->conn->contexts;
489 state->call->auth_state = hs->conn->default_auth_state;
491 if (hs->conn->assoc_group == NULL) {
492 ZERO_STRUCT(state->call->pkt);
493 state->call->pkt.u.bind.assoc_group_id = 0;
494 status = dce_ctx->callbacks.assoc_group.find(state->call);
495 if (tevent_req_nterror(req, status)) {
496 return tevent_req_post(req, ev);
500 ZERO_STRUCT(state->call->pkt);
501 state->call->pkt.u.request.opnum = opnum;
502 state->call->pkt.u.request.context_id = 0;
503 state->call->pkt.u.request.stub_and_verifier.data = discard_const_p(uint8_t, in_data);
504 state->call->pkt.u.request.stub_and_verifier.length = in_length;
506 /* TODO: allow async */
507 status = dcesrv_call_dispatch_local(state->call);
508 if (!NT_STATUS_IS_OK(status)) {
509 tevent_req_nterror(req, status);
510 return tevent_req_post(req, ev);
513 tevent_req_done(req);
514 return tevent_req_post(req, ev);
517 static NTSTATUS rpcint_bh_raw_call_recv(struct tevent_req *req,
523 struct rpcint_bh_raw_call_state *state =
525 struct rpcint_bh_raw_call_state);
526 struct data_blob_list_item *rep = NULL;
529 if (tevent_req_is_nterror(req, &status)) {
530 tevent_req_received(req);
534 rep = state->call->replies;
535 DLIST_REMOVE(state->call->replies, rep);
537 *out_data = talloc_steal(mem_ctx, rep->blob.data);
538 *out_length = rep->blob.length;
543 tevent_req_received(req);
547 struct rpcint_bh_disconnect_state {
551 static struct tevent_req *rpcint_bh_disconnect_send(TALLOC_CTX *mem_ctx,
552 struct tevent_context *ev,
553 struct dcerpc_binding_handle *h)
555 struct rpcint_bh_state *hs = dcerpc_binding_handle_data(h,
556 struct rpcint_bh_state);
557 struct tevent_req *req;
558 struct rpcint_bh_disconnect_state *state;
561 req = tevent_req_create(mem_ctx, &state,
562 struct rpcint_bh_disconnect_state);
567 ok = rpcint_bh_is_connected(h);
569 tevent_req_nterror(req, NT_STATUS_CONNECTION_DISCONNECTED);
570 return tevent_req_post(req, ev);
574 * TODO: do a real async disconnect ...
576 * For now the caller needs to free dcesrv_connection
580 tevent_req_done(req);
581 return tevent_req_post(req, ev);
584 static NTSTATUS rpcint_bh_disconnect_recv(struct tevent_req *req)
588 if (tevent_req_is_nterror(req, &status)) {
589 tevent_req_received(req);
593 tevent_req_received(req);
597 static bool rpcint_bh_ref_alloc(struct dcerpc_binding_handle *h)
602 static void rpcint_bh_do_ndr_print(struct dcerpc_binding_handle *h,
604 const void *_struct_ptr,
605 const struct ndr_interface_call *call)
607 void *struct_ptr = discard_const(_struct_ptr);
609 if (DEBUGLEVEL < 11) {
613 if (ndr_flags & NDR_IN) {
614 ndr_print_function_debug(call->ndr_print,
619 if (ndr_flags & NDR_OUT) {
620 ndr_print_function_debug(call->ndr_print,
627 static const struct dcerpc_binding_handle_ops rpcint_bh_ops = {
629 .is_connected = rpcint_bh_is_connected,
630 .set_timeout = rpcint_bh_set_timeout,
631 .raw_call_send = rpcint_bh_raw_call_send,
632 .raw_call_recv = rpcint_bh_raw_call_recv,
633 .disconnect_send = rpcint_bh_disconnect_send,
634 .disconnect_recv = rpcint_bh_disconnect_recv,
636 .ref_alloc = rpcint_bh_ref_alloc,
637 .do_ndr_print = rpcint_bh_do_ndr_print,
640 static NTSTATUS rpcint_binding_handle_ex(TALLOC_CTX *mem_ctx,
641 const struct ndr_syntax_id *abstract_syntax,
642 const struct ndr_interface_table *ndr_table,
643 const struct tsocket_address *remote_address,
644 const struct tsocket_address *local_address,
645 const struct auth_session_info *session_info,
646 struct messaging_context *msg_ctx,
647 struct dcerpc_binding_handle **binding_handle)
649 struct dcerpc_binding_handle *h;
650 struct rpcint_bh_state *hs;
651 struct dcerpc_ncacn_conn *ncacn_conn = NULL;
654 h = dcerpc_binding_handle_create(mem_ctx,
659 struct rpcint_bh_state,
662 return NT_STATUS_NO_MEMORY;
665 status = make_internal_ncacn_conn(hs,
672 if (!NT_STATUS_IS_OK(status)) {
677 status = make_internal_dcesrv_connection(ncacn_conn,
681 if (!NT_STATUS_IS_OK(status)) {
690 * @brief Create a new DCERPC Binding Handle which uses a local dispatch function.
692 * @param[in] mem_ctx The memory context to use.
694 * @param[in] ndr_table Normally the ndr_table_<name>.
696 * @param[in] remote_address The info about the connected client.
698 * @param[in] serversupplied_info The server supplied authentication function.
700 * @param[in] msg_ctx The messaging context that can be used by the server
702 * @param[out] binding_handle A pointer to store the connected
703 * dcerpc_binding_handle
705 * @return NT_STATUS_OK on success, a corresponding NT status if an
709 * struct dcerpc_binding_handle *winreg_binding;
712 * status = rpcint_binding_handle(tmp_ctx,
720 NTSTATUS rpcint_binding_handle(TALLOC_CTX *mem_ctx,
721 const struct ndr_interface_table *ndr_table,
722 const struct tsocket_address *remote_address,
723 const struct tsocket_address *local_address,
724 const struct auth_session_info *session_info,
725 struct messaging_context *msg_ctx,
726 struct dcerpc_binding_handle **binding_handle)
728 return rpcint_binding_handle_ex(mem_ctx, NULL, ndr_table, remote_address,
729 local_address, session_info,
730 msg_ctx, binding_handle);
736 * @brief Create a new RPC client context which uses a local transport.
738 * This creates a local transport. It is a shortcut to directly call the server
739 * functions and avoid marshalling.
740 * NOTE: this function should be used only by rpc_pipe_open_interface()
742 * @param[in] mem_ctx The memory context to use.
744 * @param[in] ndr_table the ndr_table_<name> structure.
746 * @param[in] serversupplied_info The server supplied authentication function.
748 * @param[in] remote_address The client address information.
750 * @param[in] msg_ctx The messaging context to use.
752 * @param[out] presult A pointer to store the connected rpc client pipe.
754 * @return NT_STATUS_OK on success, a corresponding NT status if an
757 NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx,
758 const struct ndr_interface_table *ndr_table,
759 const struct auth_session_info *session_info,
760 const struct tsocket_address *remote_address,
761 const struct tsocket_address *local_address,
762 struct messaging_context *msg_ctx,
763 struct rpc_pipe_client **presult)
765 struct rpc_pipe_client *result;
768 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
769 if (result == NULL) {
770 return NT_STATUS_NO_MEMORY;
773 result->abstract_syntax = ndr_table->syntax_id;
774 result->transfer_syntax = ndr_transfer_syntax_ndr;
776 if (remote_address == NULL) {
777 struct tsocket_address *local;
780 rc = tsocket_address_inet_from_strings(mem_ctx,
787 return NT_STATUS_NO_MEMORY;
790 remote_address = local;
793 result->max_xmit_frag = -1;
795 status = rpcint_binding_handle(result,
801 &result->binding_handle);
802 if (!NT_STATUS_IS_OK(status)) {
811 /****************************************************************************
812 * External pipes functions
813 ***************************************************************************/
815 NTSTATUS make_external_rpc_pipe(TALLOC_CTX *mem_ctx,
816 const char *pipe_name,
817 const struct tsocket_address *remote_client_address,
818 const struct tsocket_address *local_server_address,
819 const struct auth_session_info *session_info,
820 struct npa_state **pnpa)
822 TALLOC_CTX *tmp_ctx = talloc_stackframe();
823 struct auth_session_info_transport *session_info_t;
824 struct tevent_context *ev_ctx;
825 struct tevent_req *subreq;
826 const char *socket_np_dir;
827 const char *socket_dir;
828 struct npa_state *npa;
834 npa = npa_state_init(tmp_ctx);
836 status = NT_STATUS_NO_MEMORY;
840 socket_dir = lp_parm_const_string(GLOBAL_SECTION_SNUM,
844 if (socket_dir == NULL) {
845 DEBUG(0, ("external_rpc_pipe: socket_dir not set\n"));
846 status = NT_STATUS_PIPE_NOT_AVAILABLE;
850 socket_np_dir = talloc_asprintf(tmp_ctx, "%s/np", socket_dir);
851 if (socket_np_dir == NULL) {
852 DEBUG(0, ("talloc_asprintf failed\n"));
853 status = NT_STATUS_NO_MEMORY;
857 session_info_t = talloc_zero(tmp_ctx,
858 struct auth_session_info_transport);
859 if (session_info_t == NULL) {
860 DEBUG(0, ("talloc failed\n"));
861 status = NT_STATUS_NO_MEMORY;
865 session_info_t->session_info = copy_session_info(session_info_t,
867 if (session_info_t->session_info == NULL) {
868 DEBUG(0, ("copy_session_info failed\n"));
869 status = NT_STATUS_NO_MEMORY;
873 ev_ctx = samba_tevent_context_init(tmp_ctx);
874 if (ev_ctx == NULL) {
875 DEBUG(0, ("samba_tevent_context_init failed\n"));
876 status = NT_STATUS_NO_MEMORY;
881 subreq = tstream_npa_connect_send(tmp_ctx,
885 remote_client_address,
886 NULL, /* client_name */
887 local_server_address,
888 NULL, /* server_name */
890 if (subreq == NULL) {
892 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
893 "user %s\\%s failed\n",
894 socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
895 session_info_t->session_info->info->account_name));
896 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
899 ok = tevent_req_poll(subreq, ev_ctx);
902 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
903 "failed for tstream_npa_connect: %s\n",
906 session_info_t->session_info->info->domain_name,
907 session_info_t->session_info->info->account_name,
909 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
913 rc = tstream_npa_connect_recv(subreq,
919 &npa->allocation_size);
924 if (errno == ENOENT) {
928 DEBUG(l, ("tstream_npa_connect_recv to %s for pipe %s and "
929 "user %s\\%s failed: %s\n",
932 session_info_t->session_info->info->domain_name,
933 session_info_t->session_info->info->account_name,
934 strerror(sys_errno)));
935 status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
939 *pnpa = talloc_steal(mem_ctx, npa);
940 status = NT_STATUS_OK;
942 talloc_free(tmp_ctx);
947 static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx,
948 const char *pipe_name,
949 const struct tsocket_address *remote_address,
950 const struct tsocket_address *local_address,
951 const struct auth_session_info *session_info)
953 struct np_proxy_state *result;
955 const char *socket_dir;
956 struct tevent_context *ev;
957 struct tevent_req *subreq;
958 struct auth_session_info_transport *session_info_t;
963 result = talloc(mem_ctx, struct np_proxy_state);
964 if (result == NULL) {
965 DEBUG(0, ("talloc failed\n"));
969 result->read_queue = tevent_queue_create(result, "np_read");
970 if (result->read_queue == NULL) {
971 DEBUG(0, ("tevent_queue_create failed\n"));
975 result->write_queue = tevent_queue_create(result, "np_write");
976 if (result->write_queue == NULL) {
977 DEBUG(0, ("tevent_queue_create failed\n"));
981 ev = samba_tevent_context_init(talloc_tos());
983 DEBUG(0, ("samba_tevent_context_init failed\n"));
987 socket_dir = lp_parm_const_string(
988 GLOBAL_SECTION_SNUM, "external_rpc_pipe", "socket_dir",
990 if (socket_dir == NULL) {
991 DEBUG(0, ("external_rpc_pipe:socket_dir not set\n"));
994 socket_np_dir = talloc_asprintf(talloc_tos(), "%s/np", socket_dir);
995 if (socket_np_dir == NULL) {
996 DEBUG(0, ("talloc_asprintf failed\n"));
1000 session_info_t = talloc_zero(talloc_tos(), struct auth_session_info_transport);
1001 if (session_info_t == NULL) {
1002 DEBUG(0, ("talloc failed\n"));
1006 session_info_t->session_info = copy_session_info(session_info_t,
1008 if (session_info_t->session_info == NULL) {
1009 DEBUG(0, ("copy_session_info failed\n"));
1014 subreq = tstream_npa_connect_send(talloc_tos(), ev,
1018 NULL, /* client_name */
1020 NULL, /* server_name */
1022 if (subreq == NULL) {
1024 DEBUG(0, ("tstream_npa_connect_send to %s for pipe %s and "
1025 "user %s\\%s failed\n",
1026 socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
1027 session_info_t->session_info->info->account_name));
1030 ok = tevent_req_poll(subreq, ev);
1033 DEBUG(0, ("tevent_req_poll to %s for pipe %s and user %s\\%s "
1034 "failed for tstream_npa_connect: %s\n",
1035 socket_np_dir, pipe_name, session_info_t->session_info->info->domain_name,
1036 session_info_t->session_info->info->account_name,
1041 ret = tstream_npa_connect_recv(subreq, &sys_errno,
1045 &result->device_state,
1046 &result->allocation_size);
1047 TALLOC_FREE(subreq);
1050 if (errno == ENOENT) {
1053 DEBUG(l, ("tstream_npa_connect_recv to %s for pipe %s and "
1054 "user %s\\%s failed: %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,
1057 strerror(sys_errno)));
1064 TALLOC_FREE(result);
1068 static NTSTATUS rpc_pipe_open_external(TALLOC_CTX *mem_ctx,
1069 const char *pipe_name,
1070 const struct ndr_interface_table *table,
1071 const struct auth_session_info *session_info,
1072 const struct tsocket_address *remote_client_address,
1073 const struct tsocket_address *local_server_address,
1074 struct rpc_pipe_client **_result)
1076 struct rpc_pipe_client *result = NULL;
1077 struct np_proxy_state *proxy_state = NULL;
1078 struct pipe_auth_data *auth;
1079 struct tsocket_address *remote_client_addr;
1080 struct tsocket_address *local_server_addr;
1084 if (local_server_address == NULL) {
1085 /* this is an internal connection, fake up ip addresses */
1086 ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
1087 NULL, 0, &local_server_addr);
1089 return NT_STATUS_NO_MEMORY;
1091 local_server_address = local_server_addr;
1094 if (remote_client_address == NULL) {
1095 /* this is an internal connection, fake up ip addresses */
1096 ret = tsocket_address_inet_from_strings(talloc_tos(), "ip",
1097 NULL, 0, &remote_client_addr);
1099 return NT_STATUS_NO_MEMORY;
1101 remote_client_address = remote_client_addr;
1104 proxy_state = make_external_rpc_pipe_p(mem_ctx, pipe_name,
1105 remote_client_address,
1106 local_server_address,
1109 DEBUG(1, ("Unable to make proxy_state for connection to %s.\n", pipe_name));
1110 return NT_STATUS_UNSUCCESSFUL;
1113 result = talloc_zero(mem_ctx, struct rpc_pipe_client);
1114 if (result == NULL) {
1115 status = NT_STATUS_NO_MEMORY;
1119 result->abstract_syntax = table->syntax_id;
1120 result->transfer_syntax = ndr_transfer_syntax_ndr;
1122 result->desthost = get_myname(result);
1123 result->srv_name_slash = talloc_asprintf_strupper_m(
1124 result, "\\\\%s", result->desthost);
1125 if ((result->desthost == NULL) || (result->srv_name_slash == NULL)) {
1126 status = NT_STATUS_NO_MEMORY;
1130 result->max_xmit_frag = RPC_MAX_PDU_FRAG_LEN;
1132 status = rpc_transport_tstream_init(result,
1133 &proxy_state->npipe,
1134 &result->transport);
1135 if (!NT_STATUS_IS_OK(status)) {
1139 result->binding_handle = rpccli_bh_create(result, NULL, table);
1140 if (result->binding_handle == NULL) {
1141 status = NT_STATUS_NO_MEMORY;
1142 DEBUG(0, ("Failed to create binding handle.\n"));
1146 result->auth = talloc_zero(result, struct pipe_auth_data);
1147 if (!result->auth) {
1148 status = NT_STATUS_NO_MEMORY;
1151 result->auth->auth_type = DCERPC_AUTH_TYPE_NONE;
1152 result->auth->auth_level = DCERPC_AUTH_LEVEL_NONE;
1153 result->auth->auth_context_id = 0;
1155 status = rpccli_anon_bind_data(result, &auth);
1156 if (!NT_STATUS_IS_OK(status)) {
1157 DEBUG(0, ("Failed to initialize anonymous bind.\n"));
1161 status = rpc_pipe_bind(result, auth);
1162 if (!NT_STATUS_IS_OK(status)) {
1163 DEBUG(0, ("Failed to bind external pipe.\n"));
1168 if (!NT_STATUS_IS_OK(status)) {
1169 TALLOC_FREE(result);
1171 TALLOC_FREE(proxy_state);
1177 * @brief Create a new RPC client context which uses a local dispatch function
1178 * or a remote transport, depending on rpc_server configuration for the
1181 * @param[in] mem_ctx The memory context to use.
1183 * @param[in] abstract_syntax Normally the syntax_id of the autogenerated
1186 * @param[in] serversupplied_info The server supplied authentication function.
1188 * @param[in] remote_address The client address information.
1190 * @param[in] msg_ctx The messaging context to use.
1192 * @param[out] presult A pointer to store the connected rpc client pipe.
1194 * @return NT_STATUS_OK on success, a corresponding NT status if an
1198 * struct rpc_pipe_client *winreg_pipe;
1201 * status = rpc_pipe_open_interface(tmp_ctx,
1202 * &ndr_table_winreg.syntax_id,
1209 NTSTATUS rpc_pipe_open_interface(TALLOC_CTX *mem_ctx,
1210 const struct ndr_interface_table *table,
1211 const struct auth_session_info *session_info,
1212 const struct tsocket_address *remote_address,
1213 const struct tsocket_address *local_address,
1214 struct messaging_context *msg_ctx,
1215 struct rpc_pipe_client **cli_pipe)
1217 struct rpc_pipe_client *cli = NULL;
1218 enum rpc_service_mode_e pipe_mode;
1219 const char *pipe_name;
1221 TALLOC_CTX *tmp_ctx;
1223 if (cli_pipe != NULL) {
1224 if (rpccli_is_connected(*cli_pipe)) {
1225 return NT_STATUS_OK;
1227 TALLOC_FREE(*cli_pipe);
1231 tmp_ctx = talloc_stackframe();
1232 if (tmp_ctx == NULL) {
1233 return NT_STATUS_NO_MEMORY;
1236 pipe_name = dcerpc_default_transport_endpoint(mem_ctx, NCACN_NP, table);
1237 if (pipe_name == NULL) {
1238 DEBUG(1, ("Unable to find pipe name to forward %s to.\n", table->name));
1239 status = NT_STATUS_INVALID_PARAMETER;
1243 while (pipe_name[0] == '\\') {
1247 DEBUG(5, ("Connecting to %s pipe.\n", pipe_name));
1249 pipe_mode = rpc_service_mode(pipe_name);
1251 switch (pipe_mode) {
1252 case RPC_SERVICE_MODE_EMBEDDED:
1253 status = rpc_pipe_open_internal(tmp_ctx,
1254 table, session_info,
1255 remote_address, local_address,
1258 if (!NT_STATUS_IS_OK(status)) {
1262 case RPC_SERVICE_MODE_EXTERNAL:
1263 /* It would be nice to just use rpc_pipe_open_ncalrpc() but
1264 * for now we need to use the special proxy setup to connect
1267 status = rpc_pipe_open_external(tmp_ctx,
1270 remote_address, local_address,
1272 if (!NT_STATUS_IS_OK(status)) {
1276 case RPC_SERVICE_MODE_DISABLED:
1277 status = NT_STATUS_NOT_IMPLEMENTED;
1278 DEBUG(0, ("Service pipe %s is disabled in config file: %s",
1279 pipe_name, nt_errstr(status)));
1283 status = NT_STATUS_OK;
1285 if (NT_STATUS_IS_OK(status) && cli_pipe != NULL) {
1286 *cli_pipe = talloc_move(mem_ctx, &cli);
1288 TALLOC_FREE(tmp_ctx);