VERSION: Re-enable git snapshots.
[Samba.git] / source3 / rpc_server / rpc_ep_register.c
blob96a3705faa2b1121bacd05217ac1f5e4b14e5cbe
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 struct dcerpc_binding_vector *v,
36 struct dcerpc_binding_handle **pbh);
38 struct rpc_ep_regsiter_state {
39 struct dcerpc_binding_handle *h;
41 TALLOC_CTX *mem_ctx;
42 struct tevent_context *ev_ctx;
43 struct messaging_context *msg_ctx;
45 const struct ndr_interface_table *iface;
46 const struct dcerpc_binding_vector *vector;
48 uint32_t wait_time;
51 NTSTATUS rpc_ep_register(struct tevent_context *ev_ctx,
52 struct messaging_context *msg_ctx,
53 const struct ndr_interface_table *iface,
54 const struct dcerpc_binding_vector *v)
56 struct rpc_ep_regsiter_state *state;
57 struct tevent_req *req;
59 state = talloc(ev_ctx, struct rpc_ep_regsiter_state);
60 if (state == NULL) {
61 return NT_STATUS_NO_MEMORY;
64 state->mem_ctx = talloc_named(state,
66 "ep %s %p",
67 iface->name, state);
68 if (state->mem_ctx == NULL) {
69 talloc_free(state);
70 return NT_STATUS_NO_MEMORY;
73 state->wait_time = 1;
74 state->ev_ctx = ev_ctx;
75 state->msg_ctx = msg_ctx;
76 state->iface = iface;
77 state->vector = dcerpc_binding_vector_dup(state, v);
78 if (state->vector == NULL) {
79 talloc_free(state);
80 return NT_STATUS_NO_MEMORY;
83 req = tevent_wakeup_send(state->mem_ctx,
84 state->ev_ctx,
85 timeval_current_ofs(1, 0));
86 if (tevent_req_nomem(state->mem_ctx, req)) {
87 talloc_free(state);
88 return NT_STATUS_NO_MEMORY;
91 tevent_req_set_callback(req, rpc_ep_register_loop, state);
93 return NT_STATUS_OK;
96 #define MONITOR_WAIT_TIME 30
97 static void rpc_ep_monitor_loop(struct tevent_req *subreq);
99 static void rpc_ep_register_loop(struct tevent_req *subreq)
101 struct rpc_ep_regsiter_state *state =
102 tevent_req_callback_data(subreq, struct rpc_ep_regsiter_state);
103 NTSTATUS status;
104 bool ok;
106 ok = tevent_wakeup_recv(subreq);
107 TALLOC_FREE(subreq);
108 if (!ok) {
109 talloc_free(state);
110 return;
113 status = rpc_ep_try_register(state->mem_ctx,
114 state->ev_ctx,
115 state->msg_ctx,
116 state->iface,
117 state->vector,
118 &state->h);
119 if (NT_STATUS_IS_OK(status)) {
120 /* endpoint registered, monitor the connnection. */
121 subreq = tevent_wakeup_send(state->mem_ctx,
122 state->ev_ctx,
123 timeval_current_ofs(MONITOR_WAIT_TIME, 0));
124 if (tevent_req_nomem(state->mem_ctx, subreq)) {
125 talloc_free(state);
126 return;
129 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
130 return;
133 state->wait_time = state->wait_time * 2;
134 if (state->wait_time > 16) {
135 DEBUG(0, ("Failed to register endpoint '%s'!\n",
136 state->iface->name));
137 state->wait_time = 16;
140 subreq = tevent_wakeup_send(state->mem_ctx,
141 state->ev_ctx,
142 timeval_current_ofs(state->wait_time, 0));
143 if (tevent_req_nomem(state->mem_ctx, subreq)) {
144 talloc_free(state);
145 return;
148 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
149 return;
152 static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx,
153 struct tevent_context *ev_ctx,
154 struct messaging_context *msg_ctx,
155 const struct ndr_interface_table *iface,
156 const struct dcerpc_binding_vector *v,
157 struct dcerpc_binding_handle **pbh)
159 NTSTATUS status;
161 status = dcerpc_ep_register(mem_ctx,
162 msg_ctx,
163 iface,
165 &iface->syntax_id.uuid,
166 iface->name,
167 pbh);
168 if (!NT_STATUS_IS_OK(status)) {
169 return status;
172 return status;
176 * Monitor the connection to the endpoint mapper and if it goes away, try to
177 * register the endpoint.
179 static void rpc_ep_monitor_loop(struct tevent_req *subreq)
181 struct rpc_ep_regsiter_state *state =
182 tevent_req_callback_data(subreq, struct rpc_ep_regsiter_state);
183 struct policy_handle entry_handle;
184 struct dcerpc_binding map_binding;
185 struct epm_twr_p_t towers[10];
186 struct epm_twr_t *map_tower;
187 uint32_t num_towers = 0;
188 struct GUID object;
189 NTSTATUS status;
190 uint32_t result = EPMAPPER_STATUS_CANT_PERFORM_OP;
191 TALLOC_CTX *tmp_ctx;
192 bool ok;
194 ZERO_STRUCT(object);
195 ZERO_STRUCT(entry_handle);
197 tmp_ctx = talloc_stackframe();
198 if (tmp_ctx == NULL) {
199 talloc_free(state);
200 return;
203 ok = tevent_wakeup_recv(subreq);
204 TALLOC_FREE(subreq);
205 if (!ok) {
206 talloc_free(state);
207 return;
210 /* Create map tower */
211 map_binding.transport = NCACN_NP;
212 map_binding.object = state->iface->syntax_id;
213 map_binding.host = "";
214 map_binding.endpoint = "";
216 map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
217 if (map_tower == NULL) {
218 talloc_free(tmp_ctx);
219 talloc_free(state);
220 return;
223 status = dcerpc_binding_build_tower(map_tower, &map_binding,
224 &map_tower->tower);
225 if (!NT_STATUS_IS_OK(status)) {
226 talloc_free(tmp_ctx);
227 talloc_free(state);
228 return;
231 ok = false;
232 status = dcerpc_epm_Map(state->h,
233 tmp_ctx,
234 &object,
235 map_tower,
236 &entry_handle,
238 &num_towers,
239 towers,
240 &result);
241 if (NT_STATUS_IS_OK(status)) {
242 ok = true;
244 if (result == EPMAPPER_STATUS_OK ||
245 result == EPMAPPER_STATUS_NO_MORE_ENTRIES) {
246 ok = true;
248 if (num_towers == 0) {
249 ok = false;
252 dcerpc_epm_LookupHandleFree(state->h,
253 tmp_ctx,
254 &entry_handle,
255 &result);
256 talloc_free(tmp_ctx);
258 subreq = tevent_wakeup_send(state->mem_ctx,
259 state->ev_ctx,
260 timeval_current_ofs(MONITOR_WAIT_TIME, 0));
261 if (tevent_req_nomem(state->mem_ctx, subreq)) {
262 talloc_free(state);
263 return;
266 if (ok) {
267 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
268 } else {
269 TALLOC_FREE(state->h);
270 state->wait_time = 1;
272 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
275 return;