LCOV - code coverage report
Current view: top level - responder/common - responder_get_domains.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 145 243 59.7 %
Date: 2015-10-19 Functions: 14 15 93.3 %

          Line data    Source code
       1             : /*
       2             :     Authors:
       3             :         Jan Zeleny <jzeleny@redhat.com>
       4             : 
       5             :     Copyright (C) 2011 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 "util/util.h"
      22             : #include "responder/common/responder.h"
      23             : #include "providers/data_provider.h"
      24             : #include "db/sysdb.h"
      25             : 
      26             : /* ========== Get subdomains for a domain ================= */
      27             : static DBusMessage *sss_dp_get_domains_msg(void *pvt);
      28             : 
      29             : struct sss_dp_domains_info {
      30             :     struct sss_domain_info *dom;
      31             :     const char *hint;
      32             : };
      33             : 
      34             : static struct tevent_req *
      35           3 : get_subdomains_send(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx,
      36             :                     struct sss_domain_info *dom,
      37             :                     const char *hint)
      38             : {
      39             :     errno_t ret;
      40             :     struct tevent_req *req;
      41             :     struct sss_dp_req_state *state;
      42             :     struct sss_dp_domains_info *info;
      43             :     char *key;
      44             : 
      45           3 :     req = tevent_req_create(mem_ctx, &state, struct sss_dp_req_state);
      46           3 :     if (req == NULL) {
      47           0 :         return NULL;
      48             :     }
      49             : 
      50           3 :     info = talloc_zero(state, struct sss_dp_domains_info);
      51           3 :     if (!info) {
      52           0 :         ret = ENOMEM;
      53           0 :         goto fail;
      54             :     }
      55           3 :     info->hint = hint;
      56           3 :     info->dom = dom;
      57             : 
      58           3 :     key = talloc_asprintf(state, "domains@%s", dom->name);
      59           3 :     if (key == NULL) {
      60           0 :         ret = ENOMEM;
      61           0 :         goto fail;
      62             :     }
      63             : 
      64           3 :     ret = sss_dp_issue_request(state, rctx, key, dom,
      65             :                                sss_dp_get_domains_msg, info, req);
      66           3 :     talloc_free(key);
      67           3 :     if (ret != EOK) {
      68           0 :         ret = EIO;
      69           0 :         goto fail;
      70             :     }
      71             : 
      72           3 :     return req;
      73             : 
      74             : fail:
      75           0 :     tevent_req_error(req, ret);
      76           0 :     tevent_req_post(req, rctx->ev);
      77           0 :     return req;
      78             : }
      79             : 
      80             : static DBusMessage *
      81           0 : sss_dp_get_domains_msg(void *pvt)
      82             : {
      83             :     struct sss_dp_domains_info *info;
      84           0 :     DBusMessage *msg = NULL;
      85             :     dbus_bool_t dbret;
      86             : 
      87           0 :     info = talloc_get_type(pvt, struct sss_dp_domains_info);
      88             : 
      89           0 :     msg = dbus_message_new_method_call(NULL,
      90             :                                        DP_PATH,
      91             :                                        DATA_PROVIDER_IFACE,
      92             :                                        DATA_PROVIDER_IFACE_GETDOMAINS);
      93           0 :     if (msg == NULL) {
      94           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
      95           0 :         return NULL;
      96             :     }
      97             : 
      98           0 :     DEBUG(SSSDBG_TRACE_FUNC,
      99             :           "Sending get domains request for [%s][%s]\n",
     100             :            info->dom->name, info->hint);
     101             : 
     102             :     /* Send the hint argument to provider as well. This will
     103             :      * be useful for some cases of transitional trust where
     104             :      * the server might not know all trusted domains
     105             :      */
     106           0 :     dbret = dbus_message_append_args(msg,
     107             :                                      DBUS_TYPE_STRING, &info->hint,
     108             :                                      DBUS_TYPE_INVALID);
     109           0 :     if (!dbret) {
     110           0 :         DEBUG(SSSDBG_OP_FAILURE ,"Failed to build message\n");
     111           0 :         dbus_message_unref(msg);
     112           0 :         return NULL;
     113             :     }
     114             : 
     115           0 :     return msg;
     116             : }
     117             : 
     118             : static errno_t
     119           3 : get_next_domain_recv(TALLOC_CTX *mem_ctx,
     120             :                      struct tevent_req *req,
     121             :                      dbus_uint16_t *dp_err,
     122             :                      dbus_uint32_t *dp_ret,
     123             :                      char **err_msg)
     124             : {
     125           3 :     return sss_dp_req_recv(mem_ctx, req, dp_err, dp_ret, err_msg);
     126             : }
     127             : 
     128             : /* ====== Iterate over all domains, searching for their subdomains  ======= */
     129             : static errno_t process_subdomains(struct sss_domain_info *dom);
     130             : static void set_time_of_last_request(struct resp_ctx *rctx);
     131             : static errno_t check_last_request(struct resp_ctx *rctx, const char *hint);
     132             : 
     133             : struct sss_dp_get_domains_state {
     134             :     struct resp_ctx *rctx;
     135             :     struct sss_domain_info *dom;
     136             :     const char *hint;
     137             : };
     138             : 
     139             : static void
     140             : sss_dp_get_domains_process(struct tevent_req *subreq);
     141             : 
     142           3 : struct tevent_req *sss_dp_get_domains_send(TALLOC_CTX *mem_ctx,
     143             :                                            struct resp_ctx *rctx,
     144             :                                            bool force,
     145             :                                            const char *hint)
     146             : {
     147             :     errno_t ret;
     148             :     struct tevent_req *req;
     149             :     struct tevent_req *subreq;
     150             :     struct sss_dp_get_domains_state *state;
     151             : 
     152           3 :     req = tevent_req_create(mem_ctx, &state, struct sss_dp_get_domains_state);
     153           3 :     if (req == NULL) {
     154           0 :          return NULL;
     155             :     }
     156             : 
     157           3 :     if (rctx->domains == NULL) {
     158           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "No domains configured.\n");
     159           0 :         ret = EINVAL;
     160           0 :         goto immediately;
     161             :     }
     162             : 
     163           3 :     if (!force) {
     164           2 :         ret = check_last_request(rctx, hint);
     165           2 :         if (ret == EOK) {
     166           0 :             DEBUG(SSSDBG_TRACE_FUNC,
     167             :                   "Last call was too recent, nothing to do!\n");
     168           0 :             goto immediately;
     169           2 :         } else if (ret != EAGAIN) {
     170           0 :             DEBUG(SSSDBG_TRACE_FUNC, "check_domain_request failed with [%d][%s]\n",
     171             :                                       ret, strerror(ret));
     172           0 :             goto immediately;
     173             :         }
     174             :     }
     175             : 
     176           3 :     state->rctx = rctx;
     177           3 :     if (hint != NULL) {
     178           0 :         state->hint = hint;
     179             :     } else {
     180           3 :         state->hint = talloc_strdup(state, "");
     181           3 :         if (state->hint == NULL) {
     182           0 :             ret = ENOMEM;
     183           0 :             goto immediately;
     184             :         }
     185             :     }
     186             : 
     187           3 :     state->dom = rctx->domains;
     188           6 :     while(state->dom != NULL && !NEED_CHECK_PROVIDER(state->dom->provider)) {
     189           0 :         state->dom = get_next_domain(state->dom, false);
     190             :     }
     191             : 
     192           3 :     if (state->dom == NULL) {
     193             :         /* All domains were local */
     194           0 :         ret = EOK;
     195           0 :         goto immediately;
     196             :     }
     197             : 
     198           3 :     subreq = get_subdomains_send(req, rctx, state->dom, state->hint);
     199           3 :     if (subreq == NULL) {
     200           0 :         ret = ENOMEM;
     201           0 :         goto immediately;
     202             :     }
     203           3 :     tevent_req_set_callback(subreq, sss_dp_get_domains_process, req);
     204             : 
     205           3 :     return req;
     206             : 
     207             : immediately:
     208           0 :     if (ret == EOK) {
     209           0 :         set_time_of_last_request(rctx);
     210           0 :         tevent_req_done(req);
     211             :     } else {
     212           0 :         tevent_req_error(req, ret);
     213             :     }
     214           0 :     tevent_req_post(req, rctx->ev);
     215             : 
     216           0 :     return req;
     217             : }
     218             : 
     219             : static void
     220           3 : sss_dp_get_domains_process(struct tevent_req *subreq)
     221             : {
     222             :     errno_t ret;
     223           3 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     224             :                                                       struct tevent_req);
     225           3 :     struct sss_dp_get_domains_state *state = tevent_req_data(req,
     226             :                                                 struct sss_dp_get_domains_state);
     227             :     dbus_uint16_t dp_err;
     228             :     dbus_uint32_t dp_ret;
     229             :     char *err_msg;
     230             : 
     231           3 :     ret = get_next_domain_recv(req, subreq, &dp_err, &dp_ret, &err_msg);
     232           3 :     talloc_zfree(subreq);
     233           3 :     if (ret != EOK) {
     234           0 :         goto fail;
     235             :     }
     236             : 
     237           3 :     ret = process_subdomains(state->dom);
     238           3 :     if (ret != EOK) {
     239           0 :         DEBUG(SSSDBG_OP_FAILURE, "process_subdomains failed, "
     240             :                                   "trying next domain.\n");
     241           0 :         goto fail;
     242             :     }
     243             : 
     244             :     /* Advance to the next domain */
     245           3 :     state->dom = get_next_domain(state->dom, false);
     246             : 
     247             :     /* Skip local domains */
     248           6 :     while(state->dom != NULL && !NEED_CHECK_PROVIDER(state->dom->provider)) {
     249           0 :         state->dom = get_next_domain(state->dom, false);
     250             :     }
     251             : 
     252           3 :     if (state->dom == NULL) {
     253             :         /* All domains were local */
     254           3 :         set_time_of_last_request(state->rctx);
     255           3 :         tevent_req_done(req);
     256           3 :         return;
     257             :     }
     258             : 
     259           0 :     subreq = get_subdomains_send(req, state->rctx, state->dom, state->hint);
     260           0 :     if (subreq == NULL) {
     261           0 :         ret = ENOMEM;
     262           0 :         goto fail;
     263             :     }
     264           0 :     tevent_req_set_callback(subreq, sss_dp_get_domains_process, req);
     265           0 :     return;
     266             : 
     267             : fail:
     268           0 :     tevent_req_error(req, ret);
     269           0 :     return;
     270             : }
     271             : 
     272             : static errno_t
     273           3 : process_subdomains(struct sss_domain_info *domain)
     274             : {
     275             :     int ret;
     276             : 
     277           3 :     if (domain->realm == NULL ||
     278           0 :         domain->flat_name == NULL ||
     279           0 :         domain->domain_id == NULL) {
     280           3 :         ret = sysdb_master_domain_update(domain);
     281           3 :         if (ret != EOK) {
     282           0 :                 DEBUG(SSSDBG_FUNC_DATA, "sysdb_master_domain_get_info " \
     283             :                                          "failed.\n");
     284           0 :                 goto done;
     285             :         }
     286             :     }
     287             : 
     288             :     /* Retrieve all subdomains of this domain from sysdb
     289             :      * and create their struct sss_domain_info representations
     290             :      */
     291           3 :     ret = sysdb_update_subdomains(domain);
     292           3 :     if (ret != EOK) {
     293           0 :         DEBUG(SSSDBG_FUNC_DATA, "sysdb_update_subdomains failed.\n");
     294           0 :         goto done;
     295             :     }
     296             : 
     297           3 :     errno = 0;
     298           3 :     ret = gettimeofday(&domain->subdomains_last_checked, NULL);
     299           3 :     if (ret == -1) {
     300           0 :         ret = errno;
     301           0 :         goto done;
     302             :     }
     303             : 
     304           3 :     ret = EOK;
     305             : 
     306             : done:
     307           3 :     if (ret != EOK) {
     308           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to update sub-domains "
     309             :                                   "of domain [%s].\n", domain->name);
     310             :     }
     311             : 
     312           3 :     return ret;
     313             : }
     314             : 
     315           3 : errno_t sss_dp_get_domains_recv(struct tevent_req *req)
     316             : {
     317           3 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     318             : 
     319           3 :     return EOK;
     320             : }
     321             : 
     322           3 : static void set_time_of_last_request(struct resp_ctx *rctx)
     323             : {
     324             :     int ret;
     325             : 
     326           3 :     errno = 0;
     327           3 :     ret = gettimeofday(&rctx->get_domains_last_call, NULL);
     328           3 :     if (ret == -1) {
     329           0 :         ret = errno;
     330           0 :         DEBUG(SSSDBG_TRACE_FUNC, "gettimeofday failed [%d][%s].\n",
     331             :                                   ret, strerror(ret));
     332             :     }
     333           3 : }
     334             : 
     335           2 : static errno_t check_last_request(struct resp_ctx *rctx, const char *hint)
     336             : {
     337             :     struct sss_domain_info *dom;
     338           2 :     time_t now = time(NULL);
     339             :     time_t diff;
     340             : 
     341           2 :     diff = now - rctx->get_domains_last_call.tv_sec;
     342           2 :     if (diff >= rctx->domains_timeout) {
     343             :         /* Timeout, expired, fetch domains again */
     344           2 :         return EAGAIN;
     345             :     }
     346             : 
     347           0 :     if (hint != NULL) {
     348           0 :         for (dom = rctx->domains; dom; dom = get_next_domain(dom, true)) {
     349           0 :             if (!IS_SUBDOMAIN(dom)) {
     350           0 :                 diff = now - dom->subdomains_last_checked.tv_sec;
     351             :                 /* not a subdomain */
     352           0 :                 continue;
     353             :             }
     354           0 :             if (strcasecmp(dom->name, hint) == 0) {
     355           0 :                 if (diff >= rctx->domains_timeout) {
     356             :                     /* Timeout, expired, fetch domains again */
     357           0 :                     return EAGAIN;
     358             :                 }
     359             :             }
     360             :         }
     361             :     }
     362             : 
     363           0 :     return EOK;
     364             : }
     365             : 
     366             : struct get_domains_state {
     367             :     struct resp_ctx *rctx;
     368             :     struct sss_nc_ctx *optional_ncache;
     369             : };
     370             : 
     371           1 : static void get_domains_at_startup_done(struct tevent_req *req)
     372             : {
     373             :     int ret;
     374             :     struct get_domains_state *state;
     375             : 
     376           1 :     state = tevent_req_callback_data(req, struct get_domains_state);
     377             : 
     378           1 :     ret = sss_dp_get_domains_recv(req);
     379           1 :     talloc_free(req);
     380           1 :     if (ret != EOK) {
     381           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "sss_dp_get_domains request failed.\n");
     382             :     }
     383             : 
     384           1 :     if (state->optional_ncache != NULL) {
     385           1 :         ret = sss_ncache_reset_repopulate_permanent(state->rctx,
     386             :                                                     state->optional_ncache);
     387           1 :         if (ret != EOK) {
     388           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "sss_dp_get_domains request failed.\n");
     389             :         }
     390             :     }
     391             : 
     392           1 :     talloc_free(state);
     393           1 :     return;
     394             : }
     395             : 
     396           1 : static void get_domains_at_startup(struct tevent_context *ev,
     397             :                                    struct tevent_immediate *imm,
     398             :                                    void *pvt)
     399             : {
     400             :     struct tevent_req *req;
     401             :     struct get_domains_state *state;
     402             : 
     403           1 :     state = talloc_get_type(pvt, struct get_domains_state);
     404             : 
     405           1 :     req = sss_dp_get_domains_send(state, state->rctx, true, NULL);
     406           1 :     if (req == NULL) {
     407           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_dp_get_domains_send failed.\n");
     408           0 :         talloc_free(state);
     409           0 :         return;
     410             :     }
     411             : 
     412           1 :     tevent_req_set_callback(req, get_domains_at_startup_done, state);
     413           1 :     return;
     414             : }
     415             : 
     416           1 : errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx,
     417             :                                   struct tevent_context *ev,
     418             :                                   struct resp_ctx *rctx,
     419             :                                   struct sss_nc_ctx *optional_ncache)
     420             : {
     421             :     struct tevent_immediate *imm;
     422             :     struct get_domains_state *state;
     423             : 
     424           1 :     state = talloc(mem_ctx, struct get_domains_state);
     425           1 :     if (state == NULL) {
     426           0 :         return ENOMEM;
     427             :     }
     428           1 :     state->rctx = rctx;
     429           1 :     state->optional_ncache = optional_ncache;
     430             : 
     431           1 :     imm = tevent_create_immediate(mem_ctx);
     432           1 :     if (imm == NULL) {
     433           0 :         DEBUG(SSSDBG_OP_FAILURE, "tevent_create_immediate failed.\n");
     434           0 :         talloc_free(state);
     435           0 :         return ENOMEM;
     436             :     }
     437             : 
     438           1 :     tevent_schedule_immediate(imm, ev, get_domains_at_startup, state);
     439             : 
     440           1 :     return EOK;
     441             : }
     442             : 
     443             : struct sss_parse_inp_state {
     444             :     struct resp_ctx *rctx;
     445             :     const char *rawinp;
     446             : 
     447             :     char *name;
     448             :     char *domname;
     449             :     errno_t error;
     450             : };
     451             : 
     452             : static void sss_parse_inp_done(struct tevent_req *subreq);
     453             : 
     454             : struct tevent_req *
     455           4 : sss_parse_inp_send(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx,
     456             :                    const char *rawinp)
     457             : {
     458             :     errno_t ret;
     459             :     struct tevent_req *req;
     460             :     struct tevent_req *subreq;
     461             :     struct sss_parse_inp_state *state;
     462             : 
     463           4 :     req = tevent_req_create(mem_ctx, &state, struct sss_parse_inp_state);
     464           4 :     if (req == NULL) {
     465           0 :          return NULL;
     466             :     }
     467           4 :     state->rawinp = rawinp;
     468           4 :     state->rctx = rctx;
     469             : 
     470             :     /* If the subdomains haven't been checked yet, we need to always
     471             :      * attach to the post-startup subdomain request and only then parse
     472             :      * the input. Otherwise, we might not be able to parse input with a
     473             :      * flat domain name specifier */
     474           4 :     if (rctx->get_domains_last_call.tv_sec > 0) {
     475           9 :         ret = sss_parse_name_for_domains(state, rctx->domains,
     476           3 :                                          rctx->default_domain, rawinp,
     477           6 :                                          &state->domname, &state->name);
     478           3 :         if (ret == EOK) {
     479             :             /* Was able to use cached domains */
     480           1 :             goto done;
     481           2 :         } else if (ret != EAGAIN) {
     482           1 :             DEBUG(SSSDBG_OP_FAILURE, "Invalid name received [%s]\n", rawinp);
     483           1 :             ret = ERR_INPUT_PARSE;
     484           1 :             goto done;
     485             :         }
     486             :     }
     487             : 
     488             :     /* EAGAIN - check the DP for subdomains */
     489             : 
     490           2 :     DEBUG(SSSDBG_FUNC_DATA, "Requesting info for [%s] from [%s]\n",
     491             :           state->name, state->domname ? state->domname : "<ALL>");
     492             : 
     493             :     /* We explicitly use force=false here. This request should decide itself
     494             :      * if it's time to re-use the cached subdomain list or refresh. If the
     495             :      * caller needs to specify the 'force' parameter, they should use the
     496             :      * sss_dp_get_domains_send() request itself
     497             :      */
     498           2 :     subreq = sss_dp_get_domains_send(state, rctx, false, state->domname);
     499           2 :     if (subreq == NULL) {
     500           0 :         ret = ENOMEM;
     501           0 :         goto done;
     502             :     }
     503           2 :     tevent_req_set_callback(subreq, sss_parse_inp_done, req);
     504           2 :     return req;
     505             : 
     506             : done:
     507           2 :     if (ret == EOK) {
     508           1 :         tevent_req_done(req);
     509             :     } else {
     510           1 :         tevent_req_error(req, ret);
     511             :     }
     512           2 :     tevent_req_post(req, rctx->ev);
     513           2 :     return req;
     514             : }
     515             : 
     516           2 : static void sss_parse_inp_done(struct tevent_req *subreq)
     517             : {
     518             :     errno_t ret;
     519           2 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     520             :                                                       struct tevent_req);
     521           2 :     struct sss_parse_inp_state *state = tevent_req_data(req,
     522             :                                                 struct sss_parse_inp_state);
     523             : 
     524           2 :     ret = sss_dp_get_domains_recv(subreq);
     525           2 :     talloc_free(subreq);
     526           2 :     if (ret != EOK) {
     527           0 :         tevent_req_error(req, ret);
     528           0 :         return;
     529             :     }
     530             : 
     531           2 :     state->error = ERR_OK;
     532             : 
     533           4 :     ret = sss_parse_name_for_domains(state, state->rctx->domains,
     534           2 :                                      state->rctx->default_domain,
     535             :                                      state->rawinp,
     536             :                                      &state->domname, &state->name);
     537           2 :     if (ret == EAGAIN && state->domname != NULL && state->name == NULL) {
     538           0 :         DEBUG(SSSDBG_OP_FAILURE,
     539             :               "Unknown domain in [%s]\n", state->rawinp);
     540           0 :         state->error = ERR_DOMAIN_NOT_FOUND;
     541           2 :     } else if (ret != EOK) {
     542           0 :         DEBUG(SSSDBG_OP_FAILURE,
     543             :               "Invalid name received [%s]\n", state->rawinp);
     544           0 :         state->error = ERR_INPUT_PARSE;
     545             :     }
     546             : 
     547           2 :     if (state->error != ERR_OK) {
     548           0 :         tevent_req_error(req, state->error);
     549           0 :         return;
     550             :     }
     551             : 
     552             :     /* Was able to parse the name now */
     553           2 :     tevent_req_done(req);
     554             : }
     555             : 
     556           4 : errno_t sss_parse_inp_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     557             :                            char **_name, char **_domname)
     558             : {
     559           4 :     struct sss_parse_inp_state *state = tevent_req_data(req,
     560             :                                                 struct sss_parse_inp_state);
     561             : 
     562           4 :     if (state->error != ERR_DOMAIN_NOT_FOUND) {
     563           4 :         TEVENT_REQ_RETURN_ON_ERROR(req);
     564             :     }
     565             : 
     566           3 :     if (_name) {
     567           3 :         *_name = talloc_steal(mem_ctx, state->name);
     568             :     }
     569             : 
     570           3 :     if (_domname) {
     571           3 :         *_domname = talloc_steal(mem_ctx, state->domname);
     572             :     }
     573             : 
     574           3 :     return state->error;
     575             : }

Generated by: LCOV version 1.10