dns: Use new DNS debugclass in DNS server
[kai/samba.git] / source3 / rpc_server / rpc_ep_register.c
1 /*
2  *  Unix SMB/CIFS implementation.
3  *
4  *  RPC Endpoint Registration
5  *
6  *  Copyright (c) 2011      Andreas Schneider <asn@samba.org>
7  *
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.
12  *
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.
17  *
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/>.
20  */
21
22 #include "includes.h"
23 #include "ntdomain.h"
24
25 #include "../librpc/gen_ndr/ndr_epmapper_c.h"
26
27 #include "librpc/rpc/dcerpc_ep.h"
28 #include "rpc_server/rpc_ep_register.h"
29
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);
37
38 struct rpc_ep_regsiter_state {
39         struct dcerpc_binding_handle *h;
40
41         TALLOC_CTX *mem_ctx;
42         struct tevent_context *ev_ctx;
43         struct messaging_context *msg_ctx;
44
45         const struct ndr_interface_table *iface;
46         const struct dcerpc_binding_vector *vector;
47
48         uint32_t wait_time;
49 };
50
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)
55 {
56         struct rpc_ep_regsiter_state *state;
57         struct tevent_req *req;
58
59         state = talloc(ev_ctx, struct rpc_ep_regsiter_state);
60         if (state == NULL) {
61                 return NT_STATUS_NO_MEMORY;
62         }
63
64         state->mem_ctx = talloc_named(state,
65                                       0,
66                                       "ep %s %p",
67                                       iface->name, state);
68         if (state->mem_ctx == NULL) {
69                 talloc_free(state);
70                 return NT_STATUS_NO_MEMORY;
71         }
72
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;
81         }
82
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;
89         }
90
91         tevent_req_set_callback(req, rpc_ep_register_loop, state);
92
93         return NT_STATUS_OK;
94 }
95
96 #define MONITOR_WAIT_TIME 30
97 static void rpc_ep_monitor_loop(struct tevent_req *subreq);
98
99 static void rpc_ep_register_loop(struct tevent_req *subreq)
100 {
101         struct rpc_ep_regsiter_state *state =
102                 tevent_req_callback_data(subreq, struct rpc_ep_regsiter_state);
103         NTSTATUS status;
104         bool ok;
105
106         ok = tevent_wakeup_recv(subreq);
107         TALLOC_FREE(subreq);
108         if (!ok) {
109                 talloc_free(state);
110                 return;
111         }
112
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;
127                 }
128
129                 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
130                 return;
131         }
132
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;
138         }
139
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;
146         }
147
148         tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
149         return;
150 }
151
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)
158 {
159         NTSTATUS status;
160
161         status = dcerpc_ep_register(mem_ctx,
162                                     msg_ctx,
163                                     iface,
164                                     v,
165                                     &iface->syntax_id.uuid,
166                                     iface->name,
167                                     pbh);
168         if (!NT_STATUS_IS_OK(status)) {
169                 return status;
170         }
171
172         return status;
173 }
174
175 /*
176  * Monitor the connection to the endpoint mapper and if it goes away, try to
177  * register the endpoint.
178  */
179 static void rpc_ep_monitor_loop(struct tevent_req *subreq)
180 {
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;
193
194         ZERO_STRUCT(object);
195         ZERO_STRUCT(entry_handle);
196
197         tmp_ctx = talloc_stackframe();
198         if (tmp_ctx == NULL) {
199                 talloc_free(state);
200                 return;
201         }
202
203         ok = tevent_wakeup_recv(subreq);
204         TALLOC_FREE(subreq);
205         if (!ok) {
206                 talloc_free(state);
207                 return;
208         }
209
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 = "";
215
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;
221         }
222
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;
229         }
230
231         ok = false;
232         status = dcerpc_epm_Map(state->h,
233                                 tmp_ctx,
234                                 &object,
235                                 map_tower,
236                                 &entry_handle,
237                                 10,
238                                 &num_towers,
239                                 towers,
240                                 &result);
241         if (NT_STATUS_IS_OK(status)) {
242                 ok = true;
243         }
244         if (result == EPMAPPER_STATUS_OK ||
245             result == EPMAPPER_STATUS_NO_MORE_ENTRIES) {
246                 ok = true;
247         }
248         if (num_towers == 0) {
249                 ok = false;
250         }
251
252         talloc_free(tmp_ctx);
253
254         subreq = tevent_wakeup_send(state->mem_ctx,
255                                     state->ev_ctx,
256                                     timeval_current_ofs(MONITOR_WAIT_TIME, 0));
257         if (tevent_req_nomem(state->mem_ctx, subreq)) {
258                 talloc_free(state);
259                 return;
260         }
261
262         if (ok) {
263                 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
264         } else {
265                 TALLOC_FREE(state->h);
266                 state->wait_time = 1;
267
268                 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
269         }
270
271         return;
272 }