testprogs: Set functional domain level to 2003.
[Samba.git] / source3 / rpc_server / rpc_ep_register.c
blob7e7fdd7d98a804d77bf104bd8ecd34cf2befef91
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_register_state {
39 struct dcerpc_binding_handle *h;
41 struct tevent_context *ev_ctx;
42 struct messaging_context *msg_ctx;
44 const struct ndr_interface_table *iface;
45 const struct dcerpc_binding_vector *vector;
47 uint32_t wait_time;
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)
55 struct rpc_ep_register_state *state;
56 struct tevent_req *req;
58 state = talloc(ev_ctx, struct rpc_ep_register_state);
59 if (state == NULL) {
60 return NT_STATUS_NO_MEMORY;
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;
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;
81 tevent_req_set_callback(req, rpc_ep_register_loop, state);
83 return NT_STATUS_OK;
86 #define MONITOR_WAIT_TIME 30
87 static void rpc_ep_monitor_loop(struct tevent_req *subreq);
89 static void rpc_ep_register_loop(struct tevent_req *subreq)
91 struct rpc_ep_register_state *state =
92 tevent_req_callback_data(subreq, struct rpc_ep_register_state);
93 NTSTATUS status;
94 bool ok;
96 ok = tevent_wakeup_recv(subreq);
97 TALLOC_FREE(subreq);
98 if (!ok) {
99 talloc_free(state);
100 return;
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;
119 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
120 return;
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;
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;
138 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
139 return;
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)
149 NTSTATUS status;
151 status = dcerpc_ep_register(mem_ctx,
152 msg_ctx,
153 iface,
155 &iface->syntax_id.uuid,
156 iface->name,
157 pbh);
158 if (!NT_STATUS_IS_OK(status)) {
159 return status;
162 return status;
166 * Monitor the connection to the endpoint mapper and if it goes away, try to
167 * register the endpoint.
169 static void rpc_ep_monitor_loop(struct tevent_req *subreq)
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;
184 ZERO_STRUCT(object);
185 ZERO_STRUCT(entry_handle);
187 tmp_ctx = talloc_stackframe();
188 if (tmp_ctx == NULL) {
189 talloc_free(state);
190 return;
193 ok = tevent_wakeup_recv(subreq);
194 TALLOC_FREE(subreq);
195 if (!ok) {
196 talloc_free(tmp_ctx);
197 talloc_free(state);
198 return;
201 /* Create map tower */
202 status = dcerpc_parse_binding(tmp_ctx, "ncacn_np:", &map_binding);
203 if (!NT_STATUS_IS_OK(status)) {
204 talloc_free(tmp_ctx);
205 talloc_free(state);
206 return;
209 status = dcerpc_binding_set_abstract_syntax(map_binding,
210 &state->iface->syntax_id);
211 if (!NT_STATUS_IS_OK(status)) {
212 talloc_free(tmp_ctx);
213 talloc_free(state);
214 return;
217 map_tower = talloc_zero(tmp_ctx, struct epm_twr_t);
218 if (map_tower == NULL) {
219 talloc_free(tmp_ctx);
220 talloc_free(state);
221 return;
224 status = dcerpc_binding_build_tower(map_tower, map_binding,
225 &map_tower->tower);
226 if (!NT_STATUS_IS_OK(status)) {
227 talloc_free(tmp_ctx);
228 talloc_free(state);
229 return;
232 ok = false;
233 status = dcerpc_epm_Map(state->h,
234 tmp_ctx,
235 &object,
236 map_tower,
237 &entry_handle,
239 &num_towers,
240 towers,
241 &result);
242 if (NT_STATUS_IS_OK(status)) {
243 ok = true;
245 if (result == EPMAPPER_STATUS_OK ||
246 result == EPMAPPER_STATUS_NO_MORE_ENTRIES) {
247 ok = true;
249 if (num_towers == 0) {
250 ok = false;
253 dcerpc_epm_LookupHandleFree(state->h,
254 tmp_ctx,
255 &entry_handle,
256 &result);
257 talloc_free(tmp_ctx);
259 subreq = tevent_wakeup_send(state,
260 state->ev_ctx,
261 timeval_current_ofs(MONITOR_WAIT_TIME, 0));
262 if (subreq == NULL) {
263 talloc_free(state);
264 return;
267 if (ok) {
268 tevent_req_set_callback(subreq, rpc_ep_monitor_loop, state);
269 } else {
270 TALLOC_FREE(state->h);
271 state->wait_time = 1;
273 tevent_req_set_callback(subreq, rpc_ep_register_loop, state);
276 return;