rpc_server: Remove rpc_ep_register_state->mem_ctx
[amitay/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_register_state {
39         struct dcerpc_binding_handle *h;
40
41         struct tevent_context *ev_ctx;
42         struct messaging_context *msg_ctx;
43
44         const struct ndr_interface_table *iface;
45         const struct dcerpc_binding_vector *vector;
46
47         uint32_t wait_time;
48 };
49
50 NTSTATUS rpc_ep_register(struct tevent_context *ev_ctx,
51                          struct messaging_context *msg_ctx,
52                          const struct ndr_interface_table *iface,
53                          const struct dcerpc_binding_vector *v)
54 {
55         struct rpc_ep_register_state *state;
56         struct tevent_req *req;
57
58         state = talloc(ev_ctx, struct rpc_ep_register_state);
59         if (state == NULL) {
60                 return NT_STATUS_NO_MEMORY;
61         }
62
63         state->wait_time = 1;
64         state->ev_ctx = ev_ctx;
65         state->msg_ctx = msg_ctx;
66         state->iface = iface;
67         state->vector = dcerpc_binding_vector_dup(state, v);
68         if (state->vector == NULL) {
69                 talloc_free(state);
70                 return NT_STATUS_NO_MEMORY;
71         }
72
73         req = tevent_wakeup_send(state,
74                                  state->ev_ctx,
75                                  timeval_current_ofs(1, 0));
76         if (req == NULL) {
77                 talloc_free(state);
78                 return NT_STATUS_NO_MEMORY;
79         }
80
81         tevent_req_set_callback(req, rpc_ep_register_loop, state);
82
83         return NT_STATUS_OK;
84 }
85
86 #define MONITOR_WAIT_TIME 30
87 static void rpc_ep_monitor_loop(struct tevent_req *subreq);
88
89 static void rpc_ep_register_loop(struct tevent_req *subreq)
90 {
91         struct rpc_ep_register_state *state =
92                 tevent_req_callback_data(subreq, struct rpc_ep_register_state);
93         NTSTATUS status;
94         bool ok;
95
96         ok = tevent_wakeup_recv(subreq);
97         TALLOC_FREE(subreq);
98         if (!ok) {
99                 talloc_free(state);
100                 return;
101         }
102
103         status = rpc_ep_try_register(state,
104                                      state->ev_ctx,
105                                      state->msg_ctx,
106                                      state->iface,
107                                      state->vector,
108                                      &state->h);
109         if (NT_STATUS_IS_OK(status)) {
110                 /* endpoint registered, monitor the connnection. */
111                 subreq = tevent_wakeup_send(state,
112                                             state->ev_ctx,
113                                             timeval_current_ofs(MONITOR_WAIT_TIME, 0));
114                 if (subreq == NULL) {
115                         talloc_free(state);
116                         return;
117                 }
118
119                 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
120                 return;
121         }
122
123         state->wait_time = state->wait_time * 2;
124         if (state->wait_time > 16) {
125                 DEBUG(0, ("Failed to register endpoint '%s'!\n",
126                            state->iface->name));
127                 state->wait_time = 16;
128         }
129
130         subreq = tevent_wakeup_send(state,
131                                     state->ev_ctx,
132                                     timeval_current_ofs(state->wait_time, 0));
133         if (subreq == NULL) {
134                 talloc_free(state);
135                 return;
136         }
137
138         tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
139         return;
140 }
141
142 static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx,
143                                     struct tevent_context *ev_ctx,
144                                     struct messaging_context *msg_ctx,
145                                     const struct ndr_interface_table *iface,
146                                     const struct dcerpc_binding_vector *v,
147                                     struct dcerpc_binding_handle **pbh)
148 {
149         NTSTATUS status;
150
151         status = dcerpc_ep_register(mem_ctx,
152                                     msg_ctx,
153                                     iface,
154                                     v,
155                                     &iface->syntax_id.uuid,
156                                     iface->name,
157                                     pbh);
158         if (!NT_STATUS_IS_OK(status)) {
159                 return status;
160         }
161
162         return status;
163 }
164
165 /*
166  * Monitor the connection to the endpoint mapper and if it goes away, try to
167  * register the endpoint.
168  */
169 static void rpc_ep_monitor_loop(struct tevent_req *subreq)
170 {
171         struct rpc_ep_register_state *state =
172                 tevent_req_callback_data(subreq, struct rpc_ep_register_state);
173         struct policy_handle entry_handle;
174         struct dcerpc_binding map_binding;
175         struct epm_twr_p_t towers[10];
176         struct epm_twr_t *map_tower;
177         uint32_t num_towers = 0;
178         struct GUID object;
179         NTSTATUS status;
180         uint32_t result = EPMAPPER_STATUS_CANT_PERFORM_OP;
181         TALLOC_CTX *tmp_ctx;
182         bool ok;
183
184         ZERO_STRUCT(object);
185         ZERO_STRUCT(entry_handle);
186
187         tmp_ctx = talloc_stackframe();
188         if (tmp_ctx == NULL) {
189                 talloc_free(state);
190                 return;
191         }
192
193         ok = tevent_wakeup_recv(subreq);
194         TALLOC_FREE(subreq);
195         if (!ok) {
196                 talloc_free(state);
197                 return;
198         }
199
200         /* Create map tower */
201         map_binding.transport = NCACN_NP;
202         map_binding.object = state->iface->syntax_id;
203         map_binding.host = "";
204         map_binding.endpoint = "";
205
206         map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
207         if (map_tower == NULL) {
208                 talloc_free(tmp_ctx);
209                 talloc_free(state);
210                 return;
211         }
212
213         status = dcerpc_binding_build_tower(map_tower, &map_binding,
214                                             &map_tower->tower);
215         if (!NT_STATUS_IS_OK(status)) {
216                 talloc_free(tmp_ctx);
217                 talloc_free(state);
218                 return;
219         }
220
221         ok = false;
222         status = dcerpc_epm_Map(state->h,
223                                 tmp_ctx,
224                                 &object,
225                                 map_tower,
226                                 &entry_handle,
227                                 10,
228                                 &num_towers,
229                                 towers,
230                                 &result);
231         if (NT_STATUS_IS_OK(status)) {
232                 ok = true;
233         }
234         if (result == EPMAPPER_STATUS_OK ||
235             result == EPMAPPER_STATUS_NO_MORE_ENTRIES) {
236                 ok = true;
237         }
238         if (num_towers == 0) {
239                 ok = false;
240         }
241
242         dcerpc_epm_LookupHandleFree(state->h,
243                                     tmp_ctx,
244                                     &entry_handle,
245                                     &result);
246         talloc_free(tmp_ctx);
247
248         subreq = tevent_wakeup_send(state,
249                                     state->ev_ctx,
250                                     timeval_current_ofs(MONITOR_WAIT_TIME, 0));
251         if (subreq == NULL) {
252                 talloc_free(state);
253                 return;
254         }
255
256         if (ok) {
257                 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
258         } else {
259                 TALLOC_FREE(state->h);
260                 state->wait_time = 1;
261
262                 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
263         }
264
265         return;
266 }