LCOV - code coverage report
Current view: top level - providers/ad - ad_srv.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 13 433 3.0 %
Date: 2015-10-19 Functions: 1 16 6.2 %

          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             : }

Generated by: LCOV version 1.10