s3-rpc_server: Move the endpoint registration to own file.
[Samba/gbeck.git] / source3 / rpc_server / rpc_ep_register.c
blob906dd6c59e6cfd1131b6dbaa32d1f96c15f11f86
1 /*
2 * Unix SMB/CIFS implementation.
4 * RPC Endpoint Registration
6 * Copyright (c) 2011 Andreas Schneider <asn@samba.org>
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 "ntdomain.h"
25 #include "../librpc/gen_ndr/ndr_epmapper_c.h"
27 #include "librpc/rpc/dcerpc_ep.h"
28 #include "rpc_server/rpc_ep_register.h"
30 static void rpc_ep_register_loop(struct tevent_req *subreq);
31 static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx,
32 struct tevent_context *ev_ctx,
33 struct messaging_context *msg_ctx,
34 const struct ndr_interface_table *iface,
35 const char *ncalrpc,
36 uint16_t port,
37 struct dcerpc_binding_handle **pbh);
39 struct rpc_ep_regsiter_state {
40 struct dcerpc_binding_handle *h;
42 TALLOC_CTX *mem_ctx;
43 struct tevent_context *ev_ctx;
44 struct messaging_context *msg_ctx;
46 const struct ndr_interface_table *iface;
48 const char *ncalrpc;
49 uint16_t port;
51 uint32_t wait_time;
54 NTSTATUS rpc_ep_register(struct tevent_context *ev_ctx,
55 struct messaging_context *msg_ctx,
56 const struct ndr_interface_table *iface,
57 const char *ncalrpc,
58 uint16_t port)
60 struct rpc_ep_regsiter_state *state;
61 struct tevent_req *req;
63 state = talloc(ev_ctx, struct rpc_ep_regsiter_state);
64 if (state == NULL) {
65 return NT_STATUS_NO_MEMORY;
68 state->mem_ctx = talloc_named(state,
70 "ep %s %p",
71 iface->name, state);
72 if (state->mem_ctx == NULL) {
73 talloc_free(state);
74 return NT_STATUS_NO_MEMORY;
77 state->wait_time = 1;
78 state->ev_ctx = ev_ctx;
79 state->msg_ctx = msg_ctx;
80 state->iface = iface;
81 state->ncalrpc = talloc_strdup(state, ncalrpc);
82 state->port = port;
84 req = tevent_wakeup_send(state->mem_ctx,
85 state->ev_ctx,
86 timeval_current_ofs(1, 0));
87 if (tevent_req_nomem(state->mem_ctx, req)) {
88 talloc_free(state);
89 return NT_STATUS_NO_MEMORY;
92 tevent_req_set_callback(req, rpc_ep_register_loop, state);
94 return NT_STATUS_OK;
97 #define MONITOR_WAIT_TIME 15
98 static void rpc_ep_monitor_loop(struct tevent_req *subreq);
100 static void rpc_ep_register_loop(struct tevent_req *subreq)
102 struct rpc_ep_regsiter_state *state =
103 tevent_req_callback_data(subreq, struct rpc_ep_regsiter_state);
104 NTSTATUS status;
105 bool ok;
107 ok = tevent_wakeup_recv(subreq);
108 TALLOC_FREE(subreq);
109 if (!ok) {
110 talloc_free(state);
111 return;
114 status = rpc_ep_try_register(state->mem_ctx,
115 state->ev_ctx,
116 state->msg_ctx,
117 state->iface,
118 state->ncalrpc,
119 state->port,
120 &state->h);
121 if (NT_STATUS_IS_OK(status)) {
122 /* endpoint registered, monitor the connnection. */
123 subreq = tevent_wakeup_send(state->mem_ctx,
124 state->ev_ctx,
125 timeval_current_ofs(MONITOR_WAIT_TIME, 0));
126 if (tevent_req_nomem(state->mem_ctx, subreq)) {
127 talloc_free(state);
128 return;
131 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
132 return;
135 state->wait_time = state->wait_time * 2;
136 if (state->wait_time > 16) {
137 DEBUG(0, ("Failed to register endpoint '%s'!\n",
138 state->iface->name));
139 state->wait_time = 16;
142 subreq = tevent_wakeup_send(state->mem_ctx,
143 state->ev_ctx,
144 timeval_current_ofs(state->wait_time, 0));
145 if (tevent_req_nomem(state->mem_ctx, subreq)) {
146 talloc_free(state);
147 return;
150 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
151 return;
154 static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx,
155 struct tevent_context *ev_ctx,
156 struct messaging_context *msg_ctx,
157 const struct ndr_interface_table *iface,
158 const char *ncalrpc,
159 uint16_t port,
160 struct dcerpc_binding_handle **pbh)
162 struct dcerpc_binding_vector *v = NULL;
163 NTSTATUS status;
165 status = dcerpc_binding_vector_create(mem_ctx,
166 iface,
167 port,
168 ncalrpc,
169 &v);
170 if (!NT_STATUS_IS_OK(status)) {
171 return status;
174 status = dcerpc_ep_register(mem_ctx,
175 msg_ctx,
176 iface,
178 &iface->syntax_id.uuid,
179 iface->name,
180 pbh);
181 talloc_free(v);
182 if (!NT_STATUS_IS_OK(status)) {
183 return status;
186 return status;
190 * Monitor the connection to the endpoint mapper and if it goes away, try to
191 * register the endpoint.
193 static void rpc_ep_monitor_loop(struct tevent_req *subreq)
195 struct rpc_ep_regsiter_state *state =
196 tevent_req_callback_data(subreq, struct rpc_ep_regsiter_state);
197 struct policy_handle entry_handle;
198 struct dcerpc_binding map_binding;
199 struct epm_twr_p_t towers[10];
200 struct epm_twr_t *map_tower;
201 uint32_t num_towers = 0;
202 struct GUID object;
203 NTSTATUS status;
204 uint32_t result = EPMAPPER_STATUS_CANT_PERFORM_OP;
205 TALLOC_CTX *tmp_ctx;
206 bool ok;
208 ZERO_STRUCT(object);
209 ZERO_STRUCT(entry_handle);
211 tmp_ctx = talloc_stackframe();
212 if (tmp_ctx == NULL) {
213 talloc_free(state);
214 return;
217 ok = tevent_wakeup_recv(subreq);
218 TALLOC_FREE(subreq);
219 if (!ok) {
220 talloc_free(state);
221 return;
224 /* Create map tower */
225 map_binding.transport = NCACN_NP;
226 map_binding.object = state->iface->syntax_id;
227 map_binding.host = "";
228 map_binding.endpoint = "";
230 map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
231 if (map_tower == NULL) {
232 talloc_free(tmp_ctx);
233 talloc_free(state);
234 return;
237 status = dcerpc_binding_build_tower(map_tower, &map_binding,
238 &map_tower->tower);
239 if (!NT_STATUS_IS_OK(status)) {
240 talloc_free(tmp_ctx);
241 talloc_free(state);
242 return;
245 ok = false;
246 status = dcerpc_epm_Map(state->h,
247 tmp_ctx,
248 &object,
249 map_tower,
250 &entry_handle,
252 &num_towers,
253 towers,
254 &result);
255 if (NT_STATUS_IS_OK(status)) {
256 ok = true;
258 if (result == EPMAPPER_STATUS_OK ||
259 result == EPMAPPER_STATUS_NO_MORE_ENTRIES) {
260 ok = true;
262 if (num_towers == 0) {
263 ok = false;
266 talloc_free(tmp_ctx);
268 subreq = tevent_wakeup_send(state->mem_ctx,
269 state->ev_ctx,
270 timeval_current_ofs(MONITOR_WAIT_TIME, 0));
271 if (tevent_req_nomem(state->mem_ctx, subreq)) {
272 talloc_free(state);
273 return;
276 if (ok) {
277 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
278 } else {
279 TALLOC_FREE(state->h);
280 state->wait_time = 1;
282 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
285 return;