LCOV - code coverage report
Current view: top level - responder/common - responder_get_domains.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 158 244 64.8 %
Date: 2016-06-29 Functions: 15 15 100.0 %

          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           3 :         ret = EIO;
      69           3 :         goto fail;
      70             :     }
      71             : 
      72           0 :     return req;
      73             : 
      74             : fail:
      75           3 :     tevent_req_error(req, ret);
      76           3 :     tevent_req_post(req, rctx->ev);
      77           3 :     return req;
      78             : }
      79             : 
      80             : static DBusMessage *
      81           3 : sss_dp_get_domains_msg(void *pvt)
      82             : {
      83             :     struct sss_dp_domains_info *info;
      84           3 :     DBusMessage *msg = NULL;
      85             :     dbus_bool_t dbret;
      86             : 
      87           3 :     info = talloc_get_type(pvt, struct sss_dp_domains_info);
      88             : 
      89           3 :     msg = dbus_message_new_method_call(NULL,
      90             :                                        DP_PATH,
      91             :                                        DATA_PROVIDER_IFACE,
      92             :                                        DATA_PROVIDER_IFACE_GETDOMAINS);
      93           3 :     if (msg == NULL) {
      94           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Out of memory?!\n");
      95           0 :         return NULL;
      96             :     }
      97             : 
      98           3 :     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           3 :     dbret = dbus_message_append_args(msg,
     107             :                                      DBUS_TYPE_STRING, &info->hint,
     108             :                                      DBUS_TYPE_INVALID);
     109           3 :     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           3 :     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, 0);
     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, 0);
     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, 0);
     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;
     349           0 :                 dom = get_next_domain(dom, SSS_GND_DESCEND)) {
     350           0 :             if (!IS_SUBDOMAIN(dom)) {
     351           0 :                 diff = now - dom->subdomains_last_checked.tv_sec;
     352             :                 /* not a subdomain */
     353           0 :                 continue;
     354             :             }
     355           0 :             if (strcasecmp(dom->name, hint) == 0) {
     356           0 :                 if (diff >= rctx->domains_timeout) {
     357             :                     /* Timeout, expired, fetch domains again */
     358           0 :                     return EAGAIN;
     359             :                 }
     360             :             }
     361             :         }
     362             :     }
     363             : 
     364           0 :     return EOK;
     365             : }
     366             : 
     367             : struct get_domains_state {
     368             :     struct resp_ctx *rctx;
     369             :     struct sss_nc_ctx *optional_ncache;
     370             : };
     371             : 
     372           1 : static void get_domains_at_startup_done(struct tevent_req *req)
     373             : {
     374             :     int ret;
     375             :     struct get_domains_state *state;
     376             : 
     377           1 :     state = tevent_req_callback_data(req, struct get_domains_state);
     378             : 
     379           1 :     ret = sss_dp_get_domains_recv(req);
     380           1 :     talloc_free(req);
     381           1 :     if (ret != EOK) {
     382           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "sss_dp_get_domains request failed.\n");
     383             :     }
     384             : 
     385           1 :     if (state->optional_ncache != NULL) {
     386           1 :         ret = sss_ncache_reset_repopulate_permanent(state->rctx,
     387             :                                                     state->optional_ncache);
     388           1 :         if (ret != EOK) {
     389           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "sss_dp_get_domains request failed.\n");
     390             :         }
     391             :     }
     392             : 
     393           1 :     talloc_free(state);
     394           1 :     return;
     395             : }
     396             : 
     397           1 : static void get_domains_at_startup(struct tevent_context *ev,
     398             :                                    struct tevent_immediate *imm,
     399             :                                    void *pvt)
     400             : {
     401             :     struct tevent_req *req;
     402             :     struct get_domains_state *state;
     403             : 
     404           1 :     state = talloc_get_type(pvt, struct get_domains_state);
     405             : 
     406           1 :     req = sss_dp_get_domains_send(state, state->rctx, true, NULL);
     407           1 :     if (req == NULL) {
     408           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_dp_get_domains_send failed.\n");
     409           0 :         talloc_free(state);
     410           0 :         return;
     411             :     }
     412             : 
     413           1 :     tevent_req_set_callback(req, get_domains_at_startup_done, state);
     414           1 :     return;
     415             : }
     416             : 
     417           1 : errno_t schedule_get_domains_task(TALLOC_CTX *mem_ctx,
     418             :                                   struct tevent_context *ev,
     419             :                                   struct resp_ctx *rctx,
     420             :                                   struct sss_nc_ctx *optional_ncache)
     421             : {
     422             :     struct tevent_immediate *imm;
     423             :     struct get_domains_state *state;
     424             : 
     425           1 :     state = talloc(mem_ctx, struct get_domains_state);
     426           1 :     if (state == NULL) {
     427           0 :         return ENOMEM;
     428             :     }
     429           1 :     state->rctx = rctx;
     430           1 :     state->optional_ncache = optional_ncache;
     431             : 
     432           1 :     imm = tevent_create_immediate(mem_ctx);
     433           1 :     if (imm == NULL) {
     434           0 :         DEBUG(SSSDBG_OP_FAILURE, "tevent_create_immediate failed.\n");
     435           0 :         talloc_free(state);
     436           0 :         return ENOMEM;
     437             :     }
     438             : 
     439           1 :     tevent_schedule_immediate(imm, ev, get_domains_at_startup, state);
     440             : 
     441           1 :     return EOK;
     442             : }
     443             : 
     444             : struct sss_parse_inp_state {
     445             :     struct resp_ctx *rctx;
     446             :     const char *rawinp;
     447             : 
     448             :     char *name;
     449             :     char *domname;
     450             :     errno_t error;
     451             : };
     452             : 
     453             : static void sss_parse_inp_done(struct tevent_req *subreq);
     454             : 
     455             : struct tevent_req *
     456           4 : sss_parse_inp_send(TALLOC_CTX *mem_ctx, struct resp_ctx *rctx,
     457             :                    const char *rawinp)
     458             : {
     459             :     errno_t ret;
     460             :     struct tevent_req *req;
     461             :     struct tevent_req *subreq;
     462             :     struct sss_parse_inp_state *state;
     463             : 
     464           4 :     req = tevent_req_create(mem_ctx, &state, struct sss_parse_inp_state);
     465           4 :     if (req == NULL) {
     466           0 :          return NULL;
     467             :     }
     468           4 :     state->rawinp = rawinp;
     469           4 :     state->rctx = rctx;
     470             : 
     471             :     /* If the subdomains haven't been checked yet, we need to always
     472             :      * attach to the post-startup subdomain request and only then parse
     473             :      * the input. Otherwise, we might not be able to parse input with a
     474             :      * flat domain name specifier */
     475           4 :     if (rctx->get_domains_last_call.tv_sec > 0) {
     476           9 :         ret = sss_parse_name_for_domains(state, rctx->domains,
     477           3 :                                          rctx->default_domain, rawinp,
     478           6 :                                          &state->domname, &state->name);
     479           3 :         if (ret == EOK) {
     480             :             /* Was able to use cached domains */
     481           1 :             goto done;
     482           2 :         } else if (ret != EAGAIN) {
     483           1 :             DEBUG(SSSDBG_OP_FAILURE, "Invalid name received [%s]\n", rawinp);
     484           1 :             ret = ERR_INPUT_PARSE;
     485           1 :             goto done;
     486             :         }
     487             :     }
     488             : 
     489             :     /* EAGAIN - check the DP for subdomains */
     490             : 
     491           2 :     DEBUG(SSSDBG_FUNC_DATA, "Requesting info for [%s] from [%s]\n",
     492             :           state->name, state->domname ? state->domname : "<ALL>");
     493             : 
     494             :     /* We explicitly use force=false here. This request should decide itself
     495             :      * if it's time to re-use the cached subdomain list or refresh. If the
     496             :      * caller needs to specify the 'force' parameter, they should use the
     497             :      * sss_dp_get_domains_send() request itself
     498             :      */
     499           2 :     subreq = sss_dp_get_domains_send(state, rctx, false, state->domname);
     500           2 :     if (subreq == NULL) {
     501           0 :         ret = ENOMEM;
     502           0 :         goto done;
     503             :     }
     504           2 :     tevent_req_set_callback(subreq, sss_parse_inp_done, req);
     505           2 :     return req;
     506             : 
     507             : done:
     508           2 :     if (ret == EOK) {
     509           1 :         tevent_req_done(req);
     510             :     } else {
     511           1 :         tevent_req_error(req, ret);
     512             :     }
     513           2 :     tevent_req_post(req, rctx->ev);
     514           2 :     return req;
     515             : }
     516             : 
     517           2 : static void sss_parse_inp_done(struct tevent_req *subreq)
     518             : {
     519             :     errno_t ret;
     520           2 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     521             :                                                       struct tevent_req);
     522           2 :     struct sss_parse_inp_state *state = tevent_req_data(req,
     523             :                                                 struct sss_parse_inp_state);
     524             : 
     525           2 :     ret = sss_dp_get_domains_recv(subreq);
     526           2 :     talloc_free(subreq);
     527           2 :     if (ret != EOK) {
     528           0 :         tevent_req_error(req, ret);
     529           0 :         return;
     530             :     }
     531             : 
     532           2 :     state->error = ERR_OK;
     533             : 
     534           4 :     ret = sss_parse_name_for_domains(state, state->rctx->domains,
     535           2 :                                      state->rctx->default_domain,
     536             :                                      state->rawinp,
     537             :                                      &state->domname, &state->name);
     538           2 :     if (ret == EAGAIN && state->domname != NULL && state->name == NULL) {
     539           0 :         DEBUG(SSSDBG_OP_FAILURE,
     540             :               "Unknown domain in [%s]\n", state->rawinp);
     541           0 :         state->error = ERR_DOMAIN_NOT_FOUND;
     542           2 :     } else if (ret != EOK) {
     543           0 :         DEBUG(SSSDBG_OP_FAILURE,
     544             :               "Invalid name received [%s]\n", state->rawinp);
     545           0 :         state->error = ERR_INPUT_PARSE;
     546             :     }
     547             : 
     548           2 :     if (state->error != ERR_OK) {
     549           0 :         tevent_req_error(req, state->error);
     550           0 :         return;
     551             :     }
     552             : 
     553             :     /* Was able to parse the name now */
     554           2 :     tevent_req_done(req);
     555             : }
     556             : 
     557           4 : errno_t sss_parse_inp_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     558             :                            char **_name, char **_domname)
     559             : {
     560           4 :     struct sss_parse_inp_state *state = tevent_req_data(req,
     561             :                                                 struct sss_parse_inp_state);
     562             : 
     563           4 :     if (state->error != ERR_DOMAIN_NOT_FOUND) {
     564           4 :         TEVENT_REQ_RETURN_ON_ERROR(req);
     565             :     }
     566             : 
     567           3 :     if (_name) {
     568           3 :         *_name = talloc_steal(mem_ctx, state->name);
     569             :     }
     570             : 
     571           3 :     if (_domname) {
     572           3 :         *_domname = talloc_steal(mem_ctx, state->domname);
     573             :     }
     574             : 
     575           3 :     return state->error;
     576             : }

Generated by: LCOV version 1.10