rpc_server: Fix a memleak on error exit
[nivanova/samba-autobuild/.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(tmp_ctx);
197                 talloc_free(state);
198                 return;
199         }
200
201         /* Create map tower */
202         map_binding.transport = NCACN_NP;
203         map_binding.object = state->iface->syntax_id;
204         map_binding.host = "";
205         map_binding.endpoint = "";
206
207         map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
208         if (map_tower == NULL) {
209                 talloc_free(tmp_ctx);
210                 talloc_free(state);
211                 return;
212         }
213
214         status = dcerpc_binding_build_tower(map_tower, &map_binding,
215                                             &map_tower->tower);
216         if (!NT_STATUS_IS_OK(status)) {
217                 talloc_free(tmp_ctx);
218                 talloc_free(state);
219                 return;
220         }
221
222         ok = false;
223         status = dcerpc_epm_Map(state->h,
224                                 tmp_ctx,
225                                 &object,
226                                 map_tower,
227                                 &entry_handle,
228                                 10,
229                                 &num_towers,
230                                 towers,
231                                 &result);
232         if (NT_STATUS_IS_OK(status)) {
233                 ok = true;
234         }
235         if (result == EPMAPPER_STATUS_OK ||
236             result == EPMAPPER_STATUS_NO_MORE_ENTRIES) {
237                 ok = true;
238         }
239         if (num_towers == 0) {
240                 ok = false;
241         }
242
243         dcerpc_epm_LookupHandleFree(state->h,
244                                     tmp_ctx,
245                                     &entry_handle,
246                                     &result);
247         talloc_free(tmp_ctx);
248
249         subreq = tevent_wakeup_send(state,
250                                     state->ev_ctx,
251                                     timeval_current_ofs(MONITOR_WAIT_TIME, 0));
252         if (subreq == NULL) {
253                 talloc_free(state);
254                 return;
255         }
256
257         if (ok) {
258                 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
259         } else {
260                 TALLOC_FREE(state->h);
261                 state->wait_time = 1;
262
263                 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
264         }
265
266         return;
267 }