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/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 : {
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 *discovery_domain,
122 : const char *site)
123 : {
124 0 : struct ad_get_dc_servers_state *state = NULL;
125 0 : struct tevent_req *req = NULL;
126 0 : struct tevent_req *subreq = NULL;
127 0 : const char **domains = NULL;
128 : errno_t ret;
129 :
130 0 : req = tevent_req_create(mem_ctx, &state,
131 : struct ad_get_dc_servers_state);
132 0 : if (req == NULL) {
133 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
134 0 : return NULL;
135 : }
136 :
137 0 : domains = talloc_zero_array(state, const char *, 3);
138 0 : if (domains == NULL) {
139 0 : ret = ENOMEM;
140 0 : goto immediately;
141 : }
142 :
143 0 : if (site == NULL) {
144 0 : DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain "
145 : "%s\n", discovery_domain);
146 :
147 0 : domains[0] = talloc_strdup(domains, discovery_domain);
148 0 : if (domains[0] == NULL) {
149 0 : ret = ENOMEM;
150 0 : goto immediately;
151 : }
152 : } else {
153 0 : DEBUG(SSSDBG_TRACE_FUNC, "Looking up domain controllers in domain "
154 : "%s and site %s\n", discovery_domain, site);
155 :
156 0 : domains[0] = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
157 : site, discovery_domain);
158 0 : if (domains[0] == NULL) {
159 0 : ret = ENOMEM;
160 0 : goto immediately;
161 : }
162 :
163 0 : domains[1] = talloc_strdup(domains, discovery_domain);
164 0 : if (domains[1] == NULL) {
165 0 : ret = ENOMEM;
166 0 : goto immediately;
167 : }
168 : }
169 :
170 0 : subreq = fo_discover_srv_send(state, ev, resolv_ctx,
171 : "ldap", FO_PROTO_TCP, domains);
172 0 : if (subreq == NULL) {
173 0 : ret = ENOMEM;
174 0 : goto immediately;
175 : }
176 :
177 0 : tevent_req_set_callback(subreq, ad_get_dc_servers_done, req);
178 :
179 0 : return req;
180 :
181 : immediately:
182 0 : tevent_req_error(req, ret);
183 0 : tevent_req_post(req, ev);
184 :
185 0 : return req;
186 : }
187 :
188 0 : static void ad_get_dc_servers_done(struct tevent_req *subreq)
189 : {
190 0 : struct ad_get_dc_servers_state *state = NULL;
191 0 : struct tevent_req *req = NULL;
192 0 : char *domain = NULL;
193 : errno_t ret;
194 :
195 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
196 0 : state = tevent_req_data(req, struct ad_get_dc_servers_state);
197 :
198 0 : ret = fo_discover_srv_recv(state, subreq, &domain, NULL,
199 : &state->servers, &state->num_servers);
200 0 : talloc_zfree(subreq);
201 0 : if (ret != EOK) {
202 0 : goto done;
203 : }
204 :
205 0 : DEBUG(SSSDBG_TRACE_FUNC, "Found %zu domain controllers in domain %s\n",
206 : state->num_servers, domain);
207 :
208 : done:
209 0 : if (ret != EOK) {
210 0 : tevent_req_error(req, ret);
211 0 : return;
212 : }
213 :
214 0 : tevent_req_done(req);
215 : }
216 :
217 0 : static int ad_get_dc_servers_recv(TALLOC_CTX *mem_ctx,
218 : struct tevent_req *req,
219 : struct fo_server_info **_dcs,
220 : size_t *_num_dcs)
221 : {
222 0 : struct ad_get_dc_servers_state *state = NULL;
223 0 : state = tevent_req_data(req, struct ad_get_dc_servers_state);
224 :
225 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
226 :
227 0 : *_dcs = talloc_steal(mem_ctx, state->servers);
228 0 : *_num_dcs = state->num_servers;
229 :
230 0 : return EOK;
231 : }
232 :
233 : struct ad_get_client_site_state {
234 : struct tevent_context *ev;
235 : struct be_resolv_ctx *be_res;
236 : enum host_database *host_db;
237 : struct sdap_options *opts;
238 : const char *ad_domain;
239 : struct fo_server_info *dcs;
240 : size_t num_dcs;
241 : size_t dc_index;
242 : struct fo_server_info dc;
243 :
244 : struct sdap_handle *sh;
245 : char *site;
246 : char *forest;
247 : };
248 :
249 : static errno_t ad_get_client_site_next_dc(struct tevent_req *req);
250 : static void ad_get_client_site_connect_done(struct tevent_req *subreq);
251 : static void ad_get_client_site_done(struct tevent_req *subreq);
252 :
253 0 : struct tevent_req *ad_get_client_site_send(TALLOC_CTX *mem_ctx,
254 : struct tevent_context *ev,
255 : struct be_resolv_ctx *be_res,
256 : enum host_database *host_db,
257 : struct sdap_options *opts,
258 : const char *ad_domain,
259 : struct fo_server_info *dcs,
260 : size_t num_dcs)
261 : {
262 0 : struct ad_get_client_site_state *state = NULL;
263 0 : struct tevent_req *req = NULL;
264 : errno_t ret;
265 :
266 0 : req = tevent_req_create(mem_ctx, &state,
267 : struct ad_get_client_site_state);
268 0 : if (req == NULL) {
269 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
270 0 : return NULL;
271 : }
272 :
273 0 : if (be_res == NULL || host_db == NULL || opts == NULL) {
274 0 : ret = EINVAL;
275 0 : goto immediately;
276 : }
277 :
278 0 : state->ev = ev;
279 0 : state->be_res = be_res;
280 0 : state->host_db = host_db;
281 0 : state->opts = opts;
282 0 : state->ad_domain = ad_domain;
283 0 : state->dcs = dcs;
284 0 : state->num_dcs = num_dcs;
285 :
286 0 : state->dc_index = 0;
287 0 : ret = ad_get_client_site_next_dc(req);
288 0 : if (ret == EOK) {
289 0 : ret = ENOENT;
290 0 : goto immediately;
291 0 : } else if (ret != EAGAIN) {
292 0 : goto immediately;
293 : }
294 :
295 0 : return req;
296 :
297 : immediately:
298 0 : if (ret == EOK) {
299 0 : tevent_req_done(req);
300 : } else {
301 0 : tevent_req_error(req, ret);
302 : }
303 0 : tevent_req_post(req, ev);
304 :
305 0 : return req;
306 : }
307 :
308 0 : static errno_t ad_get_client_site_next_dc(struct tevent_req *req)
309 : {
310 0 : struct ad_get_client_site_state *state = NULL;
311 0 : struct tevent_req *subreq = NULL;
312 : errno_t ret;
313 :
314 0 : state = tevent_req_data(req, struct ad_get_client_site_state);
315 :
316 0 : if (state->dc_index >= state->num_dcs) {
317 0 : ret = EOK;
318 0 : goto done;
319 : }
320 :
321 0 : state->dc = state->dcs[state->dc_index];
322 :
323 0 : subreq = sdap_connect_host_send(state, state->ev, state->opts,
324 0 : state->be_res->resolv,
325 0 : state->be_res->family_order,
326 0 : state->host_db, "ldap", state->dc.host,
327 : state->dc.port, false);
328 0 : if (subreq == NULL) {
329 0 : ret = ENOMEM;
330 0 : goto done;
331 : }
332 :
333 0 : tevent_req_set_callback(subreq, ad_get_client_site_connect_done, req);
334 :
335 0 : state->dc_index++;
336 0 : ret = EAGAIN;
337 :
338 : done:
339 0 : return ret;
340 : }
341 :
342 0 : static void ad_get_client_site_connect_done(struct tevent_req *subreq)
343 : {
344 0 : struct ad_get_client_site_state *state = NULL;
345 0 : struct tevent_req *req = NULL;
346 : static const char *attrs[] = {AD_AT_NETLOGON, NULL};
347 0 : char *filter = NULL;
348 0 : char *ntver = NULL;
349 : errno_t ret;
350 :
351 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
352 0 : state = tevent_req_data(req, struct ad_get_client_site_state);
353 :
354 0 : ret = sdap_connect_host_recv(state, subreq, &state->sh);
355 0 : talloc_zfree(subreq);
356 0 : if (ret != EOK) {
357 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unable to connect to domain controller "
358 : "[%s:%d]\n", state->dc.host, state->dc.port);
359 :
360 0 : ret = ad_get_client_site_next_dc(req);
361 0 : if (ret == EOK) {
362 0 : ret = ENOENT;
363 : }
364 :
365 0 : goto done;
366 : }
367 :
368 0 : ntver = sss_ldap_encode_ndr_uint32(state, NETLOGON_NT_VERSION_5EX |
369 : NETLOGON_NT_VERSION_WITH_CLOSEST_SITE);
370 0 : if (ntver == NULL) {
371 0 : ret = ENOMEM;
372 0 : goto done;
373 : }
374 :
375 0 : filter = talloc_asprintf(state, "(&(%s=%s)(%s=%s))",
376 : AD_AT_DNS_DOMAIN, state->ad_domain,
377 : AD_AT_NT_VERSION, ntver);
378 0 : if (filter == NULL) {
379 0 : ret = ENOMEM;
380 0 : goto done;
381 : }
382 :
383 0 : subreq = sdap_get_generic_send(state, state->ev, state->opts, state->sh,
384 : "", LDAP_SCOPE_BASE, filter,
385 : attrs, NULL, 0,
386 0 : dp_opt_get_int(state->opts->basic,
387 : SDAP_SEARCH_TIMEOUT),
388 : false);
389 0 : if (subreq == NULL) {
390 0 : ret = ENOMEM;
391 0 : goto done;
392 : }
393 :
394 0 : tevent_req_set_callback(subreq, ad_get_client_site_done, req);
395 :
396 0 : ret = EAGAIN;
397 :
398 : done:
399 0 : if (ret == EOK) {
400 0 : tevent_req_done(req);
401 0 : } else if (ret != EAGAIN) {
402 0 : tevent_req_error(req, ret);
403 : }
404 :
405 0 : return;
406 : }
407 :
408 0 : static errno_t ad_get_client_site_parse_ndr(TALLOC_CTX *mem_ctx,
409 : uint8_t *data,
410 : size_t length,
411 : char **_site_name,
412 : char **_forest_name)
413 : {
414 0 : TALLOC_CTX *tmp_ctx = NULL;
415 0 : struct ndr_pull *ndr_pull = NULL;
416 : struct netlogon_samlogon_response response;
417 : enum ndr_err_code ndr_err;
418 0 : char *site = NULL;
419 0 : char *forest = NULL;
420 : DATA_BLOB blob;
421 : errno_t ret;
422 :
423 0 : tmp_ctx = talloc_new(NULL);
424 0 : if (tmp_ctx == NULL) {
425 0 : DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
426 0 : return ENOMEM;
427 : }
428 :
429 0 : blob.data = data;
430 0 : blob.length = length;
431 :
432 0 : ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
433 0 : if (ndr_pull == NULL) {
434 0 : DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_init_blob() failed.\n");
435 0 : ret = ENOMEM;
436 0 : goto done;
437 : }
438 :
439 0 : ndr_err = ndr_pull_netlogon_samlogon_response(ndr_pull, NDR_SCALARS,
440 : &response);
441 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
442 0 : DEBUG(SSSDBG_OP_FAILURE, "ndr_pull_netlogon_samlogon_response() "
443 : "failed [%d]\n", ndr_err);
444 0 : ret = EBADMSG;
445 0 : goto done;
446 : }
447 :
448 0 : if (!(response.ntver & NETLOGON_NT_VERSION_5EX)) {
449 0 : DEBUG(SSSDBG_OP_FAILURE, "This NT version does not provide site "
450 : "information [%x]\n", response.ntver);
451 0 : ret = EBADMSG;
452 0 : goto done;
453 : }
454 :
455 0 : if (response.data.nt5_ex.client_site != NULL
456 0 : && response.data.nt5_ex.client_site[0] != '\0') {
457 0 : site = talloc_strdup(tmp_ctx, response.data.nt5_ex.client_site);
458 0 : } else if (response.data.nt5_ex.next_closest_site != NULL
459 0 : && response.data.nt5_ex.next_closest_site[0] != '\0') {
460 0 : site = talloc_strdup(tmp_ctx, response.data.nt5_ex.next_closest_site);
461 : } else {
462 0 : ret = ENOENT;
463 0 : goto done;
464 : }
465 :
466 0 : if (response.data.nt5_ex.forest != NULL
467 0 : && response.data.nt5_ex.forest[0] != '\0') {
468 0 : forest = talloc_strdup(tmp_ctx, response.data.nt5_ex.forest);
469 : } else {
470 0 : ret = ENOENT;
471 0 : goto done;
472 : }
473 :
474 :
475 0 : if (site == NULL || forest == NULL) {
476 0 : ret = ENOMEM;
477 0 : goto done;
478 : }
479 :
480 0 : *_site_name = talloc_steal(mem_ctx, site);
481 0 : *_forest_name = talloc_steal(mem_ctx, forest);
482 :
483 0 : ret = EOK;
484 :
485 : done:
486 0 : talloc_free(tmp_ctx);
487 0 : return ret;
488 : }
489 :
490 0 : static void ad_get_client_site_done(struct tevent_req *subreq)
491 : {
492 0 : struct ad_get_client_site_state *state = NULL;
493 0 : struct tevent_req *req = NULL;
494 0 : struct ldb_message_element *el = NULL;
495 0 : struct sysdb_attrs **reply = NULL;
496 : size_t reply_count;
497 : errno_t ret;
498 :
499 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
500 0 : state = tevent_req_data(req, struct ad_get_client_site_state);
501 :
502 0 : ret = sdap_get_generic_recv(subreq, state, &reply_count, &reply);
503 0 : talloc_zfree(subreq);
504 :
505 : /* we're done with this LDAP, close connection */
506 0 : talloc_zfree(state->sh);
507 0 : if (ret != EOK) {
508 0 : DEBUG(SSSDBG_OP_FAILURE, "Unable to get netlogon information\n");
509 :
510 0 : ret = ad_get_client_site_next_dc(req);
511 0 : if (ret == EOK) {
512 0 : ret = ENOENT;
513 : }
514 0 : goto done;
515 : }
516 :
517 0 : if (reply_count == 0) {
518 0 : DEBUG(SSSDBG_OP_FAILURE, "No netlogon information retrieved\n");
519 0 : ret = ENOENT;
520 0 : goto done;
521 : }
522 :
523 0 : ret = sysdb_attrs_get_el(reply[0], AD_AT_NETLOGON, &el);
524 0 : if (ret != EOK) {
525 0 : DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_get_el() failed\n");
526 0 : goto done;
527 : }
528 :
529 0 : if (el->num_values == 0) {
530 0 : DEBUG(SSSDBG_OP_FAILURE, "netlogon has no value\n");
531 0 : ret = ENOENT;
532 0 : goto done;
533 0 : } else if (el->num_values > 1) {
534 0 : DEBUG(SSSDBG_OP_FAILURE, "More than one netlogon value?\n");
535 0 : ret = EIO;
536 0 : goto done;
537 : }
538 :
539 0 : ret = ad_get_client_site_parse_ndr(state, el->values[0].data,
540 0 : el->values[0].length, &state->site,
541 : &state->forest);
542 0 : if (ret != EOK) {
543 0 : DEBUG(SSSDBG_OP_FAILURE, "Unable to retrieve site name [%d]: %s\n",
544 : ret, strerror(ret));
545 0 : ret = ENOENT;
546 0 : goto done;
547 : }
548 :
549 0 : DEBUG(SSSDBG_TRACE_FUNC, "Found site: %s\n", state->site);
550 :
551 : done:
552 0 : if (ret != EOK) {
553 0 : tevent_req_error(req, ret);
554 0 : return;
555 : }
556 :
557 0 : tevent_req_done(req);
558 : }
559 :
560 0 : int ad_get_client_site_recv(TALLOC_CTX *mem_ctx,
561 : struct tevent_req *req,
562 : const char **_site,
563 : const char **_forest)
564 : {
565 0 : struct ad_get_client_site_state *state = NULL;
566 0 : state = tevent_req_data(req, struct ad_get_client_site_state);
567 :
568 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
569 :
570 0 : *_site = talloc_steal(mem_ctx, state->site);
571 0 : *_forest = talloc_steal(mem_ctx, state->forest);
572 :
573 0 : return EOK;
574 : }
575 :
576 : struct ad_srv_plugin_ctx {
577 : struct be_resolv_ctx *be_res;
578 : enum host_database *host_dbs;
579 : struct sdap_options *opts;
580 : const char *hostname;
581 : const char *ad_domain;
582 : const char *ad_site_override;
583 : };
584 :
585 : struct ad_srv_plugin_ctx *
586 0 : ad_srv_plugin_ctx_init(TALLOC_CTX *mem_ctx,
587 : struct be_resolv_ctx *be_res,
588 : enum host_database *host_dbs,
589 : struct sdap_options *opts,
590 : const char *hostname,
591 : const char *ad_domain,
592 : const char *ad_site_override)
593 : {
594 0 : struct ad_srv_plugin_ctx *ctx = NULL;
595 :
596 0 : ctx = talloc_zero(mem_ctx, struct ad_srv_plugin_ctx);
597 0 : if (ctx == NULL) {
598 0 : return NULL;
599 : }
600 :
601 0 : ctx->be_res = be_res;
602 0 : ctx->host_dbs = host_dbs;
603 0 : ctx->opts = opts;
604 :
605 0 : ctx->hostname = talloc_strdup(ctx, hostname);
606 0 : if (ctx->hostname == NULL) {
607 0 : goto fail;
608 : }
609 :
610 0 : ctx->ad_domain = talloc_strdup(ctx, ad_domain);
611 0 : if (ctx->ad_domain == NULL) {
612 0 : goto fail;
613 : }
614 :
615 0 : if (ad_site_override != NULL) {
616 0 : ctx->ad_site_override = talloc_strdup(ctx, ad_site_override);
617 0 : if (ctx->ad_site_override == NULL) {
618 0 : goto fail;
619 : }
620 : }
621 :
622 0 : return ctx;
623 :
624 : fail:
625 0 : talloc_free(ctx);
626 0 : return NULL;
627 : }
628 :
629 : struct ad_srv_plugin_state {
630 : struct tevent_context *ev;
631 : struct ad_srv_plugin_ctx *ctx;
632 : const char *service;
633 : const char *protocol;
634 : const char *discovery_domain;
635 :
636 : const char *site;
637 : char *dns_domain;
638 : uint32_t ttl;
639 : const char *forest;
640 : struct fo_server_info *primary_servers;
641 : size_t num_primary_servers;
642 : struct fo_server_info *backup_servers;
643 : size_t num_backup_servers;
644 : };
645 :
646 : static void ad_srv_plugin_dcs_done(struct tevent_req *subreq);
647 : static void ad_srv_plugin_site_done(struct tevent_req *subreq);
648 : static void ad_srv_plugin_servers_done(struct tevent_req *subreq);
649 :
650 : /* 1. Do a DNS lookup to find any DC in domain
651 : * _ldap._tcp.domain.name
652 : * 2. Send a CLDAP ping to the found DC to get the desirable site
653 : * 3. Do a DNS lookup to find SRV in the site (a)
654 : * _service._protocol.site-name._sites.domain.name
655 : * 4. Do a DNS lookup to find global SRV records (b)
656 : * _service._protocol.domain.name
657 : * 5. If the site is found, use (a) as primary and (b) as backup servers,
658 : * otherwise use (b) as primary servers
659 : */
660 0 : struct tevent_req *ad_srv_plugin_send(TALLOC_CTX *mem_ctx,
661 : struct tevent_context *ev,
662 : const char *service,
663 : const char *protocol,
664 : const char *discovery_domain,
665 : void *pvt)
666 : {
667 0 : struct ad_srv_plugin_state *state = NULL;
668 0 : struct ad_srv_plugin_ctx *ctx = NULL;
669 0 : struct tevent_req *req = NULL;
670 0 : struct tevent_req *subreq = NULL;
671 : errno_t ret;
672 :
673 0 : req = tevent_req_create(mem_ctx, &state,
674 : struct ad_srv_plugin_state);
675 0 : if (req == NULL) {
676 0 : DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
677 0 : return NULL;
678 : }
679 :
680 0 : ctx = talloc_get_type(pvt, struct ad_srv_plugin_ctx);
681 0 : if (ctx == NULL) {
682 0 : ret = EINVAL;
683 0 : goto immediately;
684 : }
685 :
686 0 : state->ev = ev;
687 0 : state->ctx = ctx;
688 :
689 0 : state->service = talloc_strdup(state, service);
690 0 : if (state->service == NULL) {
691 0 : ret = ENOMEM;
692 0 : goto immediately;
693 : }
694 :
695 0 : state->protocol = talloc_strdup(state, protocol);
696 0 : if (state->protocol == NULL) {
697 0 : ret = ENOMEM;
698 0 : goto immediately;
699 : }
700 :
701 0 : if (discovery_domain != NULL) {
702 0 : state->discovery_domain = talloc_strdup(state, discovery_domain);
703 : } else {
704 0 : state->discovery_domain = talloc_strdup(state, ctx->ad_domain);
705 : }
706 0 : if (state->discovery_domain == NULL) {
707 0 : ret = ENOMEM;
708 0 : goto immediately;
709 : }
710 :
711 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to find domain controllers\n");
712 :
713 0 : subreq = ad_get_dc_servers_send(state, ev, ctx->be_res->resolv,
714 0 : state->discovery_domain,
715 0 : state->ctx->ad_site_override);
716 0 : if (subreq == NULL) {
717 0 : ret = ENOMEM;
718 0 : goto immediately;
719 : }
720 :
721 0 : tevent_req_set_callback(subreq, ad_srv_plugin_dcs_done, req);
722 :
723 0 : return req;
724 :
725 : immediately:
726 0 : tevent_req_error(req, ret);
727 0 : tevent_req_post(req, ev);
728 :
729 0 : return req;
730 : }
731 :
732 0 : static void ad_srv_plugin_dcs_done(struct tevent_req *subreq)
733 : {
734 0 : struct ad_srv_plugin_state *state = NULL;
735 0 : struct tevent_req *req = NULL;
736 0 : struct fo_server_info *dcs = NULL;
737 0 : size_t num_dcs = 0;
738 : errno_t ret;
739 :
740 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
741 0 : state = tevent_req_data(req, struct ad_srv_plugin_state);
742 :
743 0 : ret = ad_get_dc_servers_recv(state, subreq, &dcs, &num_dcs);
744 0 : talloc_zfree(subreq);
745 0 : if (ret != EOK) {
746 0 : goto done;
747 : }
748 :
749 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to locate suitable site\n");
750 :
751 0 : subreq = ad_get_client_site_send(state, state->ev,
752 0 : state->ctx->be_res,
753 0 : state->ctx->host_dbs,
754 0 : state->ctx->opts,
755 : state->discovery_domain,
756 : dcs, num_dcs);
757 0 : if (subreq == NULL) {
758 0 : ret = ENOMEM;
759 0 : goto done;
760 : }
761 :
762 0 : tevent_req_set_callback(subreq, ad_srv_plugin_site_done, req);
763 :
764 0 : ret = EAGAIN;
765 :
766 : done:
767 0 : if (ret == EOK) {
768 0 : tevent_req_done(req);
769 0 : } else if (ret != EAGAIN) {
770 0 : tevent_req_error(req, ret);
771 : }
772 :
773 0 : return;
774 : }
775 :
776 0 : static void ad_srv_plugin_site_done(struct tevent_req *subreq)
777 : {
778 0 : struct ad_srv_plugin_state *state = NULL;
779 0 : struct tevent_req *req = NULL;
780 0 : const char *primary_domain = NULL;
781 0 : const char *backup_domain = NULL;
782 : errno_t ret;
783 :
784 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
785 0 : state = tevent_req_data(req, struct ad_srv_plugin_state);
786 :
787 0 : ret = ad_get_client_site_recv(state, subreq, &state->site, &state->forest);
788 0 : talloc_zfree(subreq);
789 : /* Ignore AD site found by dns discovery if specific site is set in
790 : * configuration file. */
791 0 : if (state->ctx->ad_site_override != NULL) {
792 0 : DEBUG(SSSDBG_TRACE_INTERNAL,
793 : "Ignoring AD site found by DNS discovery: '%s', "
794 : "using configured value: '%s' instead.\n",
795 : state->site, state->ctx->ad_site_override);
796 0 : state->site = state->ctx->ad_site_override;
797 :
798 0 : if (state->forest == NULL) {
799 0 : DEBUG(SSSDBG_TRACE_FUNC, "Missing forest information, using %s\n",
800 : state->discovery_domain);
801 0 : state->forest = state->discovery_domain;
802 : }
803 :
804 0 : ret = EOK;
805 : }
806 0 : if (ret == EOK) {
807 0 : if (strcmp(state->service, "gc") == 0) {
808 0 : primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
809 : state->site, state->forest);
810 0 : if (primary_domain == NULL) {
811 0 : ret = ENOMEM;
812 0 : goto done;
813 : }
814 :
815 0 : backup_domain = state->forest;
816 : } else {
817 0 : primary_domain = talloc_asprintf(state, AD_SITE_DOMAIN_FMT,
818 : state->site, state->discovery_domain);
819 0 : if (primary_domain == NULL) {
820 0 : ret = ENOMEM;
821 0 : goto done;
822 : }
823 :
824 0 : backup_domain = state->discovery_domain;
825 : }
826 0 : } else if (ret == ENOENT) {
827 0 : primary_domain = state->discovery_domain;
828 0 : backup_domain = NULL;
829 : } else {
830 0 : goto done;
831 : }
832 :
833 0 : DEBUG(SSSDBG_TRACE_FUNC, "About to discover primary and "
834 : "backup servers\n");
835 :
836 0 : subreq = fo_discover_servers_send(state, state->ev,
837 0 : state->ctx->be_res->resolv,
838 : state->service, state->protocol,
839 : primary_domain, backup_domain);
840 0 : if (subreq == NULL) {
841 0 : ret = ENOMEM;
842 0 : goto done;
843 : }
844 :
845 0 : tevent_req_set_callback(subreq, ad_srv_plugin_servers_done, req);
846 :
847 0 : ret = EAGAIN;
848 :
849 : done:
850 0 : if (ret == EOK) {
851 0 : tevent_req_done(req);
852 0 : } else if (ret != EAGAIN) {
853 0 : tevent_req_error(req, ret);
854 : }
855 :
856 0 : return;
857 : }
858 :
859 0 : static void ad_srv_plugin_servers_done(struct tevent_req *subreq)
860 : {
861 0 : struct ad_srv_plugin_state *state = NULL;
862 0 : struct tevent_req *req = NULL;
863 : errno_t ret;
864 :
865 0 : req = tevent_req_callback_data(subreq, struct tevent_req);
866 0 : state = tevent_req_data(req, struct ad_srv_plugin_state);
867 :
868 0 : ret = fo_discover_servers_recv(state, subreq, &state->dns_domain,
869 : &state->ttl,
870 : &state->primary_servers,
871 : &state->num_primary_servers,
872 : &state->backup_servers,
873 : &state->num_backup_servers);
874 0 : talloc_zfree(subreq);
875 0 : if (ret != EOK) {
876 0 : tevent_req_error(req, ret);
877 0 : return;
878 : }
879 :
880 0 : DEBUG(SSSDBG_TRACE_FUNC, "Got %zu primary and %zu backup servers\n",
881 : state->num_primary_servers, state->num_backup_servers);
882 :
883 0 : ret = ad_sort_servers_by_dns(state, state->discovery_domain,
884 : &state->primary_servers,
885 : state->num_primary_servers);
886 0 : if (ret != EOK) {
887 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unable to sort primary servers by DNS"
888 : "[%d]: %s\n", ret, sss_strerror(ret));
889 : /* continue */
890 : }
891 :
892 0 : ret = ad_sort_servers_by_dns(state, state->discovery_domain,
893 : &state->backup_servers,
894 : state->num_backup_servers);
895 0 : if (ret != EOK) {
896 0 : DEBUG(SSSDBG_MINOR_FAILURE, "Unable to sort backup servers by DNS"
897 : "[%d]: %s\n", ret, sss_strerror(ret));
898 : /* continue */
899 : }
900 :
901 0 : tevent_req_done(req);
902 : }
903 :
904 0 : errno_t ad_srv_plugin_recv(TALLOC_CTX *mem_ctx,
905 : struct tevent_req *req,
906 : char **_dns_domain,
907 : uint32_t *_ttl,
908 : struct fo_server_info **_primary_servers,
909 : size_t *_num_primary_servers,
910 : struct fo_server_info **_backup_servers,
911 : size_t *_num_backup_servers)
912 : {
913 0 : struct ad_srv_plugin_state *state = NULL;
914 0 : state = tevent_req_data(req, struct ad_srv_plugin_state);
915 :
916 0 : TEVENT_REQ_RETURN_ON_ERROR(req);
917 :
918 0 : if (_primary_servers) {
919 0 : *_primary_servers = talloc_steal(mem_ctx, state->primary_servers);
920 : }
921 :
922 0 : if (_num_primary_servers) {
923 0 : *_num_primary_servers = state->num_primary_servers;
924 : }
925 :
926 0 : if (_backup_servers) {
927 0 : *_backup_servers = talloc_steal(mem_ctx, state->backup_servers);
928 : }
929 :
930 0 : if (_num_backup_servers) {
931 0 : *_num_backup_servers = state->num_backup_servers;
932 : }
933 :
934 0 : if (_dns_domain) {
935 0 : *_dns_domain = talloc_steal(mem_ctx, state->dns_domain);
936 : }
937 :
938 0 : if (_ttl) {
939 0 : *_ttl = state->ttl;
940 : }
941 :
942 0 : return EOK;
943 : }
|