"Fossies" - the Fresh Open Source Software Archive

Member "sssd-2.2.3/src/providers/ad/ad_id.c" (30 Nov 2019, 47236 Bytes) of package /linux/misc/sssd-2.2.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ad_id.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.2.2_vs_2.2.3.

    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/ad/ad_pac.h"
   28 #include "providers/ldap/sdap_async_enum.h"
   29 #include "providers/ldap/sdap_idmap.h"
   30 #include "providers/ldap/sdap_async.h"
   31 
   32 static bool ad_account_can_shortcut(struct sdap_idmap_ctx *idmap_ctx,
   33                                     struct sss_domain_info *domain,
   34                                     int filter_type,
   35                                     const char *filter_value)
   36 {
   37     struct sss_domain_info *dom_head = NULL;
   38     struct sss_domain_info *sid_dom = NULL;
   39     enum idmap_error_code err;
   40     char *sid = NULL;
   41     const char *csid = NULL;
   42     uint32_t id;
   43     bool shortcut = false;
   44     errno_t ret;
   45 
   46     if (!sdap_idmap_domain_has_algorithmic_mapping(idmap_ctx, domain->name,
   47                                                    domain->domain_id)) {
   48         goto done;
   49     }
   50 
   51     switch (filter_type) {
   52     case BE_FILTER_IDNUM:
   53         /* convert value to ID */
   54         errno = 0;
   55         id = strtouint32(filter_value, NULL, 10);
   56         if (errno != 0) {
   57             ret = errno;
   58             DEBUG(SSSDBG_MINOR_FAILURE, "Unable to convert filter value to "
   59                   "number [%d]: %s\n", ret, strerror(ret));
   60             goto done;
   61         }
   62 
   63         /* convert the ID to its SID equivalent */
   64         err = sss_idmap_unix_to_sid(idmap_ctx->map, id, &sid);
   65         if (err != IDMAP_SUCCESS) {
   66             DEBUG(SSSDBG_MINOR_FAILURE, "Mapping ID [%s] to SID failed: "
   67                   "[%s]\n", filter_value, idmap_error_string(err));
   68             /* assume id is from a different domain */
   69             shortcut = true;
   70             goto done;
   71         }
   72         /* fall through */
   73         SSS_ATTRIBUTE_FALLTHROUGH;
   74     case BE_FILTER_SECID:
   75         csid = sid == NULL ? filter_value : sid;
   76 
   77         dom_head = get_domains_head(domain);
   78         if (dom_head == NULL) {
   79             DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find domain head\n");
   80             goto done;
   81         }
   82 
   83         sid_dom = find_domain_by_sid(dom_head, csid);
   84         if (sid_dom == NULL) {
   85             DEBUG(SSSDBG_OP_FAILURE, "Invalid domain for SID:%s\n", csid);
   86             goto done;
   87         }
   88 
   89         if (strcasecmp(sid_dom->name, domain->name) != 0) {
   90             shortcut = true;
   91         }
   92         break;
   93     default:
   94         break;
   95     }
   96 
   97 done:
   98     if (sid != NULL) {
   99         sss_idmap_free_sid(idmap_ctx->map, sid);
  100     }
  101 
  102     return shortcut;
  103 }
  104 
  105 struct ad_handle_acct_info_state {
  106     struct dp_id_data *ar;
  107     struct sdap_id_ctx *ctx;
  108     struct sdap_id_conn_ctx **conn;
  109     struct sdap_domain *sdom;
  110     size_t cindex;
  111     struct ad_options *ad_options;
  112     bool using_pac;
  113 
  114     int dp_error;
  115     const char *err;
  116 };
  117 
  118 static errno_t ad_handle_acct_info_step(struct tevent_req *req);
  119 static void ad_handle_acct_info_done(struct tevent_req *subreq);
  120 
  121 struct tevent_req *
  122 ad_handle_acct_info_send(TALLOC_CTX *mem_ctx,
  123                          struct dp_id_data *ar,
  124                          struct sdap_id_ctx *ctx,
  125                          struct ad_options *ad_options,
  126                          struct sdap_domain *sdom,
  127                          struct sdap_id_conn_ctx **conn)
  128 {
  129     struct tevent_req *req;
  130     struct ad_handle_acct_info_state *state;
  131     struct be_ctx *be_ctx = ctx->be;
  132     errno_t ret;
  133     bool shortcut;
  134 
  135     req = tevent_req_create(mem_ctx, &state, struct ad_handle_acct_info_state);
  136     if (req == NULL) {
  137         return NULL;
  138     }
  139     state->ar = ar;
  140     state->ctx = ctx;
  141     state->sdom = sdom;
  142     state->conn = conn;
  143     state->ad_options = ad_options;
  144     state->cindex = 0;
  145 
  146     /* Try to shortcut if this is ID or SID search and it belongs to
  147      * other domain range than is in ar->domain. */
  148     shortcut = ad_account_can_shortcut(ctx->opts->idmap_ctx,
  149                                        sdom->dom,
  150                                        ar->filter_type,
  151                                        ar->filter_value);
  152     if (shortcut) {
  153         DEBUG(SSSDBG_TRACE_FUNC, "This ID is from different domain\n");
  154         ret = EOK;
  155         goto immediate;
  156     }
  157 
  158     if (sss_domain_get_state(sdom->dom) == DOM_INACTIVE) {
  159         ret = ERR_SUBDOM_INACTIVE;
  160         goto immediate;
  161     }
  162 
  163     ret = ad_handle_acct_info_step(req);
  164     if (ret != EAGAIN) {
  165         goto immediate;
  166     }
  167 
  168     /* Lookup in progress */
  169     return req;
  170 
  171 immediate:
  172     if (ret != EOK) {
  173         tevent_req_error(req, ret);
  174     } else {
  175         tevent_req_done(req);
  176     }
  177     tevent_req_post(req, be_ctx->ev);
  178     return req;
  179 }
  180 
  181 static errno_t
  182 ad_handle_acct_info_step(struct tevent_req *req)
  183 {
  184     struct tevent_req *subreq = NULL;
  185     struct ad_handle_acct_info_state *state = tevent_req_data(req,
  186                                             struct ad_handle_acct_info_state);
  187     bool noexist_delete = false;
  188     struct ldb_message *msg;
  189     int ret;
  190 
  191     if (state->conn[state->cindex] == NULL) {
  192         return EOK;
  193     }
  194 
  195     if (state->conn[state->cindex+1] == NULL) {
  196         noexist_delete = true;
  197     }
  198 
  199 
  200     state->using_pac = false;
  201     if ((state->ar->entry_type & BE_REQ_TYPE_MASK) == BE_REQ_INITGROUPS) {
  202         ret = check_if_pac_is_available(state, state->sdom->dom,
  203                                         state->ar, &msg);
  204 
  205         if (ret == EOK) {
  206             /* evaluate PAC */
  207             state->using_pac = true;
  208             subreq = ad_handle_pac_initgr_send(state, state->ctx->be,
  209                                                state->ar, state->ctx,
  210                                                state->sdom,
  211                                                state->conn[state->cindex],
  212                                                noexist_delete,
  213                                                msg);
  214             if (subreq == NULL) {
  215                 DEBUG(SSSDBG_OP_FAILURE, "ad_handle_pac_initgr_send failed.\n");
  216                 return ENOMEM;
  217             }
  218 
  219         }
  220 
  221         /* Fall through if there is no PAC or any other error */
  222     }
  223 
  224     if (subreq == NULL) {
  225         subreq = sdap_handle_acct_req_send(state, state->ctx->be,
  226                                            state->ar, state->ctx,
  227                                            state->sdom,
  228                                            state->conn[state->cindex],
  229                                            noexist_delete);
  230         if (subreq == NULL) {
  231             return ENOMEM;
  232         }
  233     }
  234 
  235     tevent_req_set_callback(subreq, ad_handle_acct_info_done, req);
  236     return EAGAIN;
  237 }
  238 
  239 static void
  240 ad_handle_acct_info_done(struct tevent_req *subreq)
  241 {
  242     errno_t ret;
  243     int dp_error;
  244     int sdap_err;
  245     const char *err;
  246     struct tevent_req *req = tevent_req_callback_data(subreq,
  247                                                       struct tevent_req);
  248     struct ad_handle_acct_info_state *state = tevent_req_data(req,
  249                                             struct ad_handle_acct_info_state);
  250 
  251     if (state->using_pac) {
  252         ret = ad_handle_pac_initgr_recv(subreq, &dp_error, &err, &sdap_err);
  253     } else {
  254         ret = sdap_handle_acct_req_recv(subreq, &dp_error, &err, &sdap_err);
  255     }
  256     if (dp_error == DP_ERR_OFFLINE
  257         && state->conn[state->cindex+1] != NULL
  258         && state->conn[state->cindex]->ignore_mark_offline) {
  259          /* This is a special case: GC does not work.
  260           *  We need to Fall back to ldap
  261           */
  262         ret = EOK;
  263         sdap_err = ENOENT;
  264     }
  265     talloc_zfree(subreq);
  266     if (ret != EOK) {
  267         /* if GC was not used dp error should be set */
  268         state->dp_error = dp_error;
  269         state->err = err;
  270 
  271         goto fail;
  272     }
  273 
  274     if (sdap_err == EOK) {
  275         tevent_req_done(req);
  276         return;
  277     } else if (sdap_err != ENOENT) {
  278         ret = EIO;
  279         goto fail;
  280     }
  281 
  282     /* Ret is only ENOENT now. Try the next connection */
  283     state->cindex++;
  284     ret = ad_handle_acct_info_step(req);
  285     if (ret != EAGAIN) {
  286         /* No additional search in progress. Save the last
  287          * error status, we'll be returning it.
  288          */
  289         state->dp_error = dp_error;
  290         state->err = err;
  291 
  292         if (ret == EOK) {
  293             /* No more connections */
  294             tevent_req_done(req);
  295         } else {
  296             goto fail;
  297         }
  298         return;
  299     }
  300 
  301     /* Another lookup in progress */
  302     return;
  303 
  304 fail:
  305     if (IS_SUBDOMAIN(state->sdom->dom)) {
  306         /* Deactivate subdomain on lookup errors instead of going
  307          * offline completely.
  308          * This is a stopgap, until our failover is per-domain,
  309          * not per-backend. Unfortunately, we can't rewrite the error
  310          * code on some reported codes only, because sdap_id_op code
  311          * encapsulated the failover as well..
  312          */
  313         ret = ERR_SUBDOM_INACTIVE;
  314     }
  315     tevent_req_error(req, ret);
  316     return;
  317 }
  318 
  319 errno_t
  320 ad_handle_acct_info_recv(struct tevent_req *req,
  321                          int *_dp_error, const char **_err)
  322 {
  323     struct ad_handle_acct_info_state *state = tevent_req_data(req,
  324                                             struct ad_handle_acct_info_state);
  325 
  326     if (_dp_error) {
  327         *_dp_error = state->dp_error;
  328     }
  329 
  330     if (_err) {
  331         *_err = state->err;
  332     }
  333 
  334     TEVENT_REQ_RETURN_ON_ERROR(req);
  335     return EOK;
  336 }
  337 
  338 struct sdap_id_conn_ctx **
  339 get_conn_list(TALLOC_CTX *mem_ctx, struct ad_id_ctx *ad_ctx,
  340               struct sss_domain_info *dom, struct dp_id_data *ar)
  341 {
  342     struct sdap_id_conn_ctx **clist;
  343 
  344     switch (ar->entry_type & BE_REQ_TYPE_MASK) {
  345     case BE_REQ_USER: /* user */
  346         clist = ad_user_conn_list(mem_ctx, ad_ctx, dom);
  347         break;
  348     case BE_REQ_BY_SECID:   /* by SID */
  349     case BE_REQ_USER_AND_GROUP: /* get SID */
  350     case BE_REQ_GROUP: /* group */
  351     case BE_REQ_INITGROUPS: /* init groups for user */
  352         clist = ad_gc_conn_list(mem_ctx, ad_ctx, dom);
  353         break;
  354     default:
  355         /* Requests for other object should only contact LDAP by default */
  356         clist = ad_ldap_conn_list(mem_ctx, ad_ctx, dom);
  357         break;
  358     }
  359 
  360     return clist;
  361 }
  362 
  363 struct ad_account_info_state {
  364     const char *err_msg;
  365     int dp_error;
  366 };
  367 
  368 static void ad_account_info_done(struct tevent_req *subreq);
  369 
  370 struct tevent_req *
  371 ad_account_info_send(TALLOC_CTX *mem_ctx,
  372                      struct be_ctx *be_ctx,
  373                      struct ad_id_ctx *id_ctx,
  374                      struct dp_id_data *data)
  375 {
  376     struct sss_domain_info *domain = NULL;
  377     struct ad_account_info_state *state = NULL;
  378     struct tevent_req *req = NULL;
  379     struct tevent_req *subreq = NULL;
  380     struct sdap_id_conn_ctx **clist = NULL;
  381     struct sdap_id_ctx *sdap_id_ctx = NULL;
  382     struct sdap_domain *sdom;
  383     errno_t ret;
  384 
  385     req = tevent_req_create(mem_ctx, &state,
  386                             struct ad_account_info_state);
  387     if (req == NULL) {
  388         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
  389         return NULL;
  390     }
  391 
  392     sdap_id_ctx = id_ctx->sdap_id_ctx;
  393 
  394     domain = be_ctx->domain;
  395     if (strcasecmp(data->domain, be_ctx->domain->name) != 0) {
  396         /* Subdomain request, verify subdomain. */
  397         domain = find_domain_by_name(be_ctx->domain, data->domain, true);
  398     }
  399 
  400     if (domain == NULL) {
  401         DEBUG(SSSDBG_CRIT_FAILURE, "Unknown domain\n");
  402         ret = EINVAL;
  403         goto immediately;
  404     }
  405 
  406     /* Determine whether to connect to GC, LDAP or try both. */
  407     clist = get_conn_list(state, id_ctx, domain, data);
  408     if (clist == NULL) {
  409         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot create conn list\n");
  410         ret = EIO;
  411         goto immediately;
  412     }
  413 
  414     sdom = sdap_domain_get(sdap_id_ctx->opts, domain);
  415     if (sdom == NULL) {
  416         ret = EIO;
  417         goto immediately;
  418     }
  419 
  420     subreq = ad_handle_acct_info_send(state, data, sdap_id_ctx,
  421                                       id_ctx->ad_options, sdom, clist);
  422     if (subreq == NULL) {
  423         ret = ENOMEM;
  424         goto immediately;
  425     }
  426     tevent_req_set_callback(subreq, ad_account_info_done, req);
  427     return req;
  428 
  429 immediately:
  430     tevent_req_error(req, ret);
  431     tevent_req_post(req, be_ctx->ev);
  432     return req;
  433 }
  434 
  435 static void ad_account_info_done(struct tevent_req *subreq)
  436 {
  437     struct ad_account_info_state *state = NULL;
  438     struct tevent_req *req = NULL;
  439     errno_t ret;
  440 
  441     req = tevent_req_callback_data(subreq, struct tevent_req);
  442     state = tevent_req_data(req, struct ad_account_info_state);
  443 
  444     ret = ad_handle_acct_info_recv(subreq, &state->dp_error, &state->err_msg);
  445     if (ret != EOK) {
  446         DEBUG(SSSDBG_OP_FAILURE,
  447               "ad_handle_acct_info_recv failed [%d]: %s\n",
  448               ret, sss_strerror(ret));
  449         /* The caller wouldn't fail either, just report the error up */
  450     }
  451     talloc_zfree(subreq);
  452     tevent_req_done(req);
  453 }
  454 
  455 errno_t ad_account_info_recv(struct tevent_req *req,
  456                              int *_dp_error,
  457                              const char **_err_msg)
  458 {
  459     struct ad_account_info_state *state = NULL;
  460 
  461     state = tevent_req_data(req, struct ad_account_info_state);
  462 
  463     if (_err_msg != NULL) {
  464         *_err_msg = state->err_msg;
  465     }
  466 
  467     if (_dp_error) {
  468         *_dp_error = state->dp_error;
  469     }
  470 
  471 
  472     TEVENT_REQ_RETURN_ON_ERROR(req);
  473 
  474     return EOK;
  475 }
  476 
  477 struct ad_account_info_handler_state {
  478     struct sss_domain_info *domain;
  479     struct dp_reply_std reply;
  480 };
  481 
  482 static void ad_account_info_handler_done(struct tevent_req *subreq);
  483 
  484 struct tevent_req *
  485 ad_account_info_handler_send(TALLOC_CTX *mem_ctx,
  486                               struct ad_id_ctx *id_ctx,
  487                               struct dp_id_data *data,
  488                               struct dp_req_params *params)
  489 {
  490     struct ad_account_info_handler_state *state;
  491     struct tevent_req *subreq;
  492     struct tevent_req *req;
  493     errno_t ret;
  494 
  495 
  496     req = tevent_req_create(mem_ctx, &state,
  497                             struct ad_account_info_handler_state);
  498     if (req == NULL) {
  499         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
  500         return NULL;
  501     }
  502 
  503     if (sdap_is_enum_request(data)) {
  504         DEBUG(SSSDBG_TRACE_LIBS, "Skipping enumeration on demand\n");
  505         ret = EOK;
  506         goto immediately;
  507     }
  508 
  509     subreq = ad_account_info_send(state, params->be_ctx, id_ctx, data);
  510     if (subreq == NULL) {
  511         ret = ENOMEM;
  512         goto immediately;
  513     }
  514 
  515     tevent_req_set_callback(subreq, ad_account_info_handler_done, req);
  516 
  517     return req;
  518 
  519 immediately:
  520     dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
  521 
  522     /* TODO For backward compatibility we always return EOK to DP now. */
  523     tevent_req_done(req);
  524     tevent_req_post(req, params->ev);
  525 
  526     return req;
  527 }
  528 
  529 static void ad_account_info_handler_done(struct tevent_req *subreq)
  530 {
  531     struct ad_account_info_handler_state *state;
  532     struct tevent_req *req;
  533     const char *err_msg;
  534     int dp_error = DP_ERR_FATAL;
  535     errno_t ret;
  536 
  537     req = tevent_req_callback_data(subreq, struct tevent_req);
  538     state = tevent_req_data(req, struct ad_account_info_handler_state);
  539 
  540     ret = ad_account_info_recv(subreq, &dp_error, &err_msg);
  541     talloc_zfree(subreq);
  542 
  543     /* TODO For backward compatibility we always return EOK to DP now. */
  544     dp_reply_std_set(&state->reply, dp_error, ret, err_msg);
  545     tevent_req_done(req);
  546 }
  547 
  548 errno_t ad_account_info_handler_recv(TALLOC_CTX *mem_ctx,
  549                                      struct tevent_req *req,
  550                                      struct dp_reply_std *data)
  551 {
  552     struct ad_account_info_handler_state *state = NULL;
  553 
  554     state = tevent_req_data(req, struct ad_account_info_handler_state);
  555 
  556     TEVENT_REQ_RETURN_ON_ERROR(req);
  557 
  558     *data = state->reply;
  559 
  560     return EOK;
  561 }
  562 
  563 struct ad_enumeration_state {
  564     struct ad_id_ctx *id_ctx;
  565     struct ldap_enum_ctx *ectx;
  566     struct sdap_id_op *sdap_op;
  567     struct tevent_context *ev;
  568 
  569     const char *realm;
  570     struct sdap_domain *sdom;
  571     struct sdap_domain *sditer;
  572 };
  573 
  574 static void ad_enumeration_conn_done(struct tevent_req *subreq);
  575 static void ad_enumeration_master_done(struct tevent_req *subreq);
  576 static errno_t ad_enum_sdom(struct tevent_req *req, struct sdap_domain *sd,
  577                             struct ad_id_ctx *id_ctx);
  578 static void ad_enumeration_done(struct tevent_req *subreq);
  579 
  580 struct tevent_req *
  581 ad_id_enumeration_send(TALLOC_CTX *mem_ctx,
  582                        struct tevent_context *ev,
  583                        struct be_ctx *be_ctx,
  584                        struct be_ptask *be_ptask,
  585                        void *pvt)
  586 {
  587     struct tevent_req *req;
  588     struct tevent_req *subreq;
  589     struct ad_enumeration_state *state;
  590     struct ldap_enum_ctx *ectx;
  591     errno_t ret;
  592 
  593     req = tevent_req_create(mem_ctx, &state, struct ad_enumeration_state);
  594     if (req == NULL) return NULL;
  595 
  596     ectx = talloc_get_type(pvt, struct ldap_enum_ctx);
  597     if (ectx == NULL) {
  598         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot retrieve ldap_enum_ctx!\n");
  599         ret = EFAULT;
  600         goto fail;
  601     }
  602 
  603     state->ectx = ectx;
  604     state->ev = ev;
  605     state->sdom = ectx->sdom;
  606     state->sditer = state->sdom;
  607     state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
  608 
  609     state->realm = dp_opt_get_cstring(state->id_ctx->ad_options->basic,
  610                                       AD_KRB5_REALM);
  611     if (state->realm == NULL) {
  612         DEBUG(SSSDBG_CONF_SETTINGS, "Missing realm\n");
  613         ret = EINVAL;
  614         goto fail;
  615     }
  616 
  617     state->sdap_op = sdap_id_op_create(state,
  618                                        state->id_ctx->ldap_ctx->conn_cache);
  619     if (state->sdap_op == NULL) {
  620         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed.\n");
  621         ret = ENOMEM;
  622         goto fail;
  623     }
  624 
  625     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
  626     if (subreq == NULL) {
  627         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
  628                                   ret, strerror(ret));
  629         goto fail;
  630     }
  631     tevent_req_set_callback(subreq, ad_enumeration_conn_done, req);
  632 
  633     return req;
  634 
  635 fail:
  636     tevent_req_error(req, ret);
  637     tevent_req_post(req, ev);
  638     return req;
  639 }
  640 
  641 static void
  642 ad_enumeration_conn_done(struct tevent_req *subreq)
  643 {
  644     struct tevent_req *req = tevent_req_callback_data(subreq,
  645                                                       struct tevent_req);
  646     struct ad_enumeration_state *state = tevent_req_data(req,
  647                                                  struct ad_enumeration_state);
  648     int ret, dp_error;
  649 
  650     ret = sdap_id_op_connect_recv(subreq, &dp_error);
  651     talloc_zfree(subreq);
  652     if (ret != EOK) {
  653         if (dp_error == DP_ERR_OFFLINE) {
  654             DEBUG(SSSDBG_TRACE_FUNC,
  655                   "Backend is marked offline, retry later!\n");
  656             tevent_req_done(req);
  657         } else {
  658             DEBUG(SSSDBG_MINOR_FAILURE,
  659                   "Domain enumeration failed to connect to " \
  660                    "LDAP server: (%d)[%s]\n", ret, strerror(ret));
  661             tevent_req_error(req, ret);
  662         }
  663         return;
  664     }
  665 
  666     subreq = ad_master_domain_send(state, state->ev,
  667                                    state->id_ctx->ldap_ctx,
  668                                    state->sdap_op,
  669                                    state->sdom->dom->name);
  670     if (subreq == NULL) {
  671         DEBUG(SSSDBG_OP_FAILURE, "ad_master_domain_send failed.\n");
  672         tevent_req_error(req, ret);
  673         return;
  674     }
  675     tevent_req_set_callback(subreq, ad_enumeration_master_done, req);
  676 }
  677 
  678 static void
  679 ad_enumeration_master_done(struct tevent_req *subreq)
  680 {
  681     errno_t ret;
  682     struct tevent_req *req = tevent_req_callback_data(subreq,
  683                                                       struct tevent_req);
  684     struct ad_enumeration_state *state = tevent_req_data(req,
  685                                                 struct ad_enumeration_state);
  686     char *flat_name;
  687     char *master_sid;
  688     char *forest;
  689 
  690     ret = ad_master_domain_recv(subreq, state,
  691                                 &flat_name, &master_sid, NULL, &forest);
  692     talloc_zfree(subreq);
  693     if (ret != EOK) {
  694         DEBUG(SSSDBG_OP_FAILURE, "Cannot retrieve master domain info\n");
  695         tevent_req_error(req, ret);
  696         return;
  697     }
  698 
  699     ret = sysdb_master_domain_add_info(state->sdom->dom, state->realm,
  700                                        flat_name, master_sid, forest, NULL);
  701     if (ret != EOK) {
  702         DEBUG(SSSDBG_OP_FAILURE, "Cannot save master domain info\n");
  703         tevent_req_error(req, ret);
  704         return;
  705     }
  706 
  707     ret = ad_enum_sdom(req, state->sdom, state->id_ctx);
  708     if (ret != EOK) {
  709         DEBUG(SSSDBG_OP_FAILURE,
  710                 "Could not enumerate domain %s\n", state->sdom->dom->name);
  711         tevent_req_error(req, ret);
  712         return;
  713     }
  714 
  715     /* Execution will resume in ad_enumeration_done */
  716 }
  717 
  718 static errno_t
  719 ad_enum_sdom(struct tevent_req *req,
  720              struct sdap_domain *sd,
  721              struct ad_id_ctx *id_ctx)
  722 {
  723     struct sdap_id_conn_ctx *user_conn;
  724     struct tevent_req *subreq;
  725     struct ad_enumeration_state *state = tevent_req_data(req,
  726                                                 struct ad_enumeration_state);
  727 
  728     if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC)) {
  729         user_conn = id_ctx->gc_ctx;
  730     } else {
  731         user_conn = id_ctx->ldap_ctx;
  732     }
  733 
  734     /* Groups are searched for in LDAP, users in GC. Services (if present,
  735      * which is unlikely in AD) from LDAP as well
  736      */
  737     subreq = sdap_dom_enum_ex_send(state, state->ev,
  738                                    id_ctx->sdap_id_ctx,
  739                                    sd,
  740                                    user_conn,         /* Users    */
  741                                    id_ctx->ldap_ctx,  /* Groups   */
  742                                    id_ctx->ldap_ctx); /* Services */
  743     if (subreq == NULL) {
  744         /* The ptask API will reschedule the enumeration on its own on
  745          * failure */
  746         DEBUG(SSSDBG_OP_FAILURE,
  747               "Failed to schedule enumeration, retrying later!\n");
  748         return ENOMEM;
  749     }
  750     tevent_req_set_callback(subreq, ad_enumeration_done, req);
  751 
  752     return EOK;
  753 }
  754 
  755 static errno_t ad_enum_cross_dom_members(struct sdap_options *opts,
  756                                          struct sss_domain_info *dom);
  757 
  758 static void
  759 ad_enumeration_done(struct tevent_req *subreq)
  760 {
  761     errno_t ret;
  762     struct tevent_req *req = tevent_req_callback_data(subreq,
  763                                                       struct tevent_req);
  764     struct ad_enumeration_state *state = tevent_req_data(req,
  765                                                 struct ad_enumeration_state);
  766 
  767     ret = sdap_dom_enum_ex_recv(subreq);
  768     talloc_zfree(subreq);
  769     if (ret != EOK) {
  770         DEBUG(SSSDBG_OP_FAILURE,
  771               "Could not enumerate domain %s\n", state->sditer->dom->name);
  772         tevent_req_error(req, ret);
  773         return;
  774     }
  775 
  776     do {
  777         state->sditer = state->sditer->next;
  778     } while (state->sditer &&
  779              state->sditer->dom->enumerate == false);
  780 
  781     if (state->sditer != NULL) {
  782         ret = ad_enum_sdom(req, state->sditer, state->sditer->pvt);
  783         if (ret != EOK) {
  784             DEBUG(SSSDBG_OP_FAILURE, "Could not enumerate domain %s\n",
  785                   state->sditer->dom->name);
  786             tevent_req_error(req, ret);
  787             return;
  788         }
  789 
  790         /* Execution will resume in ad_enumeration_done */
  791         return;
  792     }
  793 
  794     /* No more subdomains to enumerate. Check if we need to fixup
  795      * cross-domain membership
  796      */
  797     if (state->sditer != state->sdom) {
  798         /* We did enumerate at least one subdomain. Walk the subdomains
  799          * and fixup members for each of them
  800          */
  801         for (state->sditer = state->sdom;
  802              state->sditer;
  803              state->sditer = state->sditer->next) {
  804             ret = ad_enum_cross_dom_members(state->id_ctx->ad_options->id,
  805                                             state->sditer->dom);
  806             if (ret != EOK) {
  807                 DEBUG(SSSDBG_MINOR_FAILURE, "Could not check cross-domain "
  808                       "memberships for %s, group memberships might be "
  809                       "incomplete!\n", state->sdom->dom->name);
  810                 continue;
  811             }
  812         }
  813     }
  814 
  815     tevent_req_done(req);
  816 }
  817 
  818 static errno_t ad_group_extra_members(TALLOC_CTX *mem_ctx,
  819                                       const struct ldb_message *group,
  820                                       struct sss_domain_info *dom,
  821                                       char ***_group_only);
  822 static errno_t ad_group_add_member(struct sdap_options *opts,
  823                                    struct sss_domain_info *group_domain,
  824                                    struct ldb_dn *group_dn,
  825                                    const char *member);
  826 
  827 static errno_t
  828 ad_enum_cross_dom_members(struct sdap_options *opts,
  829                           struct sss_domain_info *dom)
  830 {
  831     errno_t ret;
  832     errno_t sret;
  833     char *filter;
  834     TALLOC_CTX *tmp_ctx;
  835     const char *attrs[] = {
  836             SYSDB_NAME,
  837             SYSDB_MEMBER,
  838             SYSDB_ORIG_MEMBER,
  839             NULL
  840     };
  841     size_t count, i, mi;
  842     struct ldb_message **msgs;
  843     bool in_transaction = false;
  844     char **group_only;
  845 
  846     tmp_ctx = talloc_new(NULL);
  847     if (tmp_ctx == NULL) return ENOMEM;
  848 
  849     ret = sysdb_transaction_start(dom->sysdb);
  850     if (ret != EOK) {
  851         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
  852         goto done;
  853     }
  854     in_transaction = true;
  855 
  856     filter = talloc_asprintf(tmp_ctx, "(%s=*)", SYSDB_NAME);
  857     if (filter == NULL) {
  858         ret = ENOMEM;
  859         goto done;
  860     }
  861 
  862     ret = sysdb_search_groups(tmp_ctx, dom, filter, attrs, &count, &msgs);
  863     if (ret != EOK) {
  864         goto done;
  865     }
  866 
  867     for (i = 0; i < count; i++) {
  868         ret = ad_group_extra_members(tmp_ctx, msgs[i], dom, &group_only);
  869         if (ret != EOK) {
  870             DEBUG(SSSDBG_OP_FAILURE, "Failed to check extra members\n");
  871             continue;
  872         } else if (group_only == NULL) {
  873             DEBUG(SSSDBG_TRACE_INTERNAL, "No extra members\n");
  874             continue;
  875         }
  876 
  877         /* Group has extra members */
  878         for (mi = 0; group_only[mi]; mi++) {
  879             ret = ad_group_add_member(opts, dom, msgs[i]->dn, group_only[mi]);
  880             if (ret != EOK) {
  881                 DEBUG(SSSDBG_MINOR_FAILURE, "Failed to add [%s]: %s\n",
  882                       group_only[mi], strerror(ret));
  883                 continue;
  884             }
  885         }
  886 
  887         talloc_zfree(group_only);
  888     }
  889 
  890     ret = sysdb_transaction_commit(dom->sysdb);
  891     if (ret != EOK) {
  892         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
  893         goto done;
  894     }
  895     in_transaction = false;
  896 
  897     ret = EOK;
  898 done:
  899     if (in_transaction) {
  900         sret = sysdb_transaction_cancel(dom->sysdb);
  901         if (sret != EOK) {
  902             DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
  903         }
  904     }
  905     talloc_free(tmp_ctx);
  906     return ret;
  907 }
  908 
  909 static errno_t
  910 ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
  911                              struct ldb_dn *dn, char ***_odn_list);
  912 
  913 static errno_t
  914 ad_group_extra_members(TALLOC_CTX *mem_ctx, const struct ldb_message *group,
  915                        struct sss_domain_info *dom, char ***_group_only)
  916 {
  917     TALLOC_CTX *tmp_ctx;
  918     struct ldb_message_element *m, *om;
  919     const char *name;
  920     errno_t ret;
  921     char **sysdb_odn_list;
  922     const char **group_odn_list;
  923     char **group_only = NULL;
  924 
  925     if (_group_only == NULL) return EINVAL;
  926     *_group_only = NULL;
  927 
  928     tmp_ctx = talloc_new(NULL);
  929     if (tmp_ctx == NULL) return ENOMEM;
  930 
  931     om = ldb_msg_find_element(group, SYSDB_ORIG_MEMBER);
  932     m = ldb_msg_find_element(group, SYSDB_MEMBER);
  933     name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
  934     if (name == NULL) {
  935         DEBUG(SSSDBG_OP_FAILURE, "A group with no name!\n");
  936         ret = EFAULT;
  937         goto done;
  938     }
  939 
  940     if (om == NULL || om->num_values == 0) {
  941         DEBUG(SSSDBG_TRACE_FUNC, "Group %s has no original members\n", name);
  942         ret = EOK;
  943         goto done;
  944     }
  945 
  946     if (m == NULL || (m->num_values < om->num_values)) {
  947         DEBUG(SSSDBG_TRACE_FUNC,
  948               "Group %s has %d members but %d original members\n",
  949                name, m ? m->num_values : 0, om->num_values);
  950 
  951         /* Get the list of originalDN attributes that are already
  952          * linked to the group
  953          */
  954         ret = ad_group_stored_orig_members(tmp_ctx, dom, group->dn,
  955                                            &sysdb_odn_list);
  956         if (ret != EOK) {
  957             DEBUG(SSSDBG_OP_FAILURE,
  958                   "Could not retrieve list of original members for %s\n",
  959                   name);
  960             goto done;
  961         }
  962 
  963         /* Get the list of original DN attributes the group had in AD */
  964         group_odn_list = sss_ldb_el_to_string_list(tmp_ctx, om);
  965         if (group_odn_list == NULL) {
  966             ret = EFAULT;
  967             goto done;
  968         }
  969 
  970         /* Compare the two lists */
  971         ret = diff_string_lists(tmp_ctx, discard_const(group_odn_list),
  972                                 sysdb_odn_list, &group_only, NULL, NULL);
  973         if (ret != EOK) {
  974             DEBUG(SSSDBG_OP_FAILURE,
  975                   "Could not compare lists of members for %s\n", name);
  976             goto done;
  977         }
  978     }
  979 
  980     ret = EOK;
  981     *_group_only = talloc_steal(mem_ctx, group_only);
  982 done:
  983     talloc_free(tmp_ctx);
  984     return ret;
  985 }
  986 
  987 static errno_t
  988 ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
  989                              struct ldb_dn *dn, char ***_odn_list)
  990 {
  991     errno_t ret;
  992     TALLOC_CTX *tmp_ctx;
  993     size_t m_count, i;
  994     struct ldb_message **members;
  995     const char *attrs[] = {
  996             SYSDB_NAME,
  997             SYSDB_ORIG_DN,
  998             NULL
  999     };
 1000     char **odn_list;
 1001     const char *odn;
 1002     size_t oi;
 1003 
 1004     tmp_ctx = talloc_new(NULL);
 1005     if (tmp_ctx == NULL) return ENOMEM;
 1006 
 1007     /* Get all entries member element points to */
 1008     ret = sysdb_asq_search(tmp_ctx, dom, dn, NULL, SYSDB_MEMBER,
 1009                            attrs, &m_count, &members);
 1010     if (ret != EOK) {
 1011         goto done;
 1012     }
 1013 
 1014     odn_list = talloc_zero_array(tmp_ctx, char *, m_count + 1);
 1015     if (odn_list == NULL) {
 1016         ret = ENOMEM;
 1017         goto done;
 1018     }
 1019 
 1020     /* Get a list of their original DNs */
 1021     oi = 0;
 1022     for (i = 0; i < m_count; i++) {
 1023         odn = ldb_msg_find_attr_as_string(members[i], SYSDB_ORIG_DN, NULL);
 1024         if (odn == NULL) {
 1025             continue;
 1026         }
 1027 
 1028         odn_list[oi] = talloc_strdup(odn_list, odn);
 1029         if (odn_list[oi] == NULL) {
 1030             ret = ENOMEM;
 1031             goto done;
 1032         }
 1033         oi++;
 1034         DEBUG(SSSDBG_TRACE_INTERNAL, "Member %s already in sysdb\n", odn);
 1035     }
 1036 
 1037     ret = EOK;
 1038     *_odn_list = talloc_steal(mem_ctx, odn_list);
 1039 done:
 1040     talloc_free(tmp_ctx);
 1041     return ret;
 1042 }
 1043 
 1044 static errno_t
 1045 ad_group_add_member(struct sdap_options *opts,
 1046                     struct sss_domain_info *group_domain,
 1047                     struct ldb_dn *group_dn,
 1048                     const char *member)
 1049 {
 1050     struct sdap_domain *sd;
 1051     struct ldb_dn *base_dn;
 1052     TALLOC_CTX *tmp_ctx;
 1053     errno_t ret;
 1054     const char *mem_filter;
 1055     size_t msgs_count;
 1056     struct ldb_message **msgs;
 1057 
 1058     /* This member would be from a different domain */
 1059     sd = sdap_domain_get_by_dn(opts, member);
 1060     if (sd == NULL) {
 1061         DEBUG(SSSDBG_MINOR_FAILURE, "No matching domain for %s\n", member);
 1062         return ENOENT;
 1063     }
 1064 
 1065     tmp_ctx = talloc_new(NULL);
 1066     if (tmp_ctx == NULL) return ENOMEM;
 1067 
 1068     mem_filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
 1069                                  SYSDB_ORIG_DN, member);
 1070     if (mem_filter == NULL) {
 1071         ret = ENOMEM;
 1072         goto done;
 1073     }
 1074 
 1075     base_dn = sysdb_domain_dn(tmp_ctx, sd->dom);
 1076     if (base_dn == NULL) {
 1077         ret = ENOMEM;
 1078         goto done;
 1079     }
 1080 
 1081     ret = sysdb_search_entry(tmp_ctx, sd->dom->sysdb, base_dn,
 1082                              LDB_SCOPE_SUBTREE, mem_filter, NULL,
 1083                              &msgs_count, &msgs);
 1084     if (ret == ENOENT) {
 1085         DEBUG(SSSDBG_TRACE_FUNC, "No member [%s] in sysdb\n", member);
 1086         ret = EOK;
 1087         goto done;
 1088     } else if (ret != EOK) {
 1089         goto done;
 1090     }
 1091     DEBUG(SSSDBG_TRACE_INTERNAL, "[%s] found in sysdb\n", member);
 1092 
 1093     if (msgs_count != 1) {
 1094         DEBUG(SSSDBG_CRIT_FAILURE,
 1095                "Search by orig DN returned %zd results!\n", msgs_count);
 1096         ret = EFAULT;
 1097         goto done;
 1098     }
 1099 
 1100     ret = sysdb_mod_group_member(group_domain, msgs[0]->dn, group_dn, SYSDB_MOD_ADD);
 1101     if (ret != EOK) {
 1102         DEBUG(SSSDBG_OP_FAILURE, "Could not add [%s] as a member of [%s]\n",
 1103               ldb_dn_get_linearized(msgs[0]->dn),
 1104               ldb_dn_get_linearized(group_dn));
 1105         goto done;
 1106     }
 1107 
 1108     ret = EOK;
 1109 done:
 1110     talloc_free(tmp_ctx);
 1111     return ret;
 1112 }
 1113 
 1114 errno_t
 1115 ad_id_enumeration_recv(struct tevent_req *req)
 1116 {
 1117     TEVENT_REQ_RETURN_ON_ERROR(req);
 1118     return EOK;
 1119 }
 1120 
 1121 static errno_t ad_get_account_domain_prepare_search(struct tevent_req *req);
 1122 static errno_t ad_get_account_domain_connect_retry(struct tevent_req *req);
 1123 static void ad_get_account_domain_connect_done(struct tevent_req *subreq);
 1124 static void ad_get_account_domain_search(struct tevent_req *req);
 1125 static void ad_get_account_domain_search_done(struct tevent_req *subreq);
 1126 static void ad_get_account_domain_evaluate(struct tevent_req *req);
 1127 
 1128 struct ad_get_account_domain_state {
 1129     struct tevent_context *ev;
 1130     struct ad_id_ctx *id_ctx;
 1131     struct sdap_id_ctx *sdap_id_ctx;
 1132     struct sdap_domain *sdom;
 1133     uint32_t entry_type;
 1134     uint32_t filter_type;
 1135     char *clean_filter;
 1136 
 1137     bool twopass;
 1138 
 1139     struct sdap_search_base **search_bases;
 1140     size_t base_iter;
 1141     const char *base_filter;
 1142     char *filter;
 1143     const char **attrs;
 1144     int dp_error;
 1145     struct dp_reply_std reply;
 1146     struct sdap_id_op *op;
 1147     struct sysdb_attrs **objects;
 1148     size_t count;
 1149 
 1150     const char *found_domain_name;
 1151 };
 1152 
 1153 struct tevent_req *
 1154 ad_get_account_domain_send(TALLOC_CTX *mem_ctx,
 1155                            struct ad_id_ctx *id_ctx,
 1156                            struct dp_get_acct_domain_data *data,
 1157                            struct dp_req_params *params)
 1158 {
 1159     struct ad_get_account_domain_state *state;
 1160     struct tevent_req *req;
 1161     errno_t ret;
 1162     bool use_id_mapping;
 1163 
 1164     req = tevent_req_create(mem_ctx, &state,
 1165                             struct ad_get_account_domain_state);
 1166     if (req == NULL) {
 1167         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create() failed\n");
 1168         return NULL;
 1169     }
 1170     state->ev = params->ev;
 1171     state->id_ctx = id_ctx;
 1172     state->sdap_id_ctx = id_ctx->sdap_id_ctx;
 1173     state->entry_type = data->entry_type & BE_REQ_TYPE_MASK;
 1174     state->filter_type = data->filter_type;
 1175     state->attrs = talloc_array(state, const char *, 2);
 1176     if (state->attrs == NULL) {
 1177         ret = ENOMEM;
 1178         goto immediately;
 1179     }
 1180     state->attrs[0] = "objectclass";
 1181     state->attrs[1] = NULL;
 1182 
 1183     if (sss_domain_is_mpg(params->be_ctx->domain) == true
 1184             || state->entry_type == BE_REQ_USER_AND_GROUP) {
 1185         state->twopass = true;
 1186         if (state->entry_type == BE_REQ_USER_AND_GROUP) {
 1187             state->entry_type = BE_REQ_GROUP;
 1188         }
 1189     }
 1190 
 1191     /* The get-account-domain request only works with GC */
 1192     if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC) == false) {
 1193         DEBUG(SSSDBG_CONF_SETTINGS,
 1194               "Global catalog support is not enabled, "
 1195               "cannot locate the account domain\n");
 1196         ret = ERR_GET_ACCT_DOM_NOT_SUPPORTED;
 1197         goto immediately;
 1198     }
 1199 
 1200     state->sdom = sdap_domain_get(id_ctx->sdap_id_ctx->opts,
 1201                                   params->be_ctx->domain);
 1202     if (state->sdom == NULL) {
 1203         DEBUG(SSSDBG_CRIT_FAILURE, "Cannot find sdap_domain\n");
 1204         ret = EIO;
 1205         goto immediately;
 1206     }
 1207 
 1208     /* Currently we only support locating the account domain
 1209      * if ID mapping is disabled. With ID mapping enabled, we can
 1210      * already shortcut the 'real' ID request
 1211      */
 1212     use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
 1213                                         state->sdap_id_ctx->opts->idmap_ctx,
 1214                                         state->sdom->dom->name,
 1215                                         state->sdom->dom->domain_id);
 1216     if (use_id_mapping == true) {
 1217         DEBUG(SSSDBG_CONF_SETTINGS,
 1218               "No point in locating domain with GC if ID-mapping "
 1219               "is enabled\n");
 1220         ret = ERR_GET_ACCT_DOM_NOT_SUPPORTED;
 1221         goto immediately;
 1222     }
 1223 
 1224     ret = sss_filter_sanitize(state, data->filter_value, &state->clean_filter);
 1225     if (ret != EOK) {
 1226         DEBUG(SSSDBG_OP_FAILURE,
 1227               "Cannot sanitize filter [%d]: %s\n", ret, sss_strerror(ret));
 1228         goto immediately;
 1229     }
 1230 
 1231     ret = ad_get_account_domain_prepare_search(req);
 1232     if (ret != EOK) {
 1233         goto immediately;
 1234     }
 1235 
 1236     /* FIXME - should gc_ctx always default to ignore_offline on creation
 1237      * time rather than setting the flag on first use?
 1238      */
 1239     id_ctx->gc_ctx->ignore_mark_offline = true;
 1240     state->op = sdap_id_op_create(state, id_ctx->gc_ctx->conn_cache);
 1241     if (state->op == NULL) {
 1242         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
 1243         ret = ENOMEM;
 1244         goto immediately;
 1245     }
 1246 
 1247     ret = ad_get_account_domain_connect_retry(req);
 1248     if (ret != EOK) {
 1249         DEBUG(SSSDBG_OP_FAILURE, "Connection error");
 1250         goto immediately;
 1251     }
 1252 
 1253     return req;
 1254 
 1255 immediately:
 1256     dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ret, NULL);
 1257 
 1258     /* TODO For backward compatibility we always return EOK to DP now. */
 1259     tevent_req_done(req);
 1260     tevent_req_post(req, params->ev);
 1261 
 1262     return req;
 1263 }
 1264 
 1265 static errno_t ad_get_account_domain_prepare_search(struct tevent_req *req)
 1266 {
 1267     struct ad_get_account_domain_state *state = tevent_req_data(req,
 1268                                           struct ad_get_account_domain_state);
 1269     const char *attr_name = NULL;
 1270     const char *objectclass = NULL;
 1271 
 1272     switch (state->entry_type) {
 1273     case BE_REQ_USER:
 1274         state->search_bases = state->sdom->user_search_bases;
 1275         attr_name = state->sdap_id_ctx->opts->user_map[SDAP_AT_USER_UID].name;
 1276         objectclass = state->sdap_id_ctx->opts->user_map[SDAP_OC_USER].name;
 1277         break;
 1278     case BE_REQ_GROUP:
 1279         state->search_bases = state->sdom->group_search_bases;
 1280         attr_name = state->sdap_id_ctx->opts->group_map[SDAP_AT_GROUP_GID].name;
 1281         objectclass = state->sdap_id_ctx->opts->group_map[SDAP_OC_GROUP].name;
 1282         break;
 1283     default:
 1284         DEBUG(SSSDBG_OP_FAILURE,
 1285               "Unsupported request type %X\n",
 1286               state->entry_type & BE_REQ_TYPE_MASK);
 1287         return EINVAL;
 1288     }
 1289 
 1290     switch (state->filter_type) {
 1291     case BE_FILTER_IDNUM:
 1292         break;
 1293     default:
 1294         DEBUG(SSSDBG_OP_FAILURE,
 1295               "Unsupported filter type %X\n", state->filter_type);
 1296         return EINVAL;
 1297     }
 1298 
 1299     talloc_zfree(state->base_filter);
 1300     state->base_filter = talloc_asprintf(state,
 1301                                          "(&(%s=%s)(objectclass=%s))",
 1302                                          attr_name,
 1303                                          state->clean_filter,
 1304                                          objectclass);
 1305     if (state->base_filter == NULL) {
 1306         return ENOMEM;
 1307     }
 1308 
 1309     return EOK;
 1310 }
 1311 
 1312 static errno_t ad_get_account_domain_connect_retry(struct tevent_req *req)
 1313 {
 1314     struct ad_get_account_domain_state *state = tevent_req_data(req,
 1315                                           struct ad_get_account_domain_state);
 1316     struct tevent_req *subreq;
 1317     errno_t ret;
 1318 
 1319     subreq = sdap_id_op_connect_send(state->op, state, &ret);
 1320     if (subreq == NULL) {
 1321         return ENOMEM;
 1322     }
 1323 
 1324     tevent_req_set_callback(subreq, ad_get_account_domain_connect_done, req);
 1325     return ret;
 1326 }
 1327 
 1328 static void ad_get_account_domain_connect_done(struct tevent_req *subreq)
 1329 {
 1330     struct tevent_req *req = tevent_req_callback_data(subreq,
 1331                                                       struct tevent_req);
 1332     struct ad_get_account_domain_state *state = tevent_req_data(req,
 1333                                           struct ad_get_account_domain_state);
 1334     int dp_error = DP_ERR_FATAL;
 1335     errno_t ret;
 1336 
 1337     ret = sdap_id_op_connect_recv(subreq, &dp_error);
 1338     talloc_zfree(subreq);
 1339 
 1340     if (ret != EOK) {
 1341         state->dp_error = dp_error;
 1342         tevent_req_error(req, ret);
 1343         return;
 1344     }
 1345 
 1346     ad_get_account_domain_search(req);
 1347 }
 1348 
 1349 static void ad_get_account_domain_search(struct tevent_req *req)
 1350 {
 1351     struct ad_get_account_domain_state *state = tevent_req_data(req,
 1352                                           struct ad_get_account_domain_state);
 1353     struct tevent_req *subreq;
 1354 
 1355     talloc_zfree(state->filter);
 1356     state->filter = sdap_combine_filters(state, state->base_filter,
 1357                         state->search_bases[state->base_iter]->filter);
 1358     if (state->filter == NULL) {
 1359         tevent_req_error(req, ENOMEM);
 1360         return;
 1361     }
 1362 
 1363     subreq = sdap_get_generic_send(state, state->ev, state->sdap_id_ctx->opts,
 1364                                    sdap_id_op_handle(state->op),
 1365                                    "",
 1366                                    LDAP_SCOPE_SUBTREE,
 1367                                    state->filter,
 1368                                    state->attrs, NULL, 0,
 1369                                    dp_opt_get_int(state->sdap_id_ctx->opts->basic,
 1370                                                   SDAP_SEARCH_TIMEOUT),
 1371                                    false);
 1372 
 1373     if (subreq == NULL) {
 1374         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
 1375         tevent_req_error(req, EIO);
 1376         return;
 1377     }
 1378 
 1379     tevent_req_set_callback(subreq, ad_get_account_domain_search_done, req);
 1380 }
 1381 
 1382 static void ad_get_account_domain_search_done(struct tevent_req *subreq)
 1383 {
 1384     struct tevent_req *req = tevent_req_callback_data(subreq,
 1385                                                       struct tevent_req);
 1386     struct ad_get_account_domain_state *state = tevent_req_data(req,
 1387                                           struct ad_get_account_domain_state);
 1388     size_t count;
 1389     struct sysdb_attrs **objects;
 1390     errno_t ret;
 1391 
 1392     ret = sdap_get_generic_recv(subreq, state,
 1393                                 &count, &objects);
 1394     talloc_zfree(subreq);
 1395     if (ret) {
 1396         tevent_req_error(req, ret);
 1397         return;
 1398     }
 1399 
 1400     DEBUG(SSSDBG_TRACE_FUNC,
 1401           "Search returned %zu results.\n", count);
 1402 
 1403     if (count > 0) {
 1404         size_t copied;
 1405 
 1406         state->objects =
 1407                 talloc_realloc(state,
 1408                                state->objects,
 1409                                struct sysdb_attrs *,
 1410                                state->count + count + 1);
 1411         if (!state->objects) {
 1412             tevent_req_error(req, ENOMEM);
 1413             return;
 1414         }
 1415 
 1416         copied = sdap_steal_objects_in_dom(state->sdap_id_ctx->opts,
 1417                                            state->objects,
 1418                                            state->count,
 1419                                            NULL,
 1420                                            objects, count,
 1421                                            false);
 1422 
 1423         state->count += copied;
 1424         state->objects[state->count] = NULL;
 1425     }
 1426 
 1427     /* Even though we search with an empty search base (=across all domains)
 1428      * the reason we iterate over search bases is that the search bases can
 1429      * also contain a filter which might restrict the IDs we find
 1430      */
 1431     state->base_iter++;
 1432     if (state->search_bases[state->base_iter]) {
 1433         /* There are more search bases to try */
 1434         ad_get_account_domain_search(req);
 1435         return;
 1436     }
 1437 
 1438     /* No more searches, evaluate results */
 1439     ad_get_account_domain_evaluate(req);
 1440 }
 1441 
 1442 static void ad_get_account_domain_evaluate(struct tevent_req *req)
 1443 {
 1444     struct ad_get_account_domain_state *state = tevent_req_data(req,
 1445                                           struct ad_get_account_domain_state);
 1446     struct sss_domain_info *obj_dom;
 1447     errno_t ret;
 1448 
 1449     if (state->count == 0) {
 1450         if (state->twopass
 1451                 && state->entry_type != BE_REQ_USER) {
 1452             DEBUG(SSSDBG_TRACE_FUNC, "Retrying search\n");
 1453 
 1454             state->entry_type = BE_REQ_USER;
 1455             state->base_iter = 0;
 1456             ret = ad_get_account_domain_prepare_search(req);
 1457             if (ret != EOK) {
 1458                 DEBUG(SSSDBG_OP_FAILURE, "Cannot retry search\n");
 1459                 tevent_req_error(req, ret);
 1460                 return;
 1461             }
 1462 
 1463             ad_get_account_domain_search(req);
 1464             return;
 1465         }
 1466 
 1467         DEBUG(SSSDBG_TRACE_FUNC, "Not found\n");
 1468         dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ERR_NOT_FOUND, NULL);
 1469         tevent_req_done(req);
 1470         return;
 1471     } else if (state->count > 1) {
 1472         /* FIXME: If more than one entry was found, return error for now
 1473          * as the account requsts have no way of returning multiple
 1474          * messages back until we switch to the rdp_* requests
 1475          * from the responder side
 1476          */
 1477         DEBUG(SSSDBG_OP_FAILURE, "Multiple entries found, error!\n");
 1478         dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ERANGE, NULL);
 1479         tevent_req_done(req);
 1480         return;
 1481     }
 1482 
 1483     /* Exactly one entry was found */
 1484     obj_dom = sdap_get_object_domain(state->sdap_id_ctx->opts,
 1485                                      state->objects[0],
 1486                                      state->sdom->dom);
 1487     if (obj_dom == NULL) {
 1488         DEBUG(SSSDBG_OP_FAILURE,
 1489               "Could not match entry with domain!\n");
 1490         dp_reply_std_set(&state->reply, DP_ERR_DECIDE, ERR_NOT_FOUND, NULL);
 1491         tevent_req_done(req);
 1492         return;
 1493     }
 1494 
 1495     DEBUG(SSSDBG_TRACE_INTERNAL,
 1496           "Found object in domain %s\n", obj_dom->name);
 1497     dp_reply_std_set(&state->reply, DP_ERR_DECIDE, EOK, obj_dom->name);
 1498     tevent_req_done(req);
 1499 }
 1500 
 1501 errno_t ad_get_account_domain_recv(TALLOC_CTX *mem_ctx,
 1502                                    struct tevent_req *req,
 1503                                    struct dp_reply_std *data)
 1504 {
 1505     struct ad_get_account_domain_state *state = NULL;
 1506 
 1507     state = tevent_req_data(req, struct ad_get_account_domain_state);
 1508 
 1509     TEVENT_REQ_RETURN_ON_ERROR(req);
 1510 
 1511     *data = state->reply;
 1512 
 1513     return EOK;
 1514 }