LCOV - code coverage report
Current view: top level - providers/ad - ad_srv.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 443 0.0 %
Date: 2016-06-29 Functions: 0 16 0.0 %

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

Generated by: LCOV version 1.10