smbd: Simplify callers of notify_filter_string
[Samba.git] / source3 / libads / cldap.c
blob56c2537ffa985d736dbe8129078932b642bc585a
1 /*
2 Samba Unix/Linux SMB client library
3 net ads cldap functions
4 Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
5 Copyright (C) 2003 Jim McDonough (jmcd@us.ibm.com)
6 Copyright (C) 2008 Guenther Deschner (gd@samba.org)
7 Copyright (C) 2009 Stefan Metzmacher (metze@samba.org)
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "../libcli/cldap/cldap.h"
25 #include "../librpc/gen_ndr/ndr_netlogon.h"
26 #include "../lib/tsocket/tsocket.h"
27 #include "../lib/util/tevent_ntstatus.h"
28 #include "libads/cldap.h"
30 struct cldap_multi_netlogon_state {
31 struct tevent_context *ev;
32 const struct tsocket_address * const *servers;
33 int num_servers;
34 const char *domain;
35 const char *hostname;
36 unsigned ntversion;
37 int min_servers;
39 struct cldap_socket **cldap;
40 struct tevent_req **subreqs;
41 int num_sent;
42 int num_received;
43 int num_good_received;
44 struct cldap_netlogon *ios;
45 struct netlogon_samlogon_response **responses;
48 static void cldap_multi_netlogon_done(struct tevent_req *subreq);
49 static void cldap_multi_netlogon_next(struct tevent_req *subreq);
51 /****************************************************************
52 ****************************************************************/
54 #define RETURN_ON_FALSE(x) if (!(x)) return false;
56 bool check_cldap_reply_required_flags(uint32_t ret_flags,
57 uint32_t req_flags)
59 if (req_flags == 0) {
60 return true;
63 if (req_flags & DS_PDC_REQUIRED)
64 RETURN_ON_FALSE(ret_flags & NBT_SERVER_PDC);
66 if (req_flags & DS_GC_SERVER_REQUIRED)
67 RETURN_ON_FALSE(ret_flags & NBT_SERVER_GC);
69 if (req_flags & DS_ONLY_LDAP_NEEDED)
70 RETURN_ON_FALSE(ret_flags & NBT_SERVER_LDAP);
72 if ((req_flags & DS_DIRECTORY_SERVICE_REQUIRED) ||
73 (req_flags & DS_DIRECTORY_SERVICE_PREFERRED))
74 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS);
76 if (req_flags & DS_KDC_REQUIRED)
77 RETURN_ON_FALSE(ret_flags & NBT_SERVER_KDC);
79 if (req_flags & DS_TIMESERV_REQUIRED)
80 RETURN_ON_FALSE(ret_flags & NBT_SERVER_TIMESERV);
82 if (req_flags & DS_WEB_SERVICE_REQUIRED)
83 RETURN_ON_FALSE(ret_flags & NBT_SERVER_ADS_WEB_SERVICE);
85 if (req_flags & DS_WRITABLE_REQUIRED)
86 RETURN_ON_FALSE(ret_flags & NBT_SERVER_WRITABLE);
88 if (req_flags & DS_DIRECTORY_SERVICE_6_REQUIRED)
89 RETURN_ON_FALSE(ret_flags & (NBT_SERVER_SELECT_SECRET_DOMAIN_6
90 |NBT_SERVER_FULL_SECRET_DOMAIN_6));
92 if (req_flags & DS_DIRECTORY_SERVICE_8_REQUIRED)
93 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_8);
95 if (req_flags & DS_DIRECTORY_SERVICE_9_REQUIRED)
96 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_9);
98 if (req_flags & DS_DIRECTORY_SERVICE_10_REQUIRED)
99 RETURN_ON_FALSE(ret_flags & NBT_SERVER_DS_10);
101 return true;
105 * Do a parallel cldap ping to the servers. The first "min_servers"
106 * are fired directly, the remaining ones in 100msec intervals. If
107 * "min_servers" responses came in successfully, we immediately reply,
108 * not waiting for the remaining ones.
111 struct tevent_req *cldap_multi_netlogon_send(
112 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
113 const struct tsocket_address * const *servers, int num_servers,
114 const char *domain, const char *hostname, unsigned ntversion,
115 int min_servers)
117 struct tevent_req *req, *subreq;
118 struct cldap_multi_netlogon_state *state;
119 int i;
121 req = tevent_req_create(mem_ctx, &state,
122 struct cldap_multi_netlogon_state);
123 if (req == NULL) {
124 return NULL;
126 state->ev = ev;
127 state->servers = servers;
128 state->num_servers = num_servers;
129 state->domain = domain;
130 state->hostname = hostname;
131 state->ntversion = ntversion;
132 state->min_servers = min_servers;
134 if (min_servers > num_servers) {
135 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
136 return tevent_req_post(req, ev);
139 state->subreqs = talloc_zero_array(state,
140 struct tevent_req *,
141 num_servers);
142 if (tevent_req_nomem(state->subreqs, req)) {
143 return tevent_req_post(req, ev);
146 state->cldap = talloc_zero_array(state,
147 struct cldap_socket *,
148 num_servers);
149 if (tevent_req_nomem(state->cldap, req)) {
150 return tevent_req_post(req, ev);
153 state->responses = talloc_zero_array(state,
154 struct netlogon_samlogon_response *,
155 num_servers);
156 if (tevent_req_nomem(state->responses, req)) {
157 return tevent_req_post(req, ev);
160 state->ios = talloc_zero_array(state->responses,
161 struct cldap_netlogon,
162 num_servers);
163 if (tevent_req_nomem(state->ios, req)) {
164 return tevent_req_post(req, ev);
167 for (i=0; i<num_servers; i++) {
168 NTSTATUS status;
170 status = cldap_socket_init(state->cldap,
171 NULL, /* local_addr */
172 state->servers[i],
173 &state->cldap[i]);
174 if (!NT_STATUS_IS_OK(status)) {
176 * Don't error out all sends just
177 * because one cldap_socket_init() failed.
178 * Log it here, and the cldap_netlogon_send()
179 * will catch it (with in.dest_address == NULL)
180 * and correctly error out in
181 * cldap_multi_netlogon_done(). This still allows
182 * the other requests to be concurrently sent.
184 DBG_NOTICE("cldap_socket_init failed for %s "
185 " error %s\n",
186 tsocket_address_string(state->servers[i],
187 req),
188 nt_errstr(status));
191 state->ios[i].in.dest_address = NULL;
192 state->ios[i].in.dest_port = 0;
193 state->ios[i].in.realm = domain;
194 state->ios[i].in.host = NULL;
195 state->ios[i].in.user = NULL;
196 state->ios[i].in.domain_guid = NULL;
197 state->ios[i].in.domain_sid = NULL;
198 state->ios[i].in.acct_control = 0;
199 state->ios[i].in.version = ntversion;
200 state->ios[i].in.map_response = false;
203 for (i=0; i<min_servers; i++) {
204 state->subreqs[i] = cldap_netlogon_send(state->subreqs,
205 state->ev,
206 state->cldap[i],
207 &state->ios[i]);
208 if (tevent_req_nomem(state->subreqs[i], req)) {
209 return tevent_req_post(req, ev);
211 tevent_req_set_callback(
212 state->subreqs[i], cldap_multi_netlogon_done, req);
214 state->num_sent = min_servers;
216 if (state->num_sent < state->num_servers) {
218 * After 100 milliseconds fire the next one
220 subreq = tevent_wakeup_send(state, state->ev,
221 timeval_current_ofs(0, 100000));
222 if (tevent_req_nomem(subreq, req)) {
223 return tevent_req_post(req, ev);
225 tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
226 req);
229 return req;
232 static void cldap_multi_netlogon_done(struct tevent_req *subreq)
234 struct tevent_req *req = tevent_req_callback_data(
235 subreq, struct tevent_req);
236 struct cldap_multi_netlogon_state *state = tevent_req_data(
237 req, struct cldap_multi_netlogon_state);
238 NTSTATUS status;
239 struct netlogon_samlogon_response *response;
240 int i;
242 for (i=0; i<state->num_sent; i++) {
243 if (state->subreqs[i] == subreq) {
244 break;
247 if (i == state->num_sent) {
249 * Got a response we did not fire...
251 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
252 return;
254 state->subreqs[i] = NULL;
256 response = talloc_zero(state, struct netlogon_samlogon_response);
257 if (tevent_req_nomem(response, req)) {
258 return;
261 status = cldap_netlogon_recv(subreq, response,
262 &state->ios[i]);
263 TALLOC_FREE(subreq);
264 state->num_received += 1;
266 if (NT_STATUS_IS_OK(status)) {
267 *response = state->ios[i].out.netlogon;
268 state->responses[i] = talloc_move(state->responses,
269 &response);
270 state->num_good_received += 1;
273 if ((state->num_received == state->num_servers) ||
274 (state->num_good_received >= state->min_servers)) {
275 tevent_req_done(req);
276 return;
280 static void cldap_multi_netlogon_next(struct tevent_req *subreq)
282 struct tevent_req *req = tevent_req_callback_data(
283 subreq, struct tevent_req);
284 struct cldap_multi_netlogon_state *state = tevent_req_data(
285 req, struct cldap_multi_netlogon_state);
286 bool ret;
288 ret = tevent_wakeup_recv(subreq);
289 TALLOC_FREE(subreq);
290 if (!ret) {
291 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
292 return;
295 subreq = cldap_netlogon_send(state->subreqs,
296 state->ev,
297 state->cldap[state->num_sent],
298 &state->ios[state->num_sent]);
299 if (tevent_req_nomem(subreq, req)) {
300 return;
302 tevent_req_set_callback(subreq, cldap_multi_netlogon_done, req);
303 state->subreqs[state->num_sent] = subreq;
304 state->num_sent += 1;
306 if (state->num_sent < state->num_servers) {
308 * After 100 milliseconds fire the next one
310 subreq = tevent_wakeup_send(state, state->ev,
311 timeval_current_ofs(0, 100000));
312 if (tevent_req_nomem(subreq, req)) {
313 return;
315 tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
316 req);
320 NTSTATUS cldap_multi_netlogon_recv(
321 struct tevent_req *req, TALLOC_CTX *mem_ctx,
322 struct netlogon_samlogon_response ***responses)
324 struct cldap_multi_netlogon_state *state = tevent_req_data(
325 req, struct cldap_multi_netlogon_state);
326 NTSTATUS status;
328 if (tevent_req_is_nterror(req, &status) &&
329 !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
330 return status;
333 * If we timeout, give back what we have so far
335 *responses = talloc_move(mem_ctx, &state->responses);
336 return NT_STATUS_OK;
339 NTSTATUS cldap_multi_netlogon(
340 TALLOC_CTX *mem_ctx,
341 const struct tsocket_address * const *servers,
342 int num_servers,
343 const char *domain, const char *hostname, unsigned ntversion,
344 int min_servers, struct timeval timeout,
345 struct netlogon_samlogon_response ***responses)
347 struct tevent_context *ev;
348 struct tevent_req *req;
349 NTSTATUS status = NT_STATUS_NO_MEMORY;
351 ev = samba_tevent_context_init(talloc_tos());
352 if (ev == NULL) {
353 goto fail;
355 req = cldap_multi_netlogon_send(
356 ev, ev, servers, num_servers, domain, hostname, ntversion,
357 min_servers);
358 if (req == NULL) {
359 goto fail;
361 if (!tevent_req_set_endtime(req, ev, timeout)) {
362 goto fail;
364 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
365 goto fail;
367 status = cldap_multi_netlogon_recv(req, mem_ctx, responses);
368 fail:
369 TALLOC_FREE(ev);
370 return status;
373 /*******************************************************************
374 do a cldap netlogon query. Always 389/udp
375 *******************************************************************/
377 bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
378 struct sockaddr_storage *ss,
379 const char *realm,
380 uint32_t nt_version,
381 struct netlogon_samlogon_response **_reply)
383 NTSTATUS status;
384 char addrstr[INET6_ADDRSTRLEN];
385 const char *dest_str;
386 struct tsocket_address *dest_addr;
387 const struct tsocket_address * const *dest_addrs;
388 struct netlogon_samlogon_response **responses = NULL;
389 int ret;
391 dest_str = print_sockaddr(addrstr, sizeof(addrstr), ss);
393 ret = tsocket_address_inet_from_strings(mem_ctx, "ip",
394 dest_str, LDAP_PORT,
395 &dest_addr);
396 if (ret != 0) {
397 status = map_nt_error_from_unix(errno);
398 DEBUG(2,("Failed to create cldap tsocket_address for %s - %s\n",
399 dest_str, nt_errstr(status)));
400 return false;
403 dest_addrs = (const struct tsocket_address * const *)&dest_addr;
405 status = cldap_multi_netlogon(talloc_tos(),
406 dest_addrs, 1,
407 realm, NULL,
408 nt_version, 1,
409 timeval_current_ofs(MAX(3,lp_ldap_timeout()/2), 0),
410 &responses);
411 if (!NT_STATUS_IS_OK(status)) {
412 DEBUG(2, ("ads_cldap_netlogon: cldap_multi_netlogon "
413 "failed: %s\n", nt_errstr(status)));
414 return false;
416 if (responses == NULL || responses[0] == NULL) {
417 DEBUG(2, ("ads_cldap_netlogon: did not get a reply\n"));
418 TALLOC_FREE(responses);
419 return false;
421 *_reply = talloc_move(mem_ctx, &responses[0]);
423 return true;
426 /*******************************************************************
427 do a cldap netlogon query. Always 389/udp
428 *******************************************************************/
430 bool ads_cldap_netlogon_5(TALLOC_CTX *mem_ctx,
431 struct sockaddr_storage *ss,
432 const char *realm,
433 struct NETLOGON_SAM_LOGON_RESPONSE_EX *reply5)
435 uint32_t nt_version = NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX;
436 struct netlogon_samlogon_response *reply = NULL;
437 bool ret;
439 ret = ads_cldap_netlogon(mem_ctx, ss, realm, nt_version, &reply);
440 if (!ret) {
441 return false;
444 if (reply->ntver != NETLOGON_NT_VERSION_5EX) {
445 DEBUG(0,("ads_cldap_netlogon_5: nt_version mismatch: 0x%08x\n",
446 reply->ntver));
447 return false;
450 *reply5 = reply->data.nt5_ex;
452 return true;