LCOV - code coverage report
Current view: top level - providers/ad - ad_id.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 459 0.0 %
Date: 2015-10-19 Functions: 0 20 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Authors:
       5             :         Stephen Gallagher <sgallagh@redhat.com>
       6             : 
       7             :     Copyright (C) 2012 Red Hat
       8             : 
       9             :     This program is free software; you can redistribute it and/or modify
      10             :     it under the terms of the GNU General Public License as published by
      11             :     the Free Software Foundation; either version 3 of the License, or
      12             :     (at your option) any later version.
      13             : 
      14             :     This program is distributed in the hope that it will be useful,
      15             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :     GNU General Public License for more details.
      18             : 
      19             :     You should have received a copy of the GNU General Public License
      20             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : #include "util/util.h"
      23             : #include "util/strtonum.h"
      24             : #include "providers/ad/ad_common.h"
      25             : #include "providers/ad/ad_id.h"
      26             : #include "providers/ad/ad_domain_info.h"
      27             : #include "providers/ldap/sdap_async_enum.h"
      28             : #include "providers/ldap/sdap_idmap.h"
      29             : 
      30             : static void
      31           0 : disable_gc(struct ad_options *ad_options)
      32             : {
      33             :     errno_t ret;
      34             : 
      35           0 :     if (dp_opt_get_bool(ad_options->basic, AD_ENABLE_GC) == false) {
      36           0 :         return;
      37             :     }
      38             : 
      39           0 :     DEBUG(SSSDBG_IMPORTANT_INFO, "POSIX attributes were requested "
      40             :           "but are not present on the server side. Global Catalog "
      41             :           "lookups will be disabled\n");
      42             : 
      43           0 :     ret = dp_opt_set_bool(ad_options->basic,
      44             :                           AD_ENABLE_GC, false);
      45           0 :     if (ret != EOK) {
      46           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
      47             :                 "Could not turn off GC support\n");
      48             :         /* Not fatal */
      49             :     }
      50             : }
      51             : 
      52             : struct ad_handle_acct_info_state {
      53             :     struct be_req *breq;
      54             :     struct be_acct_req *ar;
      55             :     struct sdap_id_ctx *ctx;
      56             :     struct sdap_id_conn_ctx **conn;
      57             :     struct sdap_domain *sdom;
      58             :     size_t cindex;
      59             :     struct ad_options *ad_options;
      60             : 
      61             :     int dp_error;
      62             :     const char *err;
      63             : };
      64             : 
      65             : static errno_t ad_handle_acct_info_step(struct tevent_req *req);
      66             : static void ad_handle_acct_info_done(struct tevent_req *subreq);
      67             : 
      68             : struct tevent_req *
      69           0 : ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
      70             :                          struct be_req *breq,
      71             :                          struct be_acct_req *ar,
      72             :                          struct sdap_id_ctx *ctx,
      73             :                          struct ad_options *ad_options,
      74             :                          struct sdap_domain *sdom,
      75             :                          struct sdap_id_conn_ctx **conn)
      76             : {
      77             :     struct tevent_req *req;
      78             :     struct ad_handle_acct_info_state *state;
      79           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(breq);
      80             :     errno_t ret;
      81             : 
      82           0 :     req = tevent_req_create(mem_ctx, &state, struct ad_handle_acct_info_state);
      83           0 :     if (req == NULL) {
      84           0 :         return NULL;
      85             :     }
      86           0 :     state->breq = breq;
      87           0 :     state->ar = ar;
      88           0 :     state->ctx = ctx;
      89           0 :     state->sdom = sdom;
      90           0 :     state->conn = conn;
      91           0 :     state->ad_options = ad_options;
      92           0 :     state->cindex = 0;
      93             : 
      94           0 :     if (sss_domain_get_state(sdom->dom) == DOM_INACTIVE) {
      95           0 :         ret = ERR_SUBDOM_INACTIVE;
      96           0 :         goto immediate;
      97             :     }
      98             : 
      99           0 :     ret = ad_handle_acct_info_step(req);
     100           0 :     if (ret != EAGAIN) {
     101           0 :         goto immediate;
     102             :     }
     103             : 
     104             :     /* Lookup in progress */
     105           0 :     return req;
     106             : 
     107             : immediate:
     108           0 :     if (ret != EOK) {
     109           0 :         tevent_req_error(req, ret);
     110             :     } else {
     111           0 :         tevent_req_done(req);
     112             :     }
     113           0 :     tevent_req_post(req, be_ctx->ev);
     114           0 :     return req;
     115             : }
     116             : 
     117             : static errno_t
     118           0 : ad_handle_acct_info_step(struct tevent_req *req)
     119             : {
     120             :     struct tevent_req *subreq;
     121           0 :     struct ad_handle_acct_info_state *state = tevent_req_data(req,
     122             :                                             struct ad_handle_acct_info_state);
     123           0 :     bool noexist_delete = false;
     124             : 
     125           0 :     if (state->conn[state->cindex] == NULL) {
     126           0 :         return EOK;
     127             :     }
     128             : 
     129           0 :     if (state->conn[state->cindex+1] == NULL) {
     130           0 :         noexist_delete = true;
     131             :     }
     132             : 
     133           0 :     subreq = sdap_handle_acct_req_send(state, state->ctx->be,
     134             :                                        state->ar, state->ctx,
     135             :                                        state->sdom,
     136           0 :                                        state->conn[state->cindex],
     137             :                                        noexist_delete);
     138           0 :     if (subreq == NULL) {
     139           0 :         return ENOMEM;
     140             :     }
     141           0 :     tevent_req_set_callback(subreq, ad_handle_acct_info_done, req);
     142           0 :     return EAGAIN;
     143             : }
     144             : 
     145             : static void
     146           0 : ad_handle_acct_info_done(struct tevent_req *subreq)
     147             : {
     148             :     errno_t ret;
     149             :     int dp_error;
     150             :     int sdap_err;
     151             :     const char *err;
     152           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     153             :                                                       struct tevent_req);
     154           0 :     struct ad_handle_acct_info_state *state = tevent_req_data(req,
     155             :                                             struct ad_handle_acct_info_state);
     156             : 
     157           0 :     ret = sdap_handle_acct_req_recv(subreq, &dp_error, &err, &sdap_err);
     158           0 :     if (dp_error == DP_ERR_OFFLINE
     159           0 :         && state->conn[state->cindex+1] != NULL
     160           0 :         && state->conn[state->cindex]->ignore_mark_offline) {
     161             :          /* This is a special case: GC does not work.
     162             :           *  We need to Fall back to ldap
     163             :           */
     164           0 :         ret = EOK;
     165           0 :         sdap_err = ENOENT;
     166             :     }
     167           0 :     talloc_zfree(subreq);
     168           0 :     if (ret != EOK) {
     169             :         /* if GC was not used dp error should be set */
     170           0 :         state->dp_error = dp_error;
     171           0 :         state->err = err;
     172             : 
     173           0 :         goto fail;
     174             :     }
     175             : 
     176           0 :     if (sdap_err == EOK) {
     177           0 :         tevent_req_done(req);
     178           0 :         return;
     179           0 :     } else if (sdap_err == ERR_NO_POSIX) {
     180           0 :         disable_gc(state->ad_options);
     181           0 :     } else if (sdap_err != ENOENT) {
     182           0 :         ret = EIO;
     183           0 :         goto fail;
     184             :     }
     185             : 
     186             :     /* Ret is only ENOENT or ERR_NO_POSIX now. Try the next connection */
     187           0 :     state->cindex++;
     188           0 :     ret = ad_handle_acct_info_step(req);
     189           0 :     if (ret != EAGAIN) {
     190             :         /* No additional search in progress. Save the last
     191             :          * error status, we'll be returning it.
     192             :          */
     193           0 :         state->dp_error = dp_error;
     194           0 :         state->err = err;
     195             : 
     196           0 :         if (ret == EOK) {
     197             :             /* No more connections */
     198           0 :             tevent_req_done(req);
     199             :         } else {
     200           0 :             goto fail;
     201             :         }
     202           0 :         return;
     203             :     }
     204             : 
     205             :     /* Another lookup in progress */
     206           0 :     return;
     207             : 
     208             : fail:
     209           0 :     if (IS_SUBDOMAIN(state->sdom->dom)) {
     210             :         /* Deactivate subdomain on lookup errors instead of going
     211             :          * offline completely.
     212             :          * This is a stopgap, until our failover is per-domain,
     213             :          * not per-backend. Unfortunately, we can't rewrite the error
     214             :          * code on some reported codes only, because sdap_id_op code
     215             :          * encapsulated the failover as well..
     216             :          */
     217           0 :         ret = ERR_SUBDOM_INACTIVE;
     218             :     }
     219           0 :     tevent_req_error(req, ret);
     220           0 :     return;
     221             : }
     222             : 
     223             : errno_t
     224           0 : ad_handle_acct_info_recv(struct tevent_req *req,
     225             :                          int *_dp_error, const char **_err)
     226             : {
     227           0 :     struct ad_handle_acct_info_state *state = tevent_req_data(req,
     228             :                                             struct ad_handle_acct_info_state);
     229             : 
     230           0 :     if (_dp_error) {
     231           0 :         *_dp_error = state->dp_error;
     232             :     }
     233             : 
     234           0 :     if (_err) {
     235           0 :         *_err = state->err;
     236             :     }
     237             : 
     238           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     239           0 :     return EOK;
     240             : }
     241             : 
     242             : struct sdap_id_conn_ctx **
     243           0 : get_conn_list(struct be_req *breq, struct ad_id_ctx *ad_ctx,
     244             :               struct sss_domain_info *dom, struct be_acct_req *ar)
     245             : {
     246             :     struct sdap_id_conn_ctx **clist;
     247             : 
     248           0 :     switch (ar->entry_type & BE_REQ_TYPE_MASK) {
     249             :     case BE_REQ_USER: /* user */
     250           0 :         clist = ad_user_conn_list(breq, ad_ctx, dom);
     251           0 :         break;
     252             :     case BE_REQ_BY_SECID:   /* by SID */
     253             :     case BE_REQ_USER_AND_GROUP: /* get SID */
     254             :     case BE_REQ_GROUP: /* group */
     255             :     case BE_REQ_INITGROUPS: /* init groups for user */
     256           0 :         clist = ad_gc_conn_list(breq, ad_ctx, dom);
     257           0 :         break;
     258             :     default:
     259             :         /* Requests for other object should only contact LDAP by default */
     260           0 :         clist = ad_ldap_conn_list(breq, ad_ctx, dom);
     261           0 :         break;
     262             :     }
     263             : 
     264           0 :     return clist;
     265             : }
     266             : 
     267           0 : static bool ad_account_can_shortcut(struct be_ctx *be_ctx,
     268             :                                     struct sdap_idmap_ctx *idmap_ctx,
     269             :                                     int filter_type,
     270             :                                     const char *filter_value,
     271             :                                     const char *filter_domain)
     272             : {
     273           0 :     struct sss_domain_info *domain = be_ctx->domain;
     274           0 :     struct sss_domain_info *req_dom = NULL;
     275             :     enum idmap_error_code err;
     276           0 :     char *sid = NULL;
     277           0 :     const char *csid = NULL;
     278             :     uint32_t id;
     279           0 :     bool shortcut = false;
     280             :     errno_t ret;
     281             : 
     282           0 :     if (!sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, domain->name,
     283           0 :                                                    domain->domain_id)) {
     284           0 :         goto done;
     285             :     }
     286             : 
     287           0 :     switch (filter_type) {
     288             :     case BE_FILTER_IDNUM:
     289             :         /* convert value to ID */
     290           0 :         errno = 0;
     291           0 :         id = strtouint32(filter_value, NULL, 10);
     292           0 :         if (errno != 0) {
     293           0 :             ret = errno;
     294           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Unable to convert filter value to "
     295             :                   "number [%d]: %s\n", ret, strerror(ret));
     296           0 :             goto done;
     297             :         }
     298             : 
     299             :         /* convert the ID to its SID equivalent */
     300           0 :         err = sss_idmap_unix_to_sid(idmap_ctx->map, id, &sid);
     301           0 :         if (err != IDMAP_SUCCESS) {
     302           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Mapping ID [%s] to SID failed: "
     303             :                   "[%s]\n", filter_value, idmap_error_string(err));
     304           0 :             goto done;
     305             :         }
     306             :         /* fall through */
     307             :     case BE_FILTER_SECID:
     308           0 :         csid = sid == NULL ? filter_value : sid;
     309             : 
     310           0 :         req_dom = find_domain_by_sid(domain, csid);
     311           0 :         if (req_dom == NULL) {
     312           0 :             DEBUG(SSSDBG_OP_FAILURE, "Invalid domain\n");
     313           0 :             goto done;
     314             :         }
     315             : 
     316           0 :         if (strcasecmp(req_dom->name, filter_domain) != 0) {
     317           0 :             shortcut = true;
     318             :         }
     319           0 :         break;
     320             :     default:
     321           0 :         break;
     322             :     }
     323             : 
     324             : done:
     325           0 :     if (sid != NULL) {
     326           0 :         sss_idmap_free_sid(idmap_ctx->map, sid);
     327             :     }
     328             : 
     329           0 :     return shortcut;
     330             : }
     331             : 
     332             : static void ad_account_info_complete(struct tevent_req *req);
     333             : 
     334             : struct ad_account_info_state {
     335             :     struct be_req *be_req;
     336             :     struct sss_domain_info *dom;
     337             : };
     338             : 
     339             : void
     340           0 : ad_account_info_handler(struct be_req *be_req)
     341             : {
     342             :     struct ad_id_ctx *ad_ctx;
     343             :     struct be_acct_req *ar;
     344             :     struct sdap_id_ctx *sdap_id_ctx;
     345           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
     346             :     struct tevent_req *req;
     347             :     struct sss_domain_info *dom;
     348             :     struct sdap_domain *sdom;
     349             :     struct sdap_id_conn_ctx **clist;
     350             :     bool shortcut;
     351             :     errno_t ret;
     352             :     struct ad_account_info_state *state;
     353             : 
     354           0 :     ad_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
     355             :                              struct ad_id_ctx);
     356           0 :     ar = talloc_get_type(be_req_get_data(be_req), struct be_acct_req);
     357           0 :     sdap_id_ctx = ad_ctx->sdap_id_ctx;
     358             : 
     359           0 :     if (be_is_offline(be_ctx)) {
     360           0 :         return be_req_terminate(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline");
     361             :     }
     362             : 
     363           0 :     if (sdap_is_enum_request(ar)) {
     364           0 :         DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n");
     365           0 :         return sdap_handler_done(be_req, DP_ERR_OK, EOK, "Success");
     366             :     }
     367             : 
     368             :     /* Try to shortcut if this is ID or SID search and it belongs to
     369             :      * other domain range than is in ar->domain. */
     370           0 :     shortcut = ad_account_can_shortcut(be_ctx, sdap_id_ctx->opts->idmap_ctx,
     371           0 :                                        ar->filter_type, ar->filter_value,
     372           0 :                                        ar->domain);
     373           0 :     if (shortcut) {
     374           0 :         DEBUG(SSSDBG_TRACE_FUNC, "This ID is from different domain\n");
     375           0 :         be_req_terminate(be_req, DP_ERR_OK, EOK, NULL);
     376           0 :         return;
     377             :     }
     378             : 
     379           0 :     dom = be_ctx->domain;
     380           0 :     if (strcasecmp(ar->domain, be_ctx->domain->name) != 0) {
     381             :         /* Subdomain request, verify subdomain */
     382           0 :         dom = find_domain_by_name(be_ctx->domain, ar->domain, true);
     383             :     }
     384             : 
     385           0 :     if (dom == NULL) {
     386           0 :         ret = EINVAL;
     387           0 :         goto fail;
     388             :     }
     389             : 
     390             :     /* Determine whether to connect to GC, LDAP or try both */
     391           0 :     clist = get_conn_list(be_req, ad_ctx, dom, ar);
     392           0 :     if (clist == NULL) {
     393           0 :         ret = EIO;
     394           0 :         goto fail;
     395             :     }
     396             : 
     397           0 :     sdom = sdap_domain_get(sdap_id_ctx->opts, dom);
     398           0 :     if (sdom == NULL) {
     399           0 :         ret = EIO;
     400           0 :         goto fail;
     401             :     }
     402             : 
     403           0 :     state = talloc(be_req, struct ad_account_info_state);
     404           0 :     if (state == NULL) {
     405           0 :         ret = ENOMEM;
     406           0 :         goto fail;
     407             :     }
     408           0 :     state->dom = sdom->dom;
     409           0 :     state->be_req = be_req;
     410             : 
     411           0 :     req = ad_handle_acct_info_send(be_req, be_req, ar, sdap_id_ctx,
     412             :                                    ad_ctx->ad_options, sdom, clist);
     413           0 :     if (req == NULL) {
     414           0 :         ret = ENOMEM;
     415           0 :         goto fail;
     416             :     }
     417           0 :     tevent_req_set_callback(req, ad_account_info_complete, state);
     418           0 :     return;
     419             : 
     420             : fail:
     421           0 :     be_req_terminate(be_req, DP_ERR_FATAL, ret, NULL);
     422             : }
     423             : 
     424             : static void
     425           0 : ad_account_info_complete(struct tevent_req *req)
     426             : {
     427             :     struct be_req *be_req;
     428             :     errno_t ret;
     429             :     int dp_error;
     430           0 :     const char *error_text = "Internal error";
     431             :     const char *req_error_text;
     432             :     struct ad_account_info_state *state;
     433             : 
     434           0 :     state = tevent_req_callback_data(req, struct ad_account_info_state);
     435           0 :     be_req = state->be_req;
     436             : 
     437           0 :     ret = ad_handle_acct_info_recv(req, &dp_error, &req_error_text);
     438           0 :     talloc_zfree(req);
     439           0 :     if (ret == ERR_SUBDOM_INACTIVE) {
     440           0 :         be_mark_dom_offline(state->dom, be_req_get_be_ctx(be_req));
     441           0 :         return be_req_terminate(be_req, DP_ERR_OFFLINE, EAGAIN, "Offline");
     442           0 :     } else if (dp_error == DP_ERR_OK) {
     443           0 :         if (ret == EOK) {
     444           0 :             error_text = NULL;
     445             :         } else {
     446           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     447             :                   "Bug: dp_error is OK on failed request\n");
     448           0 :             dp_error = DP_ERR_FATAL;
     449           0 :             error_text = req_error_text;
     450             :         }
     451           0 :     } else if (dp_error == DP_ERR_OFFLINE) {
     452           0 :         error_text = "Offline";
     453           0 :     } else if (dp_error == DP_ERR_FATAL && ret == ENOMEM) {
     454           0 :         error_text = "Out of memory";
     455             :     } else {
     456           0 :         error_text = req_error_text;
     457             :     }
     458             : 
     459           0 :     return be_req_terminate(be_req, dp_error, ret, error_text);
     460             : }
     461             : 
     462             : void
     463           0 : ad_check_online(struct be_req *be_req)
     464             : {
     465             :     struct ad_id_ctx *ad_ctx;
     466           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(be_req);
     467             : 
     468           0 :     ad_ctx = talloc_get_type(be_ctx->bet_info[BET_ID].pvt_bet_data,
     469             :                              struct ad_id_ctx);
     470             : 
     471           0 :     return sdap_do_online_check(be_req, ad_ctx->sdap_id_ctx);
     472             : }
     473             : 
     474             : struct ad_enumeration_state {
     475             :     struct ad_id_ctx *id_ctx;
     476             :     struct ldap_enum_ctx *ectx;
     477             :     struct sdap_id_op *sdap_op;
     478             :     struct tevent_context *ev;
     479             : 
     480             :     const char *realm;
     481             :     struct sdap_domain *sdom;
     482             :     struct sdap_domain *sditer;
     483             : };
     484             : 
     485             : static void ad_enumeration_conn_done(struct tevent_req *subreq);
     486             : static void ad_enumeration_master_done(struct tevent_req *subreq);
     487             : static errno_t ad_enum_sdom(struct tevent_req *req, struct sdap_domain *sd,
     488             :                             struct ad_id_ctx *id_ctx);
     489             : static void ad_enumeration_done(struct tevent_req *subreq);
     490             : 
     491             : struct tevent_req *
     492           0 : ad_enumeration_send(TALLOC_CTX *mem_ctx,
     493             :                     struct tevent_context *ev,
     494             :                     struct be_ctx *be_ctx,
     495             :                     struct be_ptask *be_ptask,
     496             :                     void *pvt)
     497             : {
     498             :     struct tevent_req *req;
     499             :     struct tevent_req *subreq;
     500             :     struct ad_enumeration_state *state;
     501             :     struct ldap_enum_ctx *ectx;
     502             :     errno_t ret;
     503             : 
     504           0 :     req = tevent_req_create(mem_ctx, &state, struct ad_enumeration_state);
     505           0 :     if (req == NULL) return NULL;
     506             : 
     507           0 :     ectx = talloc_get_type(pvt, struct ldap_enum_ctx);
     508           0 :     if (ectx == NULL) {
     509           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot retrieve ldap_enum_ctx!\n");
     510           0 :         ret = EFAULT;
     511           0 :         goto fail;
     512             :     }
     513             : 
     514           0 :     state->ectx = ectx;
     515           0 :     state->ev = ev;
     516           0 :     state->sdom = ectx->sdom;
     517           0 :     state->sditer = state->sdom;
     518           0 :     state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
     519             : 
     520           0 :     state->realm = dp_opt_get_cstring(state->id_ctx->ad_options->basic,
     521             :                                       AD_KRB5_REALM);
     522           0 :     if (state->realm == NULL) {
     523           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm\n");
     524           0 :         ret = EINVAL;
     525           0 :         goto fail;
     526             :     }
     527             : 
     528           0 :     state->sdap_op = sdap_id_op_create(state,
     529           0 :                                        state->id_ctx->ldap_ctx->conn_cache);
     530           0 :     if (state->sdap_op == NULL) {
     531           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
     532           0 :         ret = ENOMEM;
     533           0 :         goto fail;
     534             :     }
     535             : 
     536           0 :     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
     537           0 :     if (subreq == NULL) {
     538           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
     539             :                                   ret, strerror(ret));
     540           0 :         goto fail;
     541             :     }
     542           0 :     tevent_req_set_callback(subreq, ad_enumeration_conn_done, req);
     543             : 
     544           0 :     return req;
     545             : 
     546             : fail:
     547           0 :     tevent_req_error(req, ret);
     548           0 :     tevent_req_post(req, ev);
     549           0 :     return req;
     550             : }
     551             : 
     552             : static void
     553           0 : ad_enumeration_conn_done(struct tevent_req *subreq)
     554             : {
     555           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     556             :                                                       struct tevent_req);
     557           0 :     struct ad_enumeration_state *state = tevent_req_data(req,
     558             :                                                  struct ad_enumeration_state);
     559             :     int ret, dp_error;
     560             : 
     561           0 :     ret = sdap_id_op_connect_recv(subreq, &dp_error);
     562           0 :     talloc_zfree(subreq);
     563           0 :     if (ret != EOK) {
     564           0 :         if (dp_error == DP_ERR_OFFLINE) {
     565           0 :             DEBUG(SSSDBG_TRACE_FUNC,
     566             :                   "Backend is marked offline, retry later!\n");
     567           0 :             tevent_req_done(req);
     568             :         } else {
     569           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     570             :                   "Domain enumeration failed to connect to " \
     571             :                    "LDAP server: (%d)[%s]\n", ret, strerror(ret));
     572           0 :             tevent_req_error(req, ret);
     573             :         }
     574           0 :         return;
     575             :     }
     576             : 
     577           0 :     subreq = ad_master_domain_send(state, state->ev,
     578           0 :                                    state->id_ctx->ldap_ctx,
     579             :                                    state->sdap_op,
     580           0 :                                    state->sdom->dom->name);
     581           0 :     if (subreq == NULL) {
     582           0 :         DEBUG(SSSDBG_OP_FAILURE, "ad_master_domain_send failed.\n");
     583           0 :         tevent_req_error(req, ret);
     584           0 :         return;
     585             :     }
     586           0 :     tevent_req_set_callback(subreq, ad_enumeration_master_done, req);
     587             : }
     588             : 
     589             : static void
     590           0 : ad_enumeration_master_done(struct tevent_req *subreq)
     591             : {
     592             :     errno_t ret;
     593           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     594             :                                                       struct tevent_req);
     595           0 :     struct ad_enumeration_state *state = tevent_req_data(req,
     596             :                                                 struct ad_enumeration_state);
     597             :     char *flat_name;
     598             :     char *master_sid;
     599             :     char *forest;
     600             : 
     601           0 :     ret = ad_master_domain_recv(subreq, state,
     602             :                                 &flat_name, &master_sid, NULL, &forest);
     603           0 :     talloc_zfree(subreq);
     604           0 :     if (ret != EOK) {
     605           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve master domain info\n");
     606           0 :         tevent_req_error(req, ret);
     607           0 :         return;
     608             :     }
     609             : 
     610           0 :     ret = sysdb_master_domain_add_info(state->sdom->dom, state->realm,
     611             :                                        flat_name, master_sid, forest);
     612           0 :     if (ret != EOK) {
     613           0 :         DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info\n");
     614           0 :         tevent_req_error(req, ret);
     615           0 :         return;
     616             :     }
     617             : 
     618           0 :     ret = ad_enum_sdom(req, state->sdom, state->id_ctx);
     619           0 :     if (ret != EOK) {
     620           0 :         DEBUG(SSSDBG_OP_FAILURE,
     621             :                 "Could not enumerate domain %s\n", state->sdom->dom->name);
     622           0 :         tevent_req_error(req, ret);
     623           0 :         return;
     624             :     }
     625             : 
     626             :     /* Execution will resume in ad_enumeration_done */
     627             : }
     628             : 
     629             : static errno_t
     630           0 : ad_enum_sdom(struct tevent_req *req,
     631             :              struct sdap_domain *sd,
     632             :              struct ad_id_ctx *id_ctx)
     633             : {
     634             :     struct sdap_id_conn_ctx *user_conn;
     635             :     struct tevent_req *subreq;
     636           0 :     struct ad_enumeration_state *state = tevent_req_data(req,
     637             :                                                 struct ad_enumeration_state);
     638             : 
     639           0 :     if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC)) {
     640           0 :         user_conn = id_ctx->gc_ctx;
     641             :     } else {
     642           0 :         user_conn = id_ctx->ldap_ctx;
     643             :     }
     644             : 
     645             :     /* Groups are searched for in LDAP, users in GC. Services (if present,
     646             :      * which is unlikely in AD) from LDAP as well
     647             :      */
     648           0 :     subreq = sdap_dom_enum_ex_send(state, state->ev,
     649             :                                    id_ctx->sdap_id_ctx,
     650             :                                    sd,
     651             :                                    user_conn,         /* Users    */
     652             :                                    id_ctx->ldap_ctx,  /* Groups   */
     653             :                                    id_ctx->ldap_ctx); /* Services */
     654           0 :     if (subreq == NULL) {
     655             :         /* The ptask API will reschedule the enumeration on its own on
     656             :          * failure */
     657           0 :         DEBUG(SSSDBG_OP_FAILURE,
     658             :               "Failed to schedule enumeration, retrying later!\n");
     659           0 :         return ENOMEM;
     660             :     }
     661           0 :     tevent_req_set_callback(subreq, ad_enumeration_done, req);
     662             : 
     663           0 :     return EOK;
     664             : }
     665             : 
     666             : static errno_t ad_enum_cross_dom_members(struct sdap_options *opts,
     667             :                                          struct sss_domain_info *dom);
     668             : 
     669             : static void
     670           0 : ad_enumeration_done(struct tevent_req *subreq)
     671             : {
     672             :     errno_t ret;
     673           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     674             :                                                       struct tevent_req);
     675           0 :     struct ad_enumeration_state *state = tevent_req_data(req,
     676             :                                                 struct ad_enumeration_state);
     677             : 
     678           0 :     ret = sdap_dom_enum_ex_recv(subreq);
     679           0 :     talloc_zfree(subreq);
     680           0 :     if (ret == ERR_NO_POSIX) {
     681             :         /* Retry enumerating the same domain again, this time w/o
     682             :          * connecting to GC
     683             :          */
     684           0 :         disable_gc(state->id_ctx->ad_options);
     685           0 :         ret = ad_enum_sdom(req, state->sditer, state->id_ctx);
     686           0 :         if (ret != EOK) {
     687           0 :             DEBUG(SSSDBG_OP_FAILURE,
     688             :                 "Could not retry domain %s\n", state->sditer->dom->name);
     689           0 :             tevent_req_error(req, ret);
     690           0 :             return;
     691             :         }
     692             : 
     693             :         /* Execution will resume in ad_enumeration_done */
     694           0 :         return;
     695           0 :     } else if (ret != EOK) {
     696           0 :         DEBUG(SSSDBG_OP_FAILURE,
     697             :               "Could not enumerate domain %s\n", state->sditer->dom->name);
     698           0 :         tevent_req_error(req, ret);
     699           0 :         return;
     700             :     }
     701             : 
     702             :     do {
     703           0 :         state->sditer = state->sditer->next;
     704           0 :     } while (state->sditer &&
     705           0 :              state->sditer->dom->enumerate == false);
     706             : 
     707           0 :     if (state->sditer != NULL) {
     708           0 :         ret = ad_enum_sdom(req, state->sditer, state->sditer->pvt);
     709           0 :         if (ret != EOK) {
     710           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not enumerate domain %s\n",
     711             :                   state->sditer->dom->name);
     712           0 :             tevent_req_error(req, ret);
     713           0 :             return;
     714             :         }
     715             : 
     716             :         /* Execution will resume in ad_enumeration_done */
     717           0 :         return;
     718             :     }
     719             : 
     720             :     /* No more subdomains to enumerate. Check if we need to fixup
     721             :      * cross-domain membership
     722             :      */
     723           0 :     if (state->sditer != state->sdom) {
     724             :         /* We did enumerate at least one subdomain. Walk the subdomains
     725             :          * and fixup members for each of them
     726             :          */
     727           0 :         for (state->sditer = state->sdom;
     728           0 :              state->sditer;
     729           0 :              state->sditer = state->sditer->next) {
     730           0 :             ret = ad_enum_cross_dom_members(state->id_ctx->ad_options->id,
     731           0 :                                             state->sditer->dom);
     732           0 :             if (ret != EOK) {
     733           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Could not check cross-domain "
     734             :                       "memberships for %s, group memberships might be "
     735             :                       "incomplete!\n", state->sdom->dom->name);
     736           0 :                 continue;
     737             :             }
     738             :         }
     739             :     }
     740             : 
     741           0 :     tevent_req_done(req);
     742             : }
     743             : 
     744             : static errno_t ad_group_extra_members(TALLOC_CTX *mem_ctx,
     745             :                                       const struct ldb_message *group,
     746             :                                       struct sss_domain_info *dom,
     747             :                                       char ***_group_only);
     748             : static errno_t ad_group_add_member(struct sdap_options *opts,
     749             :                                    struct sss_domain_info *group_domain,
     750             :                                    struct ldb_dn *group_dn,
     751             :                                    const char *member);
     752             : 
     753             : static errno_t
     754           0 : ad_enum_cross_dom_members(struct sdap_options *opts,
     755             :                           struct sss_domain_info *dom)
     756             : {
     757             :     errno_t ret;
     758             :     errno_t sret;
     759             :     char *filter;
     760             :     TALLOC_CTX *tmp_ctx;
     761           0 :     const char *attrs[] = {
     762             :             SYSDB_NAME,
     763             :             SYSDB_MEMBER,
     764             :             SYSDB_ORIG_MEMBER,
     765             :             NULL
     766             :     };
     767             :     size_t count, i, mi;
     768             :     struct ldb_message **msgs;
     769           0 :     bool in_transaction = false;
     770             :     char **group_only;
     771             : 
     772           0 :     tmp_ctx = talloc_new(NULL);
     773           0 :     if (tmp_ctx == NULL) return ENOMEM;
     774             : 
     775           0 :     ret = sysdb_transaction_start(dom->sysdb);
     776           0 :     if (ret != EOK) {
     777           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
     778           0 :         goto done;
     779             :     }
     780           0 :     in_transaction = true;
     781             : 
     782           0 :     filter = talloc_asprintf(tmp_ctx, "(%s=*)", SYSDB_NAME);
     783           0 :     if (filter == NULL) {
     784           0 :         ret = ENOMEM;
     785           0 :         goto done;
     786             :     }
     787             : 
     788           0 :     ret = sysdb_search_groups(tmp_ctx, dom, filter, attrs, &count, &msgs);
     789           0 :     if (ret != EOK) {
     790           0 :         goto done;
     791             :     }
     792             : 
     793           0 :     for (i = 0; i < count; i++) {
     794           0 :         ret = ad_group_extra_members(tmp_ctx, msgs[i], dom, &group_only);
     795           0 :         if (ret != EOK) {
     796           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to check extra members\n");
     797           0 :             continue;
     798           0 :         } else if (group_only == NULL) {
     799           0 :             DEBUG(SSSDBG_TRACE_INTERNAL, "No extra members\n");
     800           0 :             continue;
     801             :         }
     802             : 
     803             :         /* Group has extra members */
     804           0 :         for (mi = 0; group_only[mi]; mi++) {
     805           0 :             ret = ad_group_add_member(opts, dom, msgs[i]->dn, group_only[mi]);
     806           0 :             if (ret != EOK) {
     807           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add [%s]: %s\n",
     808             :                       group_only[mi], strerror(ret));
     809           0 :                 continue;
     810             :             }
     811             :         }
     812             : 
     813           0 :         talloc_zfree(group_only);
     814             :     }
     815             : 
     816           0 :     ret = sysdb_transaction_commit(dom->sysdb);
     817           0 :     if (ret != EOK) {
     818           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
     819           0 :         goto done;
     820             :     }
     821           0 :     in_transaction = false;
     822             : 
     823           0 :     ret = EOK;
     824             : done:
     825           0 :     if (in_transaction) {
     826           0 :         sret = sysdb_transaction_cancel(dom->sysdb);
     827           0 :         if (sret != EOK) {
     828           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
     829             :         }
     830             :     }
     831           0 :     talloc_free(tmp_ctx);
     832           0 :     return ret;
     833             : }
     834             : 
     835             : static errno_t
     836             : ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
     837             :                              struct ldb_dn *dn, char ***_odn_list);
     838             : 
     839             : static errno_t
     840           0 : ad_group_extra_members(TALLOC_CTX *mem_ctx, const struct ldb_message *group,
     841             :                        struct sss_domain_info *dom, char ***_group_only)
     842             : {
     843             :     TALLOC_CTX *tmp_ctx;
     844             :     struct ldb_message_element *m, *om;
     845             :     const char *name;
     846             :     errno_t ret;
     847             :     char **sysdb_odn_list;
     848             :     const char **group_odn_list;
     849           0 :     char **group_only = NULL;
     850             : 
     851           0 :     if (_group_only == NULL) return EINVAL;
     852           0 :     *_group_only = NULL;
     853             : 
     854           0 :     tmp_ctx = talloc_new(NULL);
     855           0 :     if (tmp_ctx == NULL) return ENOMEM;
     856             : 
     857           0 :     om = ldb_msg_find_element(group, SYSDB_ORIG_MEMBER);
     858           0 :     m = ldb_msg_find_element(group, SYSDB_MEMBER);
     859           0 :     name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
     860           0 :     if (name == NULL) {
     861           0 :         DEBUG(SSSDBG_OP_FAILURE, "A group with no name!\n");
     862           0 :         ret = EFAULT;
     863           0 :         goto done;
     864             :     }
     865             : 
     866           0 :     if (om == NULL || om->num_values == 0) {
     867           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Group %s has no original members\n", name);
     868           0 :         ret = EOK;
     869           0 :         goto done;
     870             :     }
     871             : 
     872           0 :     if (m == NULL || (m->num_values < om->num_values)) {
     873           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     874             :               "Group %s has %d members but %d original members\n",
     875             :                name, m ? m->num_values : 0, om->num_values);
     876             : 
     877             :         /* Get the list of originalDN attributes that are already
     878             :          * linked to the group
     879             :          */
     880           0 :         ret = ad_group_stored_orig_members(tmp_ctx, dom, group->dn,
     881             :                                            &sysdb_odn_list);
     882           0 :         if (ret != EOK) {
     883           0 :             DEBUG(SSSDBG_OP_FAILURE,
     884             :                   "Could not retrieve list of original members for %s\n",
     885             :                   name);
     886           0 :             goto done;
     887             :         }
     888             : 
     889             :         /* Get the list of original DN attributes the group had in AD */
     890           0 :         group_odn_list = sss_ldb_el_to_string_list(tmp_ctx, om);
     891           0 :         if (group_odn_list == NULL) {
     892           0 :             ret = EFAULT;
     893           0 :             goto done;
     894             :         }
     895             : 
     896             :         /* Compare the two lists */
     897           0 :         ret = diff_string_lists(tmp_ctx, discard_const(group_odn_list),
     898             :                                 sysdb_odn_list, &group_only, NULL, NULL);
     899           0 :         if (ret != EOK) {
     900           0 :             DEBUG(SSSDBG_OP_FAILURE,
     901             :                   "Could not compare lists of members for %s\n", name);
     902           0 :             goto done;
     903             :         }
     904             :     }
     905             : 
     906           0 :     ret = EOK;
     907           0 :     *_group_only = talloc_steal(mem_ctx, group_only);
     908             : done:
     909           0 :     talloc_free(tmp_ctx);
     910           0 :     return ret;
     911             : }
     912             : 
     913             : static errno_t
     914           0 : ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
     915             :                              struct ldb_dn *dn, char ***_odn_list)
     916             : {
     917             :     errno_t ret;
     918             :     TALLOC_CTX *tmp_ctx;
     919             :     size_t m_count, i;
     920             :     struct ldb_message **members;
     921           0 :     const char *attrs[] = {
     922             :             SYSDB_NAME,
     923             :             SYSDB_ORIG_DN,
     924             :             NULL
     925             :     };
     926             :     char **odn_list;
     927             :     const char *odn;
     928             :     size_t oi;
     929             : 
     930           0 :     tmp_ctx = talloc_new(NULL);
     931           0 :     if (tmp_ctx == NULL) return ENOMEM;
     932             : 
     933             :     /* Get all entries member element points to */
     934           0 :     ret = sysdb_asq_search(tmp_ctx, dom, dn, NULL, SYSDB_MEMBER,
     935             :                            attrs, &m_count, &members);
     936           0 :     if (ret != EOK) {
     937           0 :         goto done;
     938             :     }
     939             : 
     940           0 :     odn_list = talloc_zero_array(tmp_ctx, char *, m_count + 1);
     941           0 :     if (odn_list == NULL) {
     942           0 :         ret = ENOMEM;
     943           0 :         goto done;
     944             :     }
     945             : 
     946             :     /* Get a list of their original DNs */
     947           0 :     oi = 0;
     948           0 :     for (i = 0; i < m_count; i++) {
     949           0 :         odn = ldb_msg_find_attr_as_string(members[i], SYSDB_ORIG_DN, NULL);
     950           0 :         if (odn == NULL) {
     951           0 :             continue;
     952             :         }
     953             : 
     954           0 :         odn_list[oi] = talloc_strdup(odn_list, odn);
     955           0 :         if (odn_list[oi] == NULL) {
     956           0 :             ret = ENOMEM;
     957           0 :             goto done;
     958             :         }
     959           0 :         oi++;
     960           0 :         DEBUG(SSSDBG_TRACE_INTERNAL, "Member %s already in sysdb\n", odn);
     961             :     }
     962             : 
     963           0 :     ret = EOK;
     964           0 :     *_odn_list = talloc_steal(mem_ctx, odn_list);
     965             : done:
     966           0 :     talloc_free(tmp_ctx);
     967           0 :     return ret;
     968             : }
     969             : 
     970             : static errno_t
     971           0 : ad_group_add_member(struct sdap_options *opts,
     972             :                     struct sss_domain_info *group_domain,
     973             :                     struct ldb_dn *group_dn,
     974             :                     const char *member)
     975             : {
     976             :     struct sdap_domain *sd;
     977             :     struct ldb_dn *base_dn;
     978             :     TALLOC_CTX *tmp_ctx;
     979             :     errno_t ret;
     980             :     const char *mem_filter;
     981             :     size_t msgs_count;
     982             :     struct ldb_message **msgs;
     983             : 
     984             :     /* This member would be from a different domain */
     985           0 :     sd = sdap_domain_get_by_dn(opts, member);
     986           0 :     if (sd == NULL) {
     987           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "No matching domain for %s\n", member);
     988           0 :         return ENOENT;
     989             :     }
     990             : 
     991           0 :     tmp_ctx = talloc_new(NULL);
     992           0 :     if (tmp_ctx == NULL) return ENOMEM;
     993             : 
     994           0 :     mem_filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
     995             :                                  SYSDB_ORIG_DN, member);
     996           0 :     if (mem_filter == NULL) {
     997           0 :         ret = ENOMEM;
     998           0 :         goto done;
     999             :     }
    1000             : 
    1001           0 :     base_dn = sysdb_domain_dn(tmp_ctx, sd->dom);
    1002           0 :     if (base_dn == NULL) {
    1003           0 :         ret = ENOMEM;
    1004           0 :         goto done;
    1005             :     }
    1006             : 
    1007           0 :     ret = sysdb_search_entry(tmp_ctx, sd->dom->sysdb, base_dn,
    1008             :                              LDB_SCOPE_SUBTREE, mem_filter, NULL,
    1009             :                              &msgs_count, &msgs);
    1010           0 :     if (ret == ENOENT) {
    1011           0 :         DEBUG(SSSDBG_TRACE_FUNC, "No member [%s] in sysdb\n", member);
    1012           0 :         ret = EOK;
    1013           0 :         goto done;
    1014           0 :     } else if (ret != EOK) {
    1015           0 :         goto done;
    1016             :     }
    1017           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "[%s] found in sysdb\n", member);
    1018             : 
    1019           0 :     if (msgs_count != 1) {
    1020           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1021             :                "Search by orig DN returned %zd results!\n", msgs_count);
    1022           0 :         ret = EFAULT;
    1023           0 :         goto done;
    1024             :     }
    1025             : 
    1026           0 :     ret = sysdb_mod_group_member(group_domain, msgs[0]->dn, group_dn, SYSDB_MOD_ADD);
    1027           0 :     if (ret != EOK) {
    1028           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not add [%s] as a member of [%s]\n",
    1029             :               ldb_dn_get_linearized(msgs[0]->dn),
    1030             :               ldb_dn_get_linearized(group_dn));
    1031           0 :         goto done;
    1032             :     }
    1033             : 
    1034           0 :     ret = EOK;
    1035             : done:
    1036           0 :     talloc_free(tmp_ctx);
    1037           0 :     return ret;
    1038             : }
    1039             : 
    1040             : errno_t
    1041           0 : ad_enumeration_recv(struct tevent_req *req)
    1042             : {
    1043           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1044           0 :     return EOK;
    1045             : }

Generated by: LCOV version 1.10