s3: RPC: Don't crash on trying to talloc_free(-1) if smb_iconv_open_ex() fails.
[Samba.git] / source3 / rpc_server / rpc_ep_register.c
blob30184f52724a3fac71b3adc80bb18ae660df6a19
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 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_RPC_SRV
33 static void rpc_ep_register_loop(struct tevent_req *subreq);
34 static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx,
35 struct tevent_context *ev_ctx,
36 struct messaging_context *msg_ctx,
37 const struct ndr_interface_table *iface,
38 const struct dcerpc_binding_vector *v,
39 struct dcerpc_binding_handle **pbh);
41 struct rpc_ep_register_state {
42 struct dcerpc_binding_handle *h;
44 struct tevent_context *ev_ctx;
45 struct messaging_context *msg_ctx;
47 const struct ndr_interface_table *iface;
48 const struct dcerpc_binding_vector *vector;
50 uint32_t wait_time;
53 NTSTATUS rpc_ep_register(struct tevent_context *ev_ctx,
54 struct messaging_context *msg_ctx,
55 const struct ndr_interface_table *iface,
56 const struct dcerpc_binding_vector *v)
58 struct rpc_ep_register_state *state;
59 struct tevent_req *req;
61 state = talloc(ev_ctx, struct rpc_ep_register_state);
62 if (state == NULL) {
63 return NT_STATUS_NO_MEMORY;
66 state->wait_time = 1;
67 state->ev_ctx = ev_ctx;
68 state->msg_ctx = msg_ctx;
69 state->iface = iface;
70 state->vector = dcerpc_binding_vector_dup(state, v);
71 if (state->vector == NULL) {
72 talloc_free(state);
73 return NT_STATUS_NO_MEMORY;
76 req = tevent_wakeup_send(state,
77 state->ev_ctx,
78 timeval_current_ofs(1, 0));
79 if (req == NULL) {
80 talloc_free(state);
81 return NT_STATUS_NO_MEMORY;
84 tevent_req_set_callback(req, rpc_ep_register_loop, state);
86 return NT_STATUS_OK;
89 #define MONITOR_WAIT_TIME 30
90 static void rpc_ep_monitor_loop(struct tevent_req *subreq);
92 static void rpc_ep_register_loop(struct tevent_req *subreq)
94 struct rpc_ep_register_state *state =
95 tevent_req_callback_data(subreq, struct rpc_ep_register_state);
96 NTSTATUS status;
97 bool ok;
99 ok = tevent_wakeup_recv(subreq);
100 TALLOC_FREE(subreq);
101 if (!ok) {
102 talloc_free(state);
103 return;
106 status = rpc_ep_try_register(state,
107 state->ev_ctx,
108 state->msg_ctx,
109 state->iface,
110 state->vector,
111 &state->h);
112 if (NT_STATUS_IS_OK(status)) {
113 /* endpoint registered, monitor the connnection. */
114 subreq = tevent_wakeup_send(state,
115 state->ev_ctx,
116 timeval_current_ofs(MONITOR_WAIT_TIME, 0));
117 if (subreq == NULL) {
118 talloc_free(state);
119 return;
122 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
123 return;
126 state->wait_time = state->wait_time * 2;
127 if (state->wait_time > 16) {
128 DEBUG(0, ("Failed to register endpoint '%s'!\n",
129 state->iface->name));
130 state->wait_time = 16;
133 subreq = tevent_wakeup_send(state,
134 state->ev_ctx,
135 timeval_current_ofs(state->wait_time, 0));
136 if (subreq == NULL) {
137 talloc_free(state);
138 return;
141 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
142 return;
145 static NTSTATUS rpc_ep_try_register(TALLOC_CTX *mem_ctx,
146 struct tevent_context *ev_ctx,
147 struct messaging_context *msg_ctx,
148 const struct ndr_interface_table *iface,
149 const struct dcerpc_binding_vector *v,
150 struct dcerpc_binding_handle **pbh)
152 NTSTATUS status;
154 status = dcerpc_ep_register(mem_ctx,
155 msg_ctx,
156 iface,
158 &iface->syntax_id.uuid,
159 iface->name,
160 pbh);
161 if (!NT_STATUS_IS_OK(status)) {
162 return status;
165 return status;
169 * Monitor the connection to the endpoint mapper and if it goes away, try to
170 * register the endpoint.
172 static void rpc_ep_monitor_loop(struct tevent_req *subreq)
174 struct rpc_ep_register_state *state =
175 tevent_req_callback_data(subreq, struct rpc_ep_register_state);
176 struct policy_handle entry_handle;
177 struct dcerpc_binding *map_binding;
178 struct epm_twr_p_t towers[10];
179 struct epm_twr_t *map_tower;
180 uint32_t num_towers = 0;
181 struct GUID object;
182 NTSTATUS status;
183 uint32_t result = EPMAPPER_STATUS_CANT_PERFORM_OP;
184 TALLOC_CTX *tmp_ctx;
185 bool ok;
187 ZERO_STRUCT(object);
188 ZERO_STRUCT(entry_handle);
190 tmp_ctx = talloc_stackframe();
191 if (tmp_ctx == NULL) {
192 talloc_free(state);
193 return;
196 ok = tevent_wakeup_recv(subreq);
197 TALLOC_FREE(subreq);
198 if (!ok) {
199 talloc_free(tmp_ctx);
200 talloc_free(state);
201 return;
204 /* Create map tower */
205 status = dcerpc_parse_binding(tmp_ctx, "ncacn_np:", &map_binding);
206 if (!NT_STATUS_IS_OK(status)) {
207 talloc_free(tmp_ctx);
208 talloc_free(state);
209 return;
212 status = dcerpc_binding_set_abstract_syntax(map_binding,
213 &state->iface->syntax_id);
214 if (!NT_STATUS_IS_OK(status)) {
215 talloc_free(tmp_ctx);
216 talloc_free(state);
217 return;
220 map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
221 if (map_tower == NULL) {
222 talloc_free(tmp_ctx);
223 talloc_free(state);
224 return;
227 status = dcerpc_binding_build_tower(map_tower, map_binding,
228 &map_tower->tower);
229 if (!NT_STATUS_IS_OK(status)) {
230 talloc_free(tmp_ctx);
231 talloc_free(state);
232 return;
235 ok = false;
236 status = dcerpc_epm_Map(state->h,
237 tmp_ctx,
238 &object,
239 map_tower,
240 &entry_handle,
242 &num_towers,
243 towers,
244 &result);
245 if (NT_STATUS_IS_OK(status)) {
246 ok = true;
248 if (result == EPMAPPER_STATUS_OK ||
249 result == EPMAPPER_STATUS_NO_MORE_ENTRIES) {
250 ok = true;
252 if (num_towers == 0) {
253 ok = false;
256 dcerpc_epm_LookupHandleFree(state->h,
257 tmp_ctx,
258 &entry_handle,
259 &result);
260 talloc_free(tmp_ctx);
262 subreq = tevent_wakeup_send(state,
263 state->ev_ctx,
264 timeval_current_ofs(MONITOR_WAIT_TIME, 0));
265 if (subreq == NULL) {
266 talloc_free(state);
267 return;
270 if (ok) {
271 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
272 } else {
273 TALLOC_FREE(state->h);
274 state->wait_time = 1;
276 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
279 return;