From e25b34ab0c565cb702b278d22552828e6ba090a5 Mon Sep 17 00:00:00 2001 From: Andreas Schneider Date: Mon, 6 Jun 2011 11:10:02 +0200 Subject: s3-rpc_server: Move the endpoint registration to own file. --- source3/rpc_server/rpc_ep_register.c | 286 +++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 source3/rpc_server/rpc_ep_register.c (limited to 'source3/rpc_server/rpc_ep_register.c') diff --git a/source3/rpc_server/rpc_ep_register.c b/source3/rpc_server/rpc_ep_register.c new file mode 100644 index 0000000000..906dd6c59e --- /dev/null +++ b/source3/rpc_server/rpc_ep_register.c @@ -0,0 +1,286 @@ +/* + * Unix SMB/CIFS implementation. + * + * RPC Endpoint Registration + * + * Copyright (c) 2011 Andreas Schneider + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include "includes.h" +#include "ntdomain.h" + +#include "../librpc/gen_ndr/ndr_epmapper_c.h" + +#include "librpc/rpc/dcerpc_ep.h" +#include "rpc_server/rpc_ep_register.h" + +static void rpc_ep_register_loop(struct tevent_req *subreq); +static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx, + struct tevent_context *ev_ctx, + struct messaging_context *msg_ctx, + const struct ndr_interface_table *iface, + const char *ncalrpc, + uint16_t port, + struct dcerpc_binding_handle **pbh); + +struct rpc_ep_regsiter_state { + struct dcerpc_binding_handle *h; + + TALLOC_CTX *mem_ctx; + struct tevent_context *ev_ctx; + struct messaging_context *msg_ctx; + + const struct ndr_interface_table *iface; + + const char *ncalrpc; + uint16_t port; + + uint32_t wait_time; +}; + +NTSTATUS rpc_ep_register(struct tevent_context *ev_ctx, + struct messaging_context *msg_ctx, + const struct ndr_interface_table *iface, + const char *ncalrpc, + uint16_t port) +{ + struct rpc_ep_regsiter_state *state; + struct tevent_req *req; + + state = talloc(ev_ctx, struct rpc_ep_regsiter_state); + if (state == NULL) { + return NT_STATUS_NO_MEMORY; + } + + state->mem_ctx = talloc_named(state, + 0, + "ep %s %p", + iface->name, state); + if (state->mem_ctx == NULL) { + talloc_free(state); + return NT_STATUS_NO_MEMORY; + } + + state->wait_time = 1; + state->ev_ctx = ev_ctx; + state->msg_ctx = msg_ctx; + state->iface = iface; + state->ncalrpc = talloc_strdup(state, ncalrpc); + state->port = port; + + req = tevent_wakeup_send(state->mem_ctx, + state->ev_ctx, + timeval_current_ofs(1, 0)); + if (tevent_req_nomem(state->mem_ctx, req)) { + talloc_free(state); + return NT_STATUS_NO_MEMORY; + } + + tevent_req_set_callback(req, rpc_ep_register_loop, state); + + return NT_STATUS_OK; +} + +#define MONITOR_WAIT_TIME 15 +static void rpc_ep_monitor_loop(struct tevent_req *subreq); + +static void rpc_ep_register_loop(struct tevent_req *subreq) +{ + struct rpc_ep_regsiter_state *state = + tevent_req_callback_data(subreq, struct rpc_ep_regsiter_state); + NTSTATUS status; + bool ok; + + ok = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (!ok) { + talloc_free(state); + return; + } + + status = rpc_ep_try_register(state->mem_ctx, + state->ev_ctx, + state->msg_ctx, + state->iface, + state->ncalrpc, + state->port, + &state->h); + if (NT_STATUS_IS_OK(status)) { + /* endpoint registered, monitor the connnection. */ + subreq = tevent_wakeup_send(state->mem_ctx, + state->ev_ctx, + timeval_current_ofs(MONITOR_WAIT_TIME, 0)); + if (tevent_req_nomem(state->mem_ctx, subreq)) { + talloc_free(state); + return; + } + + tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state); + return; + } + + state->wait_time = state->wait_time * 2; + if (state->wait_time > 16) { + DEBUG(0, ("Failed to register endpoint '%s'!\n", + state->iface->name)); + state->wait_time = 16; + } + + subreq = tevent_wakeup_send(state->mem_ctx, + state->ev_ctx, + timeval_current_ofs(state->wait_time, 0)); + if (tevent_req_nomem(state->mem_ctx, subreq)) { + talloc_free(state); + return; + } + + tevent_req_set_callback(subreq, rpc_ep_register_loop, state); + return; +} + +static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx, + struct tevent_context *ev_ctx, + struct messaging_context *msg_ctx, + const struct ndr_interface_table *iface, + const char *ncalrpc, + uint16_t port, + struct dcerpc_binding_handle **pbh) +{ + struct dcerpc_binding_vector *v = NULL; + NTSTATUS status; + + status = dcerpc_binding_vector_create(mem_ctx, + iface, + port, + ncalrpc, + &v); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = dcerpc_ep_register(mem_ctx, + msg_ctx, + iface, + v, + &iface->syntax_id.uuid, + iface->name, + pbh); + talloc_free(v); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + return status; +} + +/* + * Monitor the connection to the endpoint mapper and if it goes away, try to + * register the endpoint. + */ +static void rpc_ep_monitor_loop(struct tevent_req *subreq) +{ + struct rpc_ep_regsiter_state *state = + tevent_req_callback_data(subreq, struct rpc_ep_regsiter_state); + struct policy_handle entry_handle; + struct dcerpc_binding map_binding; + struct epm_twr_p_t towers[10]; + struct epm_twr_t *map_tower; + uint32_t num_towers = 0; + struct GUID object; + NTSTATUS status; + uint32_t result = EPMAPPER_STATUS_CANT_PERFORM_OP; + TALLOC_CTX *tmp_ctx; + bool ok; + + ZERO_STRUCT(object); + ZERO_STRUCT(entry_handle); + + tmp_ctx = talloc_stackframe(); + if (tmp_ctx == NULL) { + talloc_free(state); + return; + } + + ok = tevent_wakeup_recv(subreq); + TALLOC_FREE(subreq); + if (!ok) { + talloc_free(state); + return; + } + + /* Create map tower */ + map_binding.transport = NCACN_NP; + map_binding.object = state->iface->syntax_id; + map_binding.host = ""; + map_binding.endpoint = ""; + + map_tower = talloc_zero(tmp_ctx, struct epm_twr_t); + if (map_tower == NULL) { + talloc_free(tmp_ctx); + talloc_free(state); + return; + } + + status = dcerpc_binding_build_tower(map_tower, &map_binding, + &map_tower->tower); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + talloc_free(state); + return; + } + + ok = false; + status = dcerpc_epm_Map(state->h, + tmp_ctx, + &object, + map_tower, + &entry_handle, + 10, + &num_towers, + towers, + &result); + if (NT_STATUS_IS_OK(status)) { + ok = true; + } + if (result == EPMAPPER_STATUS_OK || + result == EPMAPPER_STATUS_NO_MORE_ENTRIES) { + ok = true; + } + if (num_towers == 0) { + ok = false; + } + + talloc_free(tmp_ctx); + + subreq = tevent_wakeup_send(state->mem_ctx, + state->ev_ctx, + timeval_current_ofs(MONITOR_WAIT_TIME, 0)); + if (tevent_req_nomem(state->mem_ctx, subreq)) { + talloc_free(state); + return; + } + + if (ok) { + tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state); + } else { + TALLOC_FREE(state->h); + state->wait_time = 1; + + tevent_req_set_callback(subreq, rpc_ep_register_loop, state); + } + + return; +} -- cgit