LCOV - code coverage report
Current view: top level - providers - data_provider_fo.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 37 373 9.9 %
Date: 2016-06-29 Functions: 4 28 14.3 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Data Provider Helpers
       5             : 
       6             :     Copyright (C) Simo Sorce <ssorce@redhat.com> 2009
       7             : 
       8             :     This program is free software; you can redistribute it and/or modify
       9             :     it under the terms of the GNU General Public License as published by
      10             :     the Free Software Foundation; either version 3 of the License, or
      11             :     (at your option) any later version.
      12             : 
      13             :     This program is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :     GNU General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU General Public License
      19             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include <netdb.h>
      23             : #include <arpa/inet.h>
      24             : #include "providers/backend.h"
      25             : #include "resolv/async_resolv.h"
      26             : 
      27             : struct be_svc_callback {
      28             :     struct be_svc_callback *prev;
      29             :     struct be_svc_callback *next;
      30             : 
      31             :     struct be_svc_data *svc;
      32             : 
      33             :     be_svc_callback_fn_t *fn;
      34             :     void *private_data;
      35             : };
      36             : 
      37             : static const char *proto_table[] = { FO_PROTO_TCP, FO_PROTO_UDP, NULL };
      38             : 
      39           0 : int be_fo_is_srv_identifier(const char *server)
      40             : {
      41           0 :     return server && strcasecmp(server, BE_SRV_IDENTIFIER) == 0;
      42             : }
      43             : 
      44           7 : static int be_fo_get_options(struct be_ctx *ctx,
      45             :                              struct fo_options *opts)
      46             : {
      47           7 :     opts->service_resolv_timeout = dp_opt_get_int(ctx->be_res->opts,
      48             :                                                   DP_RES_OPT_RESOLVER_TIMEOUT);
      49           7 :     opts->retry_timeout = 30;
      50           7 :     opts->srv_retry_neg_timeout = 15;
      51           7 :     opts->family_order = ctx->be_res->family_order;
      52             : 
      53           7 :     return EOK;
      54             : }
      55             : 
      56           7 : int be_init_failover(struct be_ctx *ctx)
      57             : {
      58             :     int ret;
      59             :     struct fo_options fopts;
      60             : 
      61           7 :     if (ctx->be_fo != NULL) {
      62           0 :         return EOK;
      63             :     }
      64             : 
      65           7 :     ctx->be_fo = talloc_zero(ctx, struct be_failover_ctx);
      66           7 :     if (!ctx->be_fo) {
      67           0 :         return ENOMEM;
      68             :     }
      69             : 
      70           7 :     ret = be_res_init(ctx);
      71           7 :     if (ret != EOK) {
      72           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
      73             :               "fatal error initializing resolver context\n");
      74           0 :         talloc_zfree(ctx->be_fo);
      75           0 :         return ret;
      76             :     }
      77           7 :     ctx->be_fo->be_res = ctx->be_res;
      78             : 
      79           7 :     ret = be_fo_get_options(ctx, &fopts);
      80           7 :     if (ret != EOK) {
      81           0 :         talloc_zfree(ctx->be_fo);
      82           0 :         return ret;
      83             :     }
      84             : 
      85           7 :     ctx->be_fo->fo_ctx = fo_context_init(ctx->be_fo, &fopts);
      86           7 :     if (!ctx->be_fo->fo_ctx) {
      87           0 :         talloc_zfree(ctx->be_fo);
      88           0 :         return ENOMEM;
      89             :     }
      90             : 
      91           7 :     return EOK;
      92             : }
      93             : 
      94           0 : static int be_svc_data_destroy(void *memptr)
      95             : {
      96             :     struct be_svc_data *svc;
      97             : 
      98           0 :     svc = talloc_get_type(memptr, struct be_svc_data);
      99             : 
     100           0 :     while (svc->callbacks) {
     101             :         /* callbacks removes themselves from the list,
     102             :          * so this while will freem them all and then terminate */
     103           0 :         talloc_free(svc->callbacks);
     104             :     }
     105             : 
     106           0 :     return 0;
     107             : }
     108             : 
     109             : /*
     110             :  * Find registered be_svc_data by service name.
     111             :  */
     112           0 : static struct be_svc_data *be_fo_find_svc_data(struct be_ctx *ctx,
     113             :                                                const char *service_name)
     114             : {
     115             :     struct be_svc_data *svc;
     116             : 
     117           0 :     if (!ctx || !ctx->be_fo) {
     118           0 :         return 0;
     119             :     }
     120             : 
     121           0 :     DLIST_FOR_EACH(svc, ctx->be_fo->svcs) {
     122           0 :         if (strcmp(svc->name, service_name) == 0) {
     123           0 :             return svc;
     124             :         }
     125             :     }
     126             : 
     127           0 :     return 0;
     128             : }
     129             : 
     130           0 : int be_fo_add_service(struct be_ctx *ctx, const char *service_name,
     131             :                       datacmp_fn user_data_cmp)
     132             : {
     133             :     struct fo_service *service;
     134             :     struct be_svc_data *svc;
     135             :     int ret;
     136             : 
     137           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     138           0 :     if (svc) {
     139           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Failover service already initialized!\n");
     140             :         /* we already have a service up and configured,
     141             :          * can happen when using both id and auth provider
     142             :          */
     143           0 :         return EOK;
     144             :     }
     145             : 
     146             :     /* if not in the be service list, try to create new one */
     147             : 
     148           0 :     ret = fo_new_service(ctx->be_fo->fo_ctx, service_name, user_data_cmp,
     149             :                          &service);
     150           0 :     if (ret != EOK && ret != EEXIST) {
     151           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to create failover service!\n");
     152           0 :         return ret;
     153             :     }
     154             : 
     155           0 :     svc = talloc_zero(ctx->be_fo, struct be_svc_data);
     156           0 :     if (!svc) {
     157           0 :         return ENOMEM;
     158             :     }
     159           0 :     talloc_set_destructor((TALLOC_CTX *)svc, be_svc_data_destroy);
     160             : 
     161           0 :     svc->name = talloc_strdup(svc, service_name);
     162           0 :     if (!svc->name) {
     163           0 :         talloc_zfree(svc);
     164           0 :         return ENOMEM;
     165             :     }
     166           0 :     svc->fo_service = service;
     167             : 
     168           0 :     DLIST_ADD(ctx->be_fo->svcs, svc);
     169             : 
     170           0 :     return EOK;
     171             : }
     172             : 
     173           0 : static int be_svc_callback_destroy(void *memptr)
     174             : {
     175             :     struct be_svc_callback *callback;
     176             : 
     177           0 :     callback = talloc_get_type(memptr, struct be_svc_callback);
     178             : 
     179           0 :     if (callback->svc) {
     180           0 :         DLIST_REMOVE(callback->svc->callbacks, callback);
     181             :     }
     182             : 
     183           0 :     return 0;
     184             : }
     185             : 
     186           0 : int be_fo_service_add_callback(TALLOC_CTX *memctx,
     187             :                                struct be_ctx *ctx, const char *service_name,
     188             :                                be_svc_callback_fn_t *fn, void *private_data)
     189             : {
     190             :     struct be_svc_callback *callback;
     191             :     struct be_svc_data *svc;
     192             : 
     193           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     194           0 :     if (NULL == svc) {
     195           0 :         return ENOENT;
     196             :     }
     197             : 
     198           0 :     callback = talloc_zero(memctx, struct be_svc_callback);
     199           0 :     if (!callback) {
     200           0 :         return ENOMEM;
     201             :     }
     202           0 :     talloc_set_destructor((TALLOC_CTX *)callback, be_svc_callback_destroy);
     203             : 
     204           0 :     callback->svc = svc;
     205           0 :     callback->fn = fn;
     206           0 :     callback->private_data = private_data;
     207             : 
     208           0 :     DLIST_ADD(svc->callbacks, callback);
     209             : 
     210           0 :     return EOK;
     211             : }
     212             : 
     213           0 : void be_fo_set_srv_lookup_plugin(struct be_ctx *ctx,
     214             :                                  fo_srv_lookup_plugin_send_t send_fn,
     215             :                                  fo_srv_lookup_plugin_recv_t recv_fn,
     216             :                                  void *pvt,
     217             :                                  const char *plugin_name)
     218             : {
     219             :     bool bret;
     220             : 
     221           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Trying to set SRV lookup plugin to %s\n",
     222             :                               plugin_name);
     223             : 
     224           0 :     bret = fo_set_srv_lookup_plugin(ctx->be_fo->fo_ctx, send_fn, recv_fn, pvt);
     225           0 :     if (bret) {
     226           0 :         DEBUG(SSSDBG_TRACE_FUNC, "SRV lookup plugin is now %s\n",
     227             :                                   plugin_name);
     228             :     } else {
     229           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Unable to set SRV lookup plugin, "
     230             :               "another plugin may be already in place\n");
     231             :     }
     232           0 : }
     233             : 
     234           0 : errno_t be_fo_set_dns_srv_lookup_plugin(struct be_ctx *be_ctx,
     235             :                                         const char *hostname)
     236             : {
     237           0 :     struct fo_resolve_srv_dns_ctx *srv_ctx = NULL;
     238             :     char resolved_hostname[HOST_NAME_MAX + 1];
     239             :     errno_t ret;
     240             : 
     241           0 :     if (hostname == NULL) {
     242           0 :         ret = gethostname(resolved_hostname, HOST_NAME_MAX);
     243           0 :         if (ret != EOK) {
     244           0 :             ret = errno;
     245           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     246             :                   "gethostname() failed: [%d]: %s\n", ret, strerror(ret));
     247           0 :             return ret;
     248             :         }
     249           0 :         resolved_hostname[HOST_NAME_MAX] = '\0';
     250           0 :         hostname = resolved_hostname;
     251             :     }
     252             : 
     253           0 :     srv_ctx = fo_resolve_srv_dns_ctx_init(be_ctx, be_ctx->be_res->resolv,
     254           0 :                                           be_ctx->be_res->family_order,
     255             :                                           default_host_dbs, hostname,
     256           0 :                                           be_ctx->domain->name);
     257           0 :     if (srv_ctx == NULL) {
     258           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Out of memory?\n");
     259           0 :         return ENOMEM;
     260             :     }
     261             : 
     262           0 :     be_fo_set_srv_lookup_plugin(be_ctx, fo_resolve_srv_dns_send,
     263             :                                 fo_resolve_srv_dns_recv, srv_ctx, "DNS");
     264             : 
     265           0 :     return EOK;
     266             : }
     267             : 
     268           0 : int be_fo_add_srv_server(struct be_ctx *ctx,
     269             :                          const char *service_name,
     270             :                          const char *query_service,
     271             :                          const char *default_discovery_domain,
     272             :                          enum be_fo_protocol proto,
     273             :                          bool proto_fallback, void *user_data)
     274             : {
     275             :     struct be_svc_data *svc;
     276             :     const char *domain;
     277             :     int ret;
     278             :     int i;
     279             : 
     280           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     281           0 :     if (NULL == svc) {
     282           0 :         return ENOENT;
     283             :     }
     284             : 
     285           0 :     domain = dp_opt_get_string(ctx->be_res->opts, DP_RES_OPT_DNS_DOMAIN);
     286           0 :     if (!domain) {
     287           0 :         domain = default_discovery_domain;
     288             :     }
     289             : 
     290             :     /* Add the first protocol as the primary lookup */
     291           0 :     ret = fo_add_srv_server(svc->fo_service, query_service,
     292           0 :                             domain, ctx->domain->name,
     293             :                             proto_table[proto], user_data);
     294           0 :     if (ret && ret != EEXIST) {
     295           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     296             :               "Failed to add SRV lookup reference to failover service "
     297             :               "[%d]: %s\n", ret, sss_strerror(ret));
     298           0 :         return ret;
     299             :     }
     300             : 
     301           0 :     if (proto_fallback) {
     302           0 :         i = (proto + 1) % BE_FO_PROTO_SENTINEL;
     303             :         /* All the rest as fallback */
     304           0 :         while (i != proto) {
     305           0 :             ret = fo_add_srv_server(svc->fo_service, query_service,
     306           0 :                                     domain, ctx->domain->name,
     307             :                                     proto_table[i], user_data);
     308           0 :             if (ret && ret != EEXIST) {
     309           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     310             :                       "Failed to add SRV lookup reference to failover "
     311             :                       "service [%d]: %s\n", ret, sss_strerror(ret));
     312           0 :                 return ret;
     313             :             }
     314             : 
     315           0 :             i = (i + 1) % BE_FO_PROTO_SENTINEL;
     316             :         }
     317             :     }
     318             : 
     319           0 :     return EOK;
     320             : }
     321             : 
     322           0 : int be_fo_get_server_count(struct be_ctx *ctx, const char *service_name)
     323             : {
     324             :     struct be_svc_data *svc_data;
     325             : 
     326           0 :     svc_data = be_fo_find_svc_data(ctx, service_name);
     327           0 :     if (!svc_data) {
     328           0 :         return 0;
     329             :     }
     330             : 
     331           0 :     return fo_get_server_count(svc_data->fo_service);
     332             : }
     333             : 
     334           0 : int be_fo_add_server(struct be_ctx *ctx, const char *service_name,
     335             :                      const char *server, int port, void *user_data,
     336             :                      bool primary)
     337             : {
     338             :     struct be_svc_data *svc;
     339             :     int ret;
     340             : 
     341           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     342           0 :     if (NULL == svc) {
     343           0 :         return ENOENT;
     344             :     }
     345             : 
     346           0 :     ret = fo_add_server(svc->fo_service, server, port,
     347             :                         user_data, primary);
     348           0 :     if (ret && ret != EEXIST) {
     349           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     350             :               "Failed to add server to failover service [%d]: %s\n",
     351             :               ret, sss_strerror(ret));
     352           0 :         return ret;
     353             :     }
     354             : 
     355           0 :     return EOK;
     356             : }
     357             : 
     358             : struct be_resolve_server_state {
     359             :     struct tevent_context *ev;
     360             :     struct be_ctx *ctx;
     361             : 
     362             :     struct be_svc_data *svc;
     363             :     int attempts;
     364             : 
     365             :     struct fo_server *srv;
     366             :     bool first_try;
     367             : };
     368             : 
     369             : struct be_primary_server_ctx {
     370             :     struct be_ctx *bctx;
     371             :     struct tevent_context *ev;
     372             : 
     373             :     struct be_svc_data *svc;
     374             :     unsigned long timeout;
     375             : 
     376             :     int attempts;
     377             : };
     378             : 
     379             : errno_t be_resolve_server_process(struct tevent_req *subreq,
     380             :                                   struct be_resolve_server_state *state,
     381             :                                   struct tevent_req **new_subreq);
     382             : static void be_primary_server_done(struct tevent_req *subreq);
     383             : static errno_t
     384             : be_primary_server_timeout_activate(TALLOC_CTX *mem_ctx,
     385             :                                    struct tevent_context *ev,
     386             :                                    struct be_ctx *bctx,
     387             :                                    struct be_svc_data *svc,
     388             :                                    const unsigned long timeout_seconds);
     389             : 
     390             : static void
     391           0 : be_primary_server_timeout(struct tevent_context *ev,
     392             :                           struct tevent_timer *te,
     393             :                           struct timeval tv, void *pvt)
     394             : {
     395           0 :     struct be_primary_server_ctx *ctx = talloc_get_type(pvt, struct be_primary_server_ctx);
     396             :     struct tevent_req *subreq;
     397             : 
     398           0 :     ctx->bctx->be_fo->primary_server_handler = NULL;
     399             : 
     400           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Looking for primary server!\n");
     401           0 :     subreq = fo_resolve_service_send(ctx->bctx, ctx->ev,
     402           0 :                                      ctx->bctx->be_fo->be_res->resolv,
     403           0 :                                      ctx->bctx->be_fo->fo_ctx,
     404           0 :                                      ctx->svc->fo_service);
     405           0 :     if (subreq == NULL) {
     406           0 :         return;
     407             :     }
     408           0 :     tevent_req_set_callback(subreq, be_primary_server_done, ctx);
     409             : }
     410             : 
     411           0 : static void be_primary_server_done(struct tevent_req *subreq)
     412             : {
     413             :     errno_t ret;
     414             :     struct be_primary_server_ctx *ctx;
     415             :     struct be_resolve_server_state *resolve_state;
     416             :     struct tevent_req *new_subreq;
     417             : 
     418           0 :     ctx = tevent_req_callback_data(subreq, struct be_primary_server_ctx);
     419             : 
     420           0 :     resolve_state = talloc_zero(ctx->bctx, struct be_resolve_server_state);
     421           0 :     if (resolve_state == NULL) {
     422           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero() failed\n");
     423           0 :         return;
     424             :     }
     425             : 
     426           0 :     resolve_state->attempts = ctx->attempts;
     427           0 :     resolve_state->ctx = ctx->bctx;
     428           0 :     resolve_state->ev = ctx->ev;
     429           0 :     resolve_state->first_try = true;
     430           0 :     resolve_state->srv = NULL;
     431           0 :     resolve_state->svc = ctx->svc;
     432             : 
     433           0 :     ret = be_resolve_server_process(subreq, resolve_state, &new_subreq);
     434           0 :     talloc_free(subreq);
     435           0 :     if (ret == EAGAIN) {
     436           0 :         ctx->attempts++;
     437           0 :         tevent_req_set_callback(new_subreq, be_primary_server_done, ctx);
     438           0 :         return;
     439           0 :     } else if (ret == EIO || (ret == EOK &&
     440           0 :         !fo_is_server_primary(resolve_state->srv))) {
     441             : 
     442             :         /* Schedule another lookup
     443             :          * (either no server could be found or it was not primary)
     444             :          */
     445           0 :         ret = be_primary_server_timeout_activate(ctx->bctx, ctx->ev, ctx->bctx,
     446             :                                                  ctx->svc, ctx->timeout);
     447           0 :         if (ret != EOK) {
     448           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     449             :                   "Could not schedule primary server lookup [%d]: %s\n",
     450             :                   ret, sss_strerror(ret));
     451             :         }
     452           0 :     } else if (ret == EOK) {
     453           0 :         be_run_reconnect_cb(ctx->bctx);
     454             :     }
     455           0 :     talloc_zfree(ctx);
     456             : 
     457             :     /* If an error occurred just end the routine */
     458             : }
     459             : 
     460             : static errno_t
     461           0 : be_primary_server_timeout_activate(TALLOC_CTX *mem_ctx,
     462             :                                    struct tevent_context *ev,
     463             :                                    struct be_ctx *bctx,
     464             :                                    struct be_svc_data *svc,
     465             :                                    const unsigned long timeout_seconds)
     466             : {
     467             :     struct timeval tv;
     468             :     struct be_primary_server_ctx *ctx;
     469           0 :     struct be_failover_ctx *fo_ctx = bctx->be_fo;
     470             : 
     471           0 :     if (fo_ctx->primary_server_handler != NULL) {
     472           0 :         DEBUG(SSSDBG_TRACE_FUNC, "The primary server reconnection "
     473             :                                   "is already scheduled\n");
     474           0 :         return EOK;
     475             :     }
     476             : 
     477           0 :     ctx = talloc_zero(mem_ctx, struct be_primary_server_ctx);
     478           0 :     if (ctx == NULL) {
     479           0 :         return ENOMEM;
     480             :     }
     481             : 
     482           0 :     ctx->bctx = bctx;
     483           0 :     ctx->ev = ev;
     484           0 :     ctx->svc = svc;
     485           0 :     ctx->timeout = timeout_seconds;
     486             : 
     487           0 :     tv = tevent_timeval_current();
     488           0 :     tv = tevent_timeval_add(&tv, timeout_seconds, 0);
     489           0 :     fo_ctx->primary_server_handler = tevent_add_timer(ev, bctx, tv,
     490             :                                           be_primary_server_timeout, ctx);
     491           0 :     if (fo_ctx->primary_server_handler == NULL) {
     492           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
     493           0 :         talloc_free(ctx);
     494           0 :         return ENOMEM;
     495             :     }
     496             : 
     497           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Primary server reactivation timeout set "
     498             :                                   "to %lu seconds\n", timeout_seconds);
     499           0 :     return EOK;
     500             : }
     501             : 
     502             : 
     503             : static void be_resolve_server_done(struct tevent_req *subreq);
     504             : 
     505           0 : struct tevent_req *be_resolve_server_send(TALLOC_CTX *memctx,
     506             :                                           struct tevent_context *ev,
     507             :                                           struct be_ctx *ctx,
     508             :                                           const char *service_name,
     509             :                                           bool first_try)
     510             : {
     511             :     struct tevent_req *req, *subreq;
     512             :     struct be_resolve_server_state *state;
     513             :     struct be_svc_data *svc;
     514             : 
     515           0 :     req = tevent_req_create(memctx, &state, struct be_resolve_server_state);
     516           0 :     if (!req) return NULL;
     517             : 
     518           0 :     state->ev = ev;
     519           0 :     state->ctx = ctx;
     520             : 
     521           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     522           0 :     if (NULL == svc) {
     523           0 :         tevent_req_error(req, EINVAL);
     524           0 :         tevent_req_post(req, ev);
     525           0 :         return req;
     526             :     }
     527             : 
     528           0 :     state->svc = svc;
     529           0 :     state->attempts = 0;
     530           0 :     state->first_try = first_try;
     531             : 
     532           0 :     subreq = fo_resolve_service_send(state, ev,
     533           0 :                                      ctx->be_fo->be_res->resolv,
     534           0 :                                      ctx->be_fo->fo_ctx,
     535             :                                      svc->fo_service);
     536           0 :     if (!subreq) {
     537           0 :         talloc_zfree(req);
     538           0 :         return NULL;
     539             :     }
     540           0 :     tevent_req_set_callback(subreq, be_resolve_server_done, req);
     541             : 
     542           0 :     return req;
     543             : }
     544             : 
     545           0 : static void be_resolve_server_done(struct tevent_req *subreq)
     546             : {
     547             :     struct tevent_req *new_subreq;
     548           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     549             :                                                       struct tevent_req);
     550           0 :     struct be_resolve_server_state *state = tevent_req_data(req,
     551             :                                              struct be_resolve_server_state);
     552           0 :     time_t timeout = fo_get_service_retry_timeout(state->svc->fo_service) + 1;
     553             :     int ret;
     554             : 
     555           0 :     ret = be_resolve_server_process(subreq, state, &new_subreq);
     556           0 :     talloc_zfree(subreq);
     557           0 :     if (ret == EAGAIN) {
     558           0 :         tevent_req_set_callback(new_subreq, be_resolve_server_done, req);
     559           0 :         return;
     560           0 :     } else if (ret != EOK) {
     561           0 :         goto fail;
     562             :     }
     563             : 
     564           0 :     if (!fo_is_server_primary(state->srv)) {
     565             :         /* FIXME: make the timeout configurable */
     566           0 :         ret = be_primary_server_timeout_activate(state->ctx, state->ev,
     567             :                                                  state->ctx, state->svc,
     568             :                                                  timeout);
     569           0 :         if (ret != EOK) {
     570           0 :             goto fail;
     571             :         }
     572             :     }
     573             : 
     574           0 :     tevent_req_done(req);
     575           0 :     return;
     576             : 
     577             : fail:
     578           0 :     DEBUG(SSSDBG_TRACE_LIBS,
     579             :           "Server resolution failed: [%d]: %s\n", ret, sss_strerror(ret));
     580           0 :     state->svc->first_resolved = NULL;
     581           0 :     tevent_req_error(req, ret);
     582             : }
     583             : 
     584           0 : errno_t be_resolve_server_process(struct tevent_req *subreq,
     585             :                                   struct be_resolve_server_state *state,
     586             :                                   struct tevent_req **new_subreq)
     587             : {
     588             :     errno_t ret;
     589             :     time_t srv_status_change;
     590             :     struct be_svc_callback *callback;
     591             : 
     592           0 :     ret = fo_resolve_service_recv(subreq, state, &state->srv);
     593           0 :     switch (ret) {
     594             :     case EOK:
     595           0 :         if (!state->srv) {
     596           0 :             return EFAULT;
     597             :         }
     598           0 :         break;
     599             : 
     600             :     case ENOENT:
     601             :         /* all servers have been tried and none
     602             :          * was found good, go offline */
     603           0 :         return EIO;
     604             : 
     605             :     default:
     606             :         /* mark server as bad and retry */
     607           0 :         if (!state->srv) {
     608           0 :             return EFAULT;
     609             :         }
     610           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     611             :               "Couldn't resolve server (%s), resolver returned [%d]: %s\n",
     612             :               fo_get_server_str_name(state->srv), ret, sss_strerror(ret));
     613             : 
     614           0 :         state->attempts++;
     615           0 :         if (state->attempts >= 10) {
     616           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to find a server after 10 attempts\n");
     617           0 :             return EIO;
     618             :         }
     619             : 
     620             :         /* now try next one */
     621           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Trying with the next one!\n");
     622           0 :         subreq = fo_resolve_service_send(state, state->ev,
     623           0 :                                          state->ctx->be_fo->be_res->resolv,
     624           0 :                                          state->ctx->be_fo->fo_ctx,
     625           0 :                                          state->svc->fo_service);
     626           0 :         if (!subreq) {
     627           0 :             return ENOMEM;
     628             :         }
     629             : 
     630           0 :         if (new_subreq) {
     631           0 :             *new_subreq = subreq;
     632             :         }
     633             : 
     634           0 :         return EAGAIN;
     635             :     }
     636             : 
     637             :     /* all fine we got the server */
     638           0 :     if (state->svc->first_resolved == NULL || state->first_try == true) {
     639           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Saving the first resolved server\n");
     640           0 :         state->svc->first_resolved = state->srv;
     641           0 :     } else if (state->svc->first_resolved == state->srv) {
     642           0 :         DEBUG(SSSDBG_OP_FAILURE,
     643             :               "The fail over cycled through all available servers\n");
     644           0 :         return ENOENT;
     645             :     }
     646             : 
     647           0 :     if (DEBUG_IS_SET(SSSDBG_FUNC_DATA) && fo_get_server_name(state->srv)) {
     648             :         struct resolv_hostent *srvaddr;
     649             :         char ipaddr[128];
     650           0 :         srvaddr = fo_get_server_hostent(state->srv);
     651           0 :         if (!srvaddr) {
     652           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     653             :                   "FATAL: No hostent available for server (%s)\n",
     654             :                   fo_get_server_str_name(state->srv));
     655           0 :             return EFAULT;
     656             :         }
     657             : 
     658           0 :         inet_ntop(srvaddr->family, srvaddr->addr_list[0]->ipaddr,
     659             :                   ipaddr, 128);
     660             : 
     661           0 :         DEBUG(SSSDBG_FUNC_DATA, "Found address for server %s: [%s] TTL %d\n",
     662             :               fo_get_server_str_name(state->srv), ipaddr,
     663             :               srvaddr->addr_list[0]->ttl);
     664             :     }
     665             : 
     666           0 :     srv_status_change = fo_get_server_hostname_last_change(state->srv);
     667             : 
     668             :     /* now call all svc callbacks if server changed or if it is explicitly
     669             :      * requested or if the server is the same but changed status since last time*/
     670           0 :     if (state->srv != state->svc->last_good_srv ||
     671           0 :         state->svc->run_callbacks ||
     672           0 :         srv_status_change > state->svc->last_status_change) {
     673           0 :         state->svc->last_good_srv = state->srv;
     674           0 :         state->svc->last_status_change = srv_status_change;
     675           0 :         state->svc->run_callbacks = false;
     676             : 
     677           0 :         DLIST_FOR_EACH(callback, state->svc->callbacks) {
     678           0 :             callback->fn(callback->private_data, state->srv);
     679             :         }
     680             :     }
     681             : 
     682           0 :     return EOK;
     683             : }
     684             : 
     685           0 : int be_resolve_server_recv(struct tevent_req *req,
     686             :                            TALLOC_CTX *ref_ctx,
     687             :                            struct fo_server **srv)
     688             : {
     689           0 :     struct be_resolve_server_state *state = tevent_req_data(req,
     690             :                                              struct be_resolve_server_state);
     691             : 
     692           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     693             : 
     694           0 :     if (srv) {
     695           0 :         fo_ref_server(ref_ctx, state->srv);
     696           0 :         *srv = state->srv;
     697             :     }
     698             : 
     699           0 :     return EOK;
     700             : }
     701             : 
     702           0 : void be_fo_try_next_server(struct be_ctx *ctx, const char *service_name)
     703             : {
     704             :     struct be_svc_data *svc;
     705             : 
     706           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     707           0 :     if (svc) {
     708           0 :         fo_try_next_server(svc->fo_service);
     709             :     }
     710           0 : }
     711             : 
     712           0 : const char *be_fo_get_active_server_name(struct be_ctx *ctx,
     713             :                                          const char *service_name)
     714             : {
     715             :     struct be_svc_data *svc;
     716             :     struct fo_server *server;
     717             : 
     718           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     719           0 :     if (svc != NULL) {
     720           0 :         server = fo_get_active_server(svc->fo_service);
     721           0 :         if (server != NULL) {
     722           0 :             return fo_get_server_name(server);
     723             :         }
     724             :     }
     725             : 
     726           0 :     return NULL;
     727             : }
     728             : 
     729           0 : int be_fo_run_callbacks_at_next_request(struct be_ctx *ctx,
     730             :                                         const char *service_name)
     731             : {
     732             :     struct be_svc_data *svc;
     733             : 
     734           0 :     svc = be_fo_find_svc_data(ctx, service_name);
     735           0 :     if (NULL == svc) {
     736           0 :         return ENOENT;
     737             :     }
     738             : 
     739           0 :     svc->run_callbacks = true;
     740             : 
     741           0 :     return EOK;
     742             : }
     743             : 
     744           0 : void reset_fo(struct be_ctx *be_ctx)
     745             : {
     746           0 :     fo_reset_services(be_ctx->be_fo->fo_ctx);
     747           0 : }
     748             : 
     749           0 : void be_fo_reset_svc(struct be_ctx *be_ctx,
     750             :                      const char *svc_name)
     751             : {
     752             :     struct fo_service *service;
     753             :     int ret;
     754             : 
     755           0 :     DEBUG(SSSDBG_TRACE_LIBS,
     756             :           "Resetting all servers in service %s\n", svc_name);
     757             : 
     758           0 :     ret = fo_get_service(be_ctx->be_fo->fo_ctx, svc_name, &service);
     759           0 :     if (ret != EOK) {
     760           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     761             :               "Cannot retrieve service [%s]\n", svc_name);
     762           0 :         return;
     763             :     }
     764             : 
     765           0 :     fo_reset_servers(service);
     766             : }
     767             : 
     768           0 : void _be_fo_set_port_status(struct be_ctx *ctx,
     769             :                             const char *service_name,
     770             :                             struct fo_server *server,
     771             :                             enum port_status status,
     772             :                             int line,
     773             :                             const char *file,
     774             :                             const char *function)
     775             : {
     776             :     struct be_svc_data *be_svc;
     777             : 
     778             :     /* Print debug info */
     779           0 :     switch (status) {
     780             :     case PORT_NEUTRAL:
     781           0 :         DEBUG(SSSDBG_BE_FO,
     782             :               "Setting status: PORT_NEUTRAL. Called from: %s: %s: %d\n",
     783             :               file, function, line);
     784           0 :         break;
     785             :     case PORT_WORKING:
     786           0 :         DEBUG(SSSDBG_BE_FO,
     787             :               "Setting status: PORT_WORKING. Called from: %s: %s: %d\n",
     788             :               file, function, line);
     789           0 :         break;
     790             :     case PORT_NOT_WORKING:
     791           0 :         DEBUG(SSSDBG_BE_FO,
     792             :               "Setting status: PORT_NOT_WORKING. Called from: %s: %s: %d\n",
     793             :               file, function, line);
     794           0 :         break;
     795             :     }
     796             : 
     797           0 :     be_svc = be_fo_find_svc_data(ctx, service_name);
     798           0 :     if (be_svc == NULL) {
     799           0 :         DEBUG(SSSDBG_OP_FAILURE,
     800             :               "No service associated with name %s\n", service_name);
     801           0 :         return;
     802             :     }
     803             : 
     804           0 :     if (!fo_svc_has_server(be_svc->fo_service, server)) {
     805           0 :         DEBUG(SSSDBG_OP_FAILURE,
     806             :               "The server %p is not valid anymore, cannot set its status\n",
     807             :                server);
     808           0 :         return;
     809             :     }
     810             : 
     811             :     /* Now we know that the server is valid */
     812           0 :     fo_set_port_status(server, status);
     813             : 
     814           0 :     if (status == PORT_WORKING) {
     815             :         /* We were successful in connecting to the server. Cycle through all
     816             :          * available servers next time */
     817           0 :         be_svc->first_resolved = NULL;
     818             :     }
     819             : }
     820             : 
     821             : /* Resolver back end interface */
     822             : static struct dp_option dp_res_default_opts[] = {
     823             :     { "lookup_family_order", DP_OPT_STRING, { "ipv4_first" }, NULL_STRING },
     824             :     { "dns_resolver_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
     825             :     { "dns_resolver_op_timeout", DP_OPT_NUMBER, { .number = 6 }, NULL_NUMBER },
     826             :     { "dns_discovery_domain", DP_OPT_STRING, NULL_STRING, NULL_STRING },
     827             :     DP_OPTION_TERMINATOR
     828             : };
     829             : 
     830           7 : static errno_t be_res_get_opts(struct be_resolv_ctx *res_ctx,
     831             :                                struct confdb_ctx *cdb,
     832             :                                const char *conf_path)
     833             : {
     834             :     errno_t ret;
     835             :     const char *str_family;
     836             : 
     837           7 :     ret = dp_get_options(res_ctx, cdb, conf_path,
     838             :                          dp_res_default_opts,
     839             :                          DP_RES_OPTS,
     840             :                          &res_ctx->opts);
     841           7 :     if (ret != EOK) {
     842           0 :         return ret;
     843             :     }
     844             : 
     845           7 :     str_family = dp_opt_get_string(res_ctx->opts, DP_RES_OPT_FAMILY_ORDER);
     846           7 :     DEBUG(SSSDBG_CONF_SETTINGS, "Lookup order: %s\n", str_family);
     847             : 
     848           7 :     if (strcasecmp(str_family, "ipv4_first") == 0) {
     849           7 :         res_ctx->family_order = IPV4_FIRST;
     850           0 :     } else if (strcasecmp(str_family, "ipv4_only") == 0) {
     851           0 :         res_ctx->family_order = IPV4_ONLY;
     852           0 :     } else if (strcasecmp(str_family, "ipv6_first") == 0) {
     853           0 :         res_ctx->family_order = IPV6_FIRST;
     854           0 :     } else if (strcasecmp(str_family, "ipv6_only") == 0) {
     855           0 :         res_ctx->family_order = IPV6_ONLY;
     856             :     } else {
     857           0 :         DEBUG(SSSDBG_OP_FAILURE, "Unknown value for option %s: %s\n",
     858             :               dp_res_default_opts[DP_RES_OPT_FAMILY_ORDER].opt_name, str_family);
     859           0 :         return EINVAL;
     860             :     }
     861             : 
     862           7 :     return EOK;
     863             : }
     864             : 
     865           7 : errno_t be_res_init(struct be_ctx *ctx)
     866             : {
     867             :     errno_t ret;
     868             : 
     869           7 :     if (ctx->be_res != NULL) {
     870           0 :         return EOK;
     871             :     }
     872             : 
     873           7 :     ctx->be_res = talloc_zero(ctx, struct be_resolv_ctx);
     874           7 :     if (!ctx->be_res) {
     875           0 :         return ENOMEM;
     876             :     }
     877             : 
     878           7 :     ret = be_res_get_opts(ctx->be_res, ctx->cdb, ctx->conf_path);
     879           7 :     if (ret != EOK) {
     880           0 :         talloc_zfree(ctx->be_res);
     881           0 :         return ret;
     882             :     }
     883             : 
     884          14 :     ret = resolv_init(ctx, ctx->ev,
     885           7 :                       dp_opt_get_int(ctx->be_res->opts,
     886             :                                      DP_RES_OPT_RESOLVER_OP_TIMEOUT),
     887           7 :                       &ctx->be_res->resolv);
     888           7 :     if (ret != EOK) {
     889           0 :         talloc_zfree(ctx->be_res);
     890           0 :         return ret;
     891             :     }
     892             : 
     893           7 :     return EOK;
     894             : }

Generated by: LCOV version 1.10