"Fossies" - the Fresh Open Source Software Archive

Member "sssd-2.2.3/src/providers/ad/ad_srv.c" (30 Nov 2019, 27838 Bytes) of package /linux/misc/sssd-2.2.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ad_srv.c" see the Fossies "Dox" file reference documentation.

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