Line data Source code
1 : /*
2 : Authors:
3 : Pavel Březina <pbrezina@redhat.com>
4 :
5 : Copyright (C) 2013 Red Hat
6 :
7 : This program is free software; you can redistribute it and/or modify
8 : it under the terms of the GNU General Public License as published by
9 : the Free Software Foundation; either version 3 of the License, or
10 : (at your option) any later version.
11 :
12 : This program is distributed in the hope that it will be useful,
13 : but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : GNU General Public License for more details.
16 :
17 : You should have received a copy of the GNU General Public License
18 : along with this program. If not, see <http://www.gnu.org/licenses/>.
19 : */
20 :
21 : #include <string.h>
22 : #include <talloc.h>
23 : #include <tevent.h>
24 : #include <ndr.h>
25 : #include <ndr/ndr_nbt.h>
26 :
27 : #include "util/util.h"
28 : #include "util/sss_ldap.h"
29 : #include "resolv/async_resolv.h"
30 : #include "providers/dp_backend.h"
31 : #include "providers/ad/ad_srv.h"
32 : #include "providers/ad/ad_common.h"
33 : #include "providers/fail_over.h"
34 : #include "providers/fail_over_srv.h"
35 : #include "providers/ldap/sdap.h"
36 : #include "providers/ldap/sdap_async.h"
37 :
38 : #define AD_SITE_DOMAIN_FMT "%s._sites.%s"
39 :
40 0 : static errno_t ad_sort_servers_by_dns(TALLOC_CTX *mem_ctx,
41 : const char *domain,
42 : struct fo_server_info **_srv,
43 : size_t num)
44 0 : {
45 0 : struct fo_server_info *out = NULL;
46 0 : struct fo_server_info *srv = NULL;
47 0 : struct fo_server_info in_domain[num];
48 0 : struct fo_server_info out_domain[num];
49 0 : size_t srv_index = 0;
50 0 : size_t in_index = 0;
51 0 : size_t out_index = 0;
52 : size_t i, j;
53 :
54 0 : if (_srv == NULL) {
55 0 : return EINVAL;
56 : }
57 :
58 0 : srv = *_srv;
59 :
60 0 : if (num <= 1) {
61 0 : return EOK;
62 : }
63 :
64 0 : out = talloc_zero_array(mem_ctx, struct fo_server_info, num);
65 0 : if (out == NULL) {
66 0 : return ENOMEM;
67 : }
68 :
69 : /* When several servers share priority, we will prefer the one that
70 : * is located in the same domain as client (e.g. child domain instead
71 : * of forest root) but obey their weight. We will use the fact that
72 : * the servers are already sorted by priority. */
73 :
74 0 : for (i = 0; i < num; i++) {
75 0 : if (is_host_in_domain(srv[i].host, domain)) {
76 : /* this is a preferred server, push it to the in domain list */
77 0 : in_domain[in_index] = srv[i];
78 0 : in_index++;
79 : } else {
80 : /* this is a normal server, push it to the out domain list */
81 0 : out_domain[out_index] = srv[i];
82 0 : out_index++;
83 : }
84 :
85 0 : if (i + 1 == num || srv[i].priority != srv[i + 1].priority) {
86 : /* priority has changed or we have reached the end of the srv list,
87 : * we will merge the list into final list and start over with
88 : * next priority */
89 0 : for (j = 0; j < in_index; j++) {
90 0 : out[srv_index] = in_domain[j];
91 0 : talloc_steal(out, out[srv_index].host);
92 0 : srv_index++;
93 : }
94 :
95 0 : for (j = 0; j < out_index; j++) {
96 0 : out[srv_index] = out_domain[j];
97 0 : talloc_steal(out, out[srv_index].host);
98 0 : srv_index++;
99 : }
100 :
101 0 : in_index = 0;
102 0 : out_index = 0;
103 : }
104 : }
105 :
106 0 : talloc_free(*_srv);
107 0 : *_srv = out;
108 0 : return EOK;
109 : }
110 :
111 : struct ad_get_dc_servers_state {
112 : struct fo_server_info *servers;
113 : size_t num_servers;
114 : };
115 :
116 : static void ad_get_dc_servers_done(struct tevent_req *subreq);
117 :
118 0 : static struct tevent_req *ad_get_dc_servers_send(TALLOC_CTX *mem_ctx,
119 : struct tevent_context *ev,
120 : struct resolv_ctx *resolv_ctx,
121 : const char *domain)
122 : {
123 0 : struct ad_get_dc_servers_state *state = NULL;
124 0 : struct tevent_req *req = NULL;
125 0 : struct tevent_req *subreq = NULL;
126 0 : const char **domains = NULL;
127 : errno_t ret;
128 :
129 0 : req = tevent_req_create(mem_ctx, &state,
130 : struct ad_get_dc_servers_state);
131 0 : if (req == NULL) {
132 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
133 0 : return NULL;
134 : }
135 :
136 0 : domains = talloc_zero_array(state, const char *, 2);
137 0 : if (domains == NULL) {
138 0 : ret = ENOMEM;
139 0 : goto immediately;
140 : }
141 :
142 0 : domains[0] = talloc_strdup(domains, domain);
143 0 : if (domains[0] == NULL) {
144 0 : ret = ENOMEM;
145 0 : goto immediately;
146 : }
147 :
148 0 : DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain %s\n",
149 : domain);
150 :
151 0 : subreq = fo_discover_srv_send(state, ev, resolv_ctx,
152 : "ldap", FO_PROTO_TCP, domains);
153 0 : if (subreq == NULL) {
154 0 : ret = ENOMEM;
155 0 : goto immediately;
156 : }
157 :
158 0 : tevent_req_set_callback(subreq, ad_get_dc_servers_done, req);
159 :
160 0 : return req;
161 :
162 : immediately:
163 0 : tevent_req_error(req, ret);
164 0 : tevent_req_post(req, ev);
165 :
166 0 : return req;
167 : }
168 :
169 0 : static void ad_get_dc_servers_done(struct tevent_req *subreq)
170 : {
171 0 : struct ad_get_dc_servers_state *state = NULL;
172 0 : struct tevent_req *req = NULL;
173 0 : char *domain = NULL;
174 : errno_t ret;
175 :
176 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
177 0 : state = tevent_req_data(req, struct ad_get_dc_servers_state);
178 :
179 0 : ret = fo_discover_srv_recv(state, subreq, &domain, NULL,
180 : &state->servers, &state->num_servers);
181 0 : talloc_zfree(subreq);
182 0 : if (ret != EOK) {
183 0 : goto done;
184 : }
185 :
186 0 : DEBUG(SSSDBG_TRACE_FUNC, "Found %zu domain controllers in domain %s\n",
187 : state->num_servers, domain);
188 :
189 : done:
190 0 : if (ret != EOK) {
191 0 : tevent_req_error(req, ret);
192 0 : return;
193 : }
194 :
195 0 : tevent_req_done(req);
196 : }
197 :
198 0 : static int ad_get_dc_servers_recv(TALLOC_CTX *mem_ctx,
199 : struct tevent_req *req,
200 : struct fo_server_info **_dcs,
201 : size_t *_num_dcs)
202 : {
203 0 : struct ad_get_dc_servers_state *state = NULL;
204 0 : state = tevent_req_data(req, struct ad_get_dc_servers_state);
205 :
206 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
207 :
208 0 : *_dcs = talloc_steal(mem_ctx, state->servers);
209 0 : *_num_dcs = state->num_servers;
210 :
211 0 : return EOK;
212 : }
213 :
214 : struct ad_get_client_site_state {
215 : struct tevent_context *ev;
216 : struct be_resolv_ctx *be_res;
217 : enum host_database *host_db;
218 : struct sdap_options *opts;
219 : const char *ad_domain;
220 : struct fo_server_info *dcs;
221 : size_t num_dcs;
222 : size_t dc_index;
223 : struct fo_server_info dc;
224 :
225 : struct sdap_handle *sh;
226 : char *site;
227 : char *forest;
228 : };
229 :
230 : static errno_t ad_get_client_site_next_dc(struct tevent_req *req);
231 : static void ad_get_client_site_connect_done(struct tevent_req *subreq);
232 : static void ad_get_client_site_done(struct tevent_req *subreq);
233 :
234 0 : struct tevent_req *ad_get_client_site_send(TALLOC_CTX *mem_ctx,
235 : struct tevent_context *ev,
236 : struct be_resolv_ctx *be_res,
237 : enum host_database *host_db,
238 : struct sdap_options *opts,
239 : const char *ad_domain,
240 : struct fo_server_info *dcs,
241 : size_t num_dcs)
242 : {
243 0 : struct ad_get_client_site_state *state = NULL;
244 0 : struct tevent_req *req = NULL;
245 : errno_t ret;
246 :
247 0 : req = tevent_req_create(mem_ctx, &state,
248 : struct ad_get_client_site_state);
249 0 : if (req == NULL) {
250 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
251 0 : return NULL;
252 : }
253 :
254 0 : if (be_res == NULL || host_db == NULL || opts == NULL) {
255 0 : ret = EINVAL;
256 0 : goto immediately;
257 : }
258 :
259 0 : state->ev = ev;
260 0 : state->be_res = be_res;
261 0 : state->host_db = host_db;
262 0 : state->opts = opts;
263 0 : state->ad_domain = ad_domain;
264 0 : state->dcs = dcs;
265 0 : state->num_dcs = num_dcs;
266 :
267 0 : state->dc_index = 0;
268 0 : ret = ad_get_client_site_next_dc(req);
269 0 : if (ret == EOK) {
270 0 : ret = ENOENT;
271 0 : goto immediately;
272 0 : } else if (ret != EAGAIN) {
273 0 : goto immediately;
274 : }
275 :
276 0 : return req;
277 :
278 : immediately:
279 0 : if (ret == EOK) {
280 0 : tevent_req_done(req);
281 : } else {
282 0 : tevent_req_error(req, ret);
283 : }
284 0 : tevent_req_post(req, ev);
285 :
286 0 : return req;
287 : }
288 :
289 0 : static errno_t ad_get_client_site_next_dc(struct tevent_req *req)
290 : {
291 0 : struct ad_get_client_site_state *state = NULL;
292 0 : struct tevent_req *subreq = NULL;
293 : errno_t ret;
294 :
295 0 : state = tevent_req_data(req, struct ad_get_client_site_state);
296 :
297 0 : if (state->dc_index >= state->num_dcs) {
298 0 : ret = EOK;
299 0 : goto done;
300 : }
301 :
302 0 : state->dc = state->dcs[state->dc_index];
303 :
304 0 : subreq = sdap_connect_host_send(state, state->ev, state->opts,
305 0 : state->be_res->resolv,
306 0 : state->be_res->family_order,
307 0 : state->host_db, "ldap", state->dc.host,
308 : state->dc.port, false);
309 0 : if (subreq == NULL) {
310 0 : ret = ENOMEM;
311 0 : goto done;
312 : }
313 :
314 0 : tevent_req_set_callback(subreq, ad_get_client_site_connect_done, req);
315 :
316 0 : state->dc_index++;
317 0 : ret = EAGAIN;
318 :
319 : done:
320 0 : return ret;
321 : }
322 :
323 0 : static void ad_get_client_site_connect_done(struct tevent_req *subreq)
324 : {
325 0 : struct ad_get_client_site_state *state = NULL;
326 0 : struct tevent_req *req = NULL;
327 : static const char *attrs[] = {AD_AT_NETLOGON, NULL};
328 0 : char *filter = NULL;
329 0 : char *ntver = NULL;
330 : errno_t ret;
331 :
332 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
333 0 : state = tevent_req_data(req, struct ad_get_client_site_state);
334 :
335 0 : ret = sdap_connect_host_recv(state, subreq, &state->sh);
336 0 : talloc_zfree(subreq);
337 0 : if (ret != EOK) {
338 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unable to connect to domain controller "
339 : "[%s:%d]\n", state->dc.host, state->dc.port);
340 :
341 0 : ret = ad_get_client_site_next_dc(req);
342 0 : if (ret == EOK) {
343 0 : ret = ENOENT;
344 : }
345 :
346 0 : goto done;
347 : }
348 :
349 0 : ntver = sss_ldap_encode_ndr_uint32(state, NETLOGON_NT_VERSION_5EX |
350 : NETLOGON_NT_VERSION_WITH_CLOSEST_SITE);
351 0 : if (ntver == NULL) {
352 0 : ret = ENOMEM;
353 0 : goto done;
354 : }
355 :
356 0 : filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))",
357 : AD_AT_DNS_DOMAIN, state->ad_domain,
358 : AD_AT_NT_VERSION, ntver);
359 0 : if (filter == NULL) {
360 0 : ret = ENOMEM;
361 0 : goto done;
362 : }
363 :
364 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
365 : "", LDAP_SCOPE_BASE, filter,
366 : attrs, NULL, 0,
367 0 : dp_opt_get_int(state->opts->basic,
368 : SDAP_SEARCH_TIMEOUT),
369 : false);
370 0 : if (subreq == NULL) {
371 0 : ret = ENOMEM;
372 0 : goto done;
373 : }
374 :
375 0 : tevent_req_set_callback(subreq, ad_get_client_site_done, req);
376 :
377 0 : ret = EAGAIN;
378 :
379 : done:
380 0 : if (ret == EOK) {
381 0 : tevent_req_done(req);
382 0 : } else if (ret != EAGAIN) {
383 0 : tevent_req_error(req, ret);
384 : }
385 :
386 0 : return;
387 : }
388 :
389 0 : static errno_t ad_get_client_site_parse_ndr(TALLOC_CTX *mem_ctx,
390 : uint8_t *data,
391 : size_t length,
392 : char **_site_name,
393 : char **_forest_name)
394 : {
395 0 : TALLOC_CTX *tmp_ctx = NULL;
396 0 : struct ndr_pull *ndr_pull = NULL;
397 : struct netlogon_samlogon_response response;
398 : enum ndr_err_code ndr_err;
399 0 : char *site = NULL;
400 0 : char *forest = NULL;
401 : DATA_BLOB blob;
402 : errno_t ret;
403 :
404 0 : tmp_ctx = talloc_new(NULL);
405 0 : if (tmp_ctx == NULL) {
406 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
407 0 : return ENOMEM;
408 : }
409 :
410 0 : blob.data = data;
411 0 : blob.length = length;
412 :
413 0 : ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
414 0 : if (ndr_pull == NULL) {
415 0 : DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob() failed.\n");
416 0 : ret = ENOMEM;
417 0 : goto done;
418 : }
419 :
420 0 : ndr_err = ndr_pull_netlogon_samlogon_response(ndr_pull, NDR_SCALARS,
421 : &response);
422 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
423 0 : DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_netlogon_samlogon_response() "
424 : "failed [%d]\n", ndr_err);
425 0 : ret = EBADMSG;
426 0 : goto done;
427 : }
428 :
429 0 : if (!(response.ntver & NETLOGON_NT_VERSION_5EX)) {
430 0 : DEBUG(SSSDBG_OP_FAILURE, "This NT version does not provide site "
431 : "information [%x]\n", response.ntver);
432 0 : ret = EBADMSG;
433 0 : goto done;
434 : }
435 :
436 0 : if (response.data.nt5_ex.client_site != NULL
437 0 : && response.data.nt5_ex.client_site[0] != '\0') {
438 0 : site = talloc_strdup(tmp_ctx, response.data.nt5_ex.client_site);
439 0 : } else if (response.data.nt5_ex.next_closest_site != NULL
440 0 : && response.data.nt5_ex.next_closest_site[0] != '\0') {
441 0 : site = talloc_strdup(tmp_ctx, response.data.nt5_ex.next_closest_site);
442 : } else {
443 0 : ret = ENOENT;
444 0 : goto done;
445 : }
446 :
447 0 : if (response.data.nt5_ex.forest != NULL
448 0 : && response.data.nt5_ex.forest[0] != '\0') {
449 0 : forest = talloc_strdup(tmp_ctx, response.data.nt5_ex.forest);
450 : } else {
451 0 : ret = ENOENT;
452 0 : goto done;
453 : }
454 :
455 :
456 0 : if (site == NULL || forest == NULL) {
457 0 : ret = ENOMEM;
458 0 : goto done;
459 : }
460 :
461 0 : *_site_name = talloc_steal(mem_ctx, site);
462 0 : *_forest_name = talloc_steal(mem_ctx, forest);
463 :
464 0 : ret = EOK;
465 :
466 : done:
467 0 : talloc_free(tmp_ctx);
468 0 : return ret;
469 : }
470 :
471 0 : static void ad_get_client_site_done(struct tevent_req *subreq)
472 : {
473 0 : struct ad_get_client_site_state *state = NULL;
474 0 : struct tevent_req *req = NULL;
475 0 : struct ldb_message_element *el = NULL;
476 0 : struct sysdb_attrs **reply = NULL;
477 : size_t reply_count;
478 : errno_t ret;
479 :
480 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
481 0 : state = tevent_req_data(req, struct ad_get_client_site_state);
482 :
483 0 : ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
484 0 : talloc_zfree(subreq);
485 :
486 : /* we're done with this LDAP, close connection */
487 0 : talloc_zfree(state->sh);
488 0 : if (ret != EOK) {
489 0 : DEBUG(SSSDBG_OP_FAILURE, "Unable to get netlogon information\n");
490 :
491 0 : ret = ad_get_client_site_next_dc(req);
492 0 : if (ret == EOK) {
493 0 : ret = ENOENT;
494 : }
495 0 : goto done;
496 : }
497 :
498 0 : if (reply_count == 0) {
499 0 : DEBUG(SSSDBG_OP_FAILURE, "No netlogon information retrieved\n");
500 0 : ret = ENOENT;
501 0 : goto done;
502 : }
503 :
504 0 : ret = sysdb_attrs_get_el(reply[0], AD_AT_NETLOGON, &el);
505 0 : if (ret != EOK) {
506 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
507 0 : goto done;
508 : }
509 :
510 0 : if (el->num_values == 0) {
511 0 : DEBUG(SSSDBG_OP_FAILURE, "netlogon has no value\n");
512 0 : ret = ENOENT;
513 0 : goto done;
514 0 : } else if (el->num_values > 1) {
515 0 : DEBUG(SSSDBG_OP_FAILURE, "More than one netlogon value?\n");
516 0 : ret = EIO;
517 0 : goto done;
518 : }
519 :
520 0 : ret = ad_get_client_site_parse_ndr(state, el->values[0].data,
521 0 : el->values[0].length, &state->site,
522 : &state->forest);
523 0 : if (ret != EOK) {
524 0 : DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve site name [%d]: %s\n",
525 : ret, strerror(ret));
526 0 : ret = ENOENT;
527 0 : goto done;
528 : }
529 :
530 0 : DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site);
531 :
532 : done:
533 0 : if (ret != EOK) {
534 0 : tevent_req_error(req, ret);
535 0 : return;
536 : }
537 :
538 0 : tevent_req_done(req);
539 : }
540 :
541 0 : int ad_get_client_site_recv(TALLOC_CTX *mem_ctx,
542 : struct tevent_req *req,
543 : const char **_site,
544 : const char **_forest)
545 : {
546 0 : struct ad_get_client_site_state *state = NULL;
547 0 : state = tevent_req_data(req, struct ad_get_client_site_state);
548 :
549 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
550 :
551 0 : *_site = talloc_steal(mem_ctx, state->site);
552 0 : *_forest = talloc_steal(mem_ctx, state->forest);
553 :
554 0 : return EOK;
555 : }
556 :
557 : struct ad_srv_plugin_ctx {
558 : struct be_resolv_ctx *be_res;
559 : enum host_database *host_dbs;
560 : struct sdap_options *opts;
561 : const char *hostname;
562 : const char *ad_domain;
563 : const char *ad_site_override;
564 : };
565 :
566 : struct ad_srv_plugin_ctx *
567 12 : ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
568 : struct be_resolv_ctx *be_res,
569 : enum host_database *host_dbs,
570 : struct sdap_options *opts,
571 : const char *hostname,
572 : const char *ad_domain,
573 : const char *ad_site_override)
574 : {
575 12 : struct ad_srv_plugin_ctx *ctx = NULL;
576 :
577 12 : ctx = talloc_zero(mem_ctx, struct ad_srv_plugin_ctx);
578 12 : if (ctx == NULL) {
579 0 : return NULL;
580 : }
581 :
582 12 : ctx->be_res = be_res;
583 12 : ctx->host_dbs = host_dbs;
584 12 : ctx->opts = opts;
585 :
586 12 : ctx->hostname = talloc_strdup(ctx, hostname);
587 12 : if (ctx->hostname == NULL) {
588 0 : goto fail;
589 : }
590 :
591 12 : ctx->ad_domain = talloc_strdup(ctx, ad_domain);
592 12 : if (ctx->ad_domain == NULL) {
593 0 : goto fail;
594 : }
595 :
596 12 : if (ad_site_override != NULL) {
597 0 : ctx->ad_site_override = talloc_strdup(ctx, ad_site_override);
598 0 : if (ctx->ad_site_override == NULL) {
599 0 : goto fail;
600 : }
601 : }
602 :
603 12 : return ctx;
604 :
605 : fail:
606 0 : talloc_free(ctx);
607 0 : return NULL;
608 : }
609 :
610 : struct ad_srv_plugin_state {
611 : struct tevent_context *ev;
612 : struct ad_srv_plugin_ctx *ctx;
613 : const char *service;
614 : const char *protocol;
615 : const char *discovery_domain;
616 :
617 : const char *site;
618 : char *dns_domain;
619 : uint32_t ttl;
620 : const char *forest;
621 : struct fo_server_info *primary_servers;
622 : size_t num_primary_servers;
623 : struct fo_server_info *backup_servers;
624 : size_t num_backup_servers;
625 : };
626 :
627 : static void ad_srv_plugin_dcs_done(struct tevent_req *subreq);
628 : static void ad_srv_plugin_site_done(struct tevent_req *subreq);
629 : static void ad_srv_plugin_servers_done(struct tevent_req *subreq);
630 :
631 : /* 1. Do a DNS lookup to find any DC in domain
632 : * _ldap._tcp.domain.name
633 : * 2. Send a CLDAP ping to the found DC to get the desirable site
634 : * 3. Do a DNS lookup to find SRV in the site (a)
635 : * _service._protocol.site-name._sites.domain.name
636 : * 4. Do a DNS lookup to find global SRV records (b)
637 : * _service._protocol.domain.name
638 : * 5. If the site is found, use (a) as primary and (b) as backup servers,
639 : * otherwise use (b) as primary servers
640 : */
641 0 : struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx,
642 : struct tevent_context *ev,
643 : const char *service,
644 : const char *protocol,
645 : const char *discovery_domain,
646 : void *pvt)
647 : {
648 0 : struct ad_srv_plugin_state *state = NULL;
649 0 : struct ad_srv_plugin_ctx *ctx = NULL;
650 0 : struct tevent_req *req = NULL;
651 0 : struct tevent_req *subreq = NULL;
652 : errno_t ret;
653 :
654 0 : req = tevent_req_create(mem_ctx, &state,
655 : struct ad_srv_plugin_state);
656 0 : if (req == NULL) {
657 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
658 0 : return NULL;
659 : }
660 :
661 0 : ctx = talloc_get_type(pvt, struct ad_srv_plugin_ctx);
662 0 : if (ctx == NULL) {
663 0 : ret = EINVAL;
664 0 : goto immediately;
665 : }
666 :
667 0 : state->ev = ev;
668 0 : state->ctx = ctx;
669 :
670 0 : state->service = talloc_strdup(state, service);
671 0 : if (state->service == NULL) {
672 0 : ret = ENOMEM;
673 0 : goto immediately;
674 : }
675 :
676 0 : state->protocol = talloc_strdup(state, protocol);
677 0 : if (state->protocol == NULL) {
678 0 : ret = ENOMEM;
679 0 : goto immediately;
680 : }
681 :
682 0 : if (discovery_domain != NULL) {
683 0 : state->discovery_domain = talloc_strdup(state, discovery_domain);
684 : } else {
685 0 : state->discovery_domain = talloc_strdup(state, ctx->ad_domain);
686 : }
687 0 : if (state->discovery_domain == NULL) {
688 0 : ret = ENOMEM;
689 0 : goto immediately;
690 : }
691 :
692 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to find domain controllers\n");
693 :
694 0 : subreq = ad_get_dc_servers_send(state, ev, ctx->be_res->resolv,
695 0 : state->discovery_domain);
696 0 : if (subreq == NULL) {
697 0 : ret = ENOMEM;
698 0 : goto immediately;
699 : }
700 :
701 0 : tevent_req_set_callback(subreq, ad_srv_plugin_dcs_done, req);
702 :
703 0 : return req;
704 :
705 : immediately:
706 0 : tevent_req_error(req, ret);
707 0 : tevent_req_post(req, ev);
708 :
709 0 : return req;
710 : }
711 :
712 0 : static void ad_srv_plugin_dcs_done(struct tevent_req *subreq)
713 : {
714 0 : struct ad_srv_plugin_state *state = NULL;
715 0 : struct tevent_req *req = NULL;
716 0 : struct fo_server_info *dcs = NULL;
717 0 : size_t num_dcs = 0;
718 : errno_t ret;
719 :
720 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
721 0 : state = tevent_req_data(req, struct ad_srv_plugin_state);
722 :
723 0 : ret = ad_get_dc_servers_recv(state, subreq, &dcs, &num_dcs);
724 0 : talloc_zfree(subreq);
725 0 : if (ret != EOK) {
726 0 : goto done;
727 : }
728 :
729 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to locate suitable site\n");
730 :
731 0 : subreq = ad_get_client_site_send(state, state->ev,
732 0 : state->ctx->be_res,
733 0 : state->ctx->host_dbs,
734 0 : state->ctx->opts,
735 : state->discovery_domain,
736 : dcs, num_dcs);
737 0 : if (subreq == NULL) {
738 0 : ret = ENOMEM;
739 0 : goto done;
740 : }
741 :
742 0 : tevent_req_set_callback(subreq, ad_srv_plugin_site_done, req);
743 :
744 0 : ret = EAGAIN;
745 :
746 : done:
747 0 : if (ret == EOK) {
748 0 : tevent_req_done(req);
749 0 : } else if (ret != EAGAIN) {
750 0 : tevent_req_error(req, ret);
751 : }
752 :
753 0 : return;
754 : }
755 :
756 0 : static void ad_srv_plugin_site_done(struct tevent_req *subreq)
757 : {
758 0 : struct ad_srv_plugin_state *state = NULL;
759 0 : struct tevent_req *req = NULL;
760 0 : const char *primary_domain = NULL;
761 0 : const char *backup_domain = NULL;
762 : errno_t ret;
763 :
764 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
765 0 : state = tevent_req_data(req, struct ad_srv_plugin_state);
766 :
767 0 : ret = ad_get_client_site_recv(state, subreq, &state->site, &state->forest);
768 0 : talloc_zfree(subreq);
769 : /* Ignore AD site found by dns discovery if specific site is set in
770 : * configuration file. */
771 0 : if (state->ctx->ad_site_override != NULL) {
772 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
773 : "Ignoring AD site found by DNS discovery: '%s', "
774 : "using configured value: '%s' instead.\n",
775 : state->site, state->ctx->ad_site_override);
776 0 : state->site = state->ctx->ad_site_override;
777 :
778 0 : if (state->forest == NULL) {
779 0 : DEBUG(SSSDBG_TRACE_FUNC, "Missing forest information, using %s\n",
780 : state->discovery_domain);
781 0 : state->forest = state->discovery_domain;
782 : }
783 :
784 0 : ret = EOK;
785 : }
786 0 : if (ret == EOK) {
787 0 : if (strcmp(state->service, "gc") == 0) {
788 0 : primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
789 : state->site, state->forest);
790 0 : if (primary_domain == NULL) {
791 0 : ret = ENOMEM;
792 0 : goto done;
793 : }
794 :
795 0 : backup_domain = state->forest;
796 : } else {
797 0 : primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
798 : state->site, state->discovery_domain);
799 0 : if (primary_domain == NULL) {
800 0 : ret = ENOMEM;
801 0 : goto done;
802 : }
803 :
804 0 : backup_domain = state->discovery_domain;
805 : }
806 0 : } else if (ret == ENOENT) {
807 0 : primary_domain = state->discovery_domain;
808 0 : backup_domain = NULL;
809 : } else {
810 0 : goto done;
811 : }
812 :
813 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to discover primary and "
814 : "backup servers\n");
815 :
816 0 : subreq = fo_discover_servers_send(state, state->ev,
817 0 : state->ctx->be_res->resolv,
818 : state->service, state->protocol,
819 : primary_domain, backup_domain);
820 0 : if (subreq == NULL) {
821 0 : ret = ENOMEM;
822 0 : goto done;
823 : }
824 :
825 0 : tevent_req_set_callback(subreq, ad_srv_plugin_servers_done, req);
826 :
827 0 : ret = EAGAIN;
828 :
829 : done:
830 0 : if (ret == EOK) {
831 0 : tevent_req_done(req);
832 0 : } else if (ret != EAGAIN) {
833 0 : tevent_req_error(req, ret);
834 : }
835 :
836 0 : return;
837 : }
838 :
839 0 : static void ad_srv_plugin_servers_done(struct tevent_req *subreq)
840 : {
841 0 : struct ad_srv_plugin_state *state = NULL;
842 0 : struct tevent_req *req = NULL;
843 : errno_t ret;
844 :
845 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
846 0 : state = tevent_req_data(req, struct ad_srv_plugin_state);
847 :
848 0 : ret = fo_discover_servers_recv(state, subreq, &state->dns_domain,
849 : &state->ttl,
850 : &state->primary_servers,
851 : &state->num_primary_servers,
852 : &state->backup_servers,
853 : &state->num_backup_servers);
854 0 : talloc_zfree(subreq);
855 0 : if (ret != EOK) {
856 0 : tevent_req_error(req, ret);
857 0 : return;
858 : }
859 :
860 0 : DEBUG(SSSDBG_TRACE_FUNC, "Got %zu primary and %zu backup servers\n",
861 : state->num_primary_servers, state->num_backup_servers);
862 :
863 0 : ret = ad_sort_servers_by_dns(state, state->discovery_domain,
864 : &state->primary_servers,
865 : state->num_primary_servers);
866 0 : if (ret != EOK) {
867 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unable to sort primary servers by DNS"
868 : "[%d]: %s\n", ret, sss_strerror(ret));
869 : /* continue */
870 : }
871 :
872 0 : ret = ad_sort_servers_by_dns(state, state->discovery_domain,
873 : &state->backup_servers,
874 : state->num_backup_servers);
875 0 : if (ret != EOK) {
876 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unable to sort backup servers by DNS"
877 : "[%d]: %s\n", ret, sss_strerror(ret));
878 : /* continue */
879 : }
880 :
881 0 : tevent_req_done(req);
882 : }
883 :
884 0 : errno_t ad_srv_plugin_recv(TALLOC_CTX *mem_ctx,
885 : struct tevent_req *req,
886 : char **_dns_domain,
887 : uint32_t *_ttl,
888 : struct fo_server_info **_primary_servers,
889 : size_t *_num_primary_servers,
890 : struct fo_server_info **_backup_servers,
891 : size_t *_num_backup_servers)
892 : {
893 0 : struct ad_srv_plugin_state *state = NULL;
894 0 : state = tevent_req_data(req, struct ad_srv_plugin_state);
895 :
896 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
897 :
898 0 : if (_primary_servers) {
899 0 : *_primary_servers = talloc_steal(mem_ctx, state->primary_servers);
900 : }
901 :
902 0 : if (_num_primary_servers) {
903 0 : *_num_primary_servers = state->num_primary_servers;
904 : }
905 :
906 0 : if (_backup_servers) {
907 0 : *_backup_servers = talloc_steal(mem_ctx, state->backup_servers);
908 : }
909 :
910 0 : if (_num_backup_servers) {
911 0 : *_num_backup_servers = state->num_backup_servers;
912 : }
913 :
914 0 : if (_dns_domain) {
915 0 : *_dns_domain = talloc_steal(mem_ctx, state->dns_domain);
916 : }
917 :
918 0 : if (_ttl) {
919 0 : *_ttl = state->ttl;
920 : }
921 :
922 0 : return EOK;
923 : }
|