"Fossies" - the Fresh Open Source Software Archive

Member "sssd-2.2.3/src/providers/ad/ad_pac.c" (30 Nov 2019, 24231 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_pac.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2     SSSD
    3 
    4     Authors:
    5         Sumit Bose <sbose@redhat.com>
    6 
    7     Copyright (C) 2016 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 
   23 #include "util/util.h"
   24 #include "providers/ad/ad_pac.h"
   25 #include "providers/ad/ad_common.h"
   26 #include "providers/ad/ad_id.h"
   27 #include "providers/ldap/sdap_idmap.h"
   28 #include "providers/ldap/sdap_async_ad.h"
   29 
   30 static errno_t find_user_entry(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
   31                                struct dp_id_data *ar,
   32                                struct ldb_message **_msg)
   33 {
   34     const char *user_attrs[] = { SYSDB_NAME, SYSDB_OBJECTCATEGORY,
   35                                  SYSDB_PAC_BLOB, SYSDB_PAC_BLOB_EXPIRE,
   36                                  NULL };
   37     struct ldb_message *msg;
   38     struct ldb_result *res;
   39     int ret;
   40     TALLOC_CTX *tmp_ctx = NULL;
   41 
   42     if (dom == NULL || ar == NULL) {
   43         DEBUG(SSSDBG_OP_FAILURE, "Missing arguments.\n");
   44         return EINVAL;
   45     }
   46 
   47     tmp_ctx = talloc_new(NULL);
   48     if (tmp_ctx == NULL) {
   49         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
   50         return ENOMEM;
   51     }
   52 
   53     if (ar->extra_value && strcmp(ar->extra_value, EXTRA_NAME_IS_UPN) == 0) {
   54         ret = sysdb_search_user_by_upn(tmp_ctx, dom, false, ar->filter_value,
   55                                        user_attrs, &msg);
   56     } else {
   57         switch (ar->filter_type) {
   58         case BE_FILTER_SECID:
   59             ret = sysdb_search_user_by_sid_str(tmp_ctx, dom, ar->filter_value,
   60                                                user_attrs, &msg);
   61             break;
   62         case BE_FILTER_UUID:
   63             ret = sysdb_search_object_by_uuid(tmp_ctx, dom, ar->filter_value,
   64                                               user_attrs, &res);
   65 
   66             if (ret == EOK) {
   67                 if (res->count == 1) {
   68                     msg = res->msgs[0];
   69                 } else {
   70                     talloc_free(res);
   71                     DEBUG(SSSDBG_CRIT_FAILURE,
   72                           "Search by UUID returned multiple results.\n");
   73                     ret = EINVAL;
   74                     goto done;
   75                 }
   76             }
   77             break;
   78         case BE_FILTER_NAME:
   79             ret = sysdb_search_user_by_name(tmp_ctx, dom, ar->filter_value,
   80                                             user_attrs, &msg);
   81             break;
   82         default:
   83             DEBUG(SSSDBG_OP_FAILURE, "Unsupported filter type [%d].\n",
   84                                      ar->filter_type);
   85             ret = EINVAL;
   86             goto done;
   87         }
   88     }
   89 
   90     if (ret != EOK) {
   91         if (ret == ENOENT) {
   92             DEBUG(SSSDBG_TRACE_ALL, "No user found with filter [%s].\n",
   93                                     ar->filter_value);
   94         } else {
   95             DEBUG(SSSDBG_OP_FAILURE,
   96                   "Looking up user in cache with filter [%s] failed.\n",
   97                   ar->filter_value);
   98         }
   99         goto done;
  100     }
  101 
  102     *_msg = talloc_steal(mem_ctx, msg);
  103     ret = EOK;
  104 
  105 done:
  106     talloc_free(tmp_ctx);
  107     return ret;
  108 }
  109 
  110 errno_t check_if_pac_is_available(TALLOC_CTX *mem_ctx,
  111                                   struct sss_domain_info *dom,
  112                                   struct dp_id_data *ar,
  113                                   struct ldb_message **_msg)
  114 {
  115     struct ldb_message *msg;
  116     struct ldb_message_element *el;
  117     uint64_t pac_expires;
  118     time_t now;
  119     int ret;
  120 
  121     ret = find_user_entry(mem_ctx, dom, ar, &msg);
  122     if (ret != EOK) {
  123         DEBUG(SSSDBG_OP_FAILURE, "find_user_entry failed.\n");
  124         return ret;
  125     }
  126 
  127     el = ldb_msg_find_element(msg, SYSDB_PAC_BLOB);
  128     if (el == NULL) {
  129         DEBUG(SSSDBG_TRACE_ALL, "No PAC available.\n");
  130         talloc_free(msg);
  131         return ENOENT;
  132     }
  133 
  134     pac_expires = ldb_msg_find_attr_as_uint64(msg, SYSDB_PAC_BLOB_EXPIRE, 0);
  135     now = time(NULL);
  136     if (pac_expires < now) {
  137         DEBUG(SSSDBG_TRACE_FUNC, "PAC available but too old.\n");
  138         talloc_free(msg);
  139         return ENOENT;
  140     }
  141 
  142     if (_msg != NULL) {
  143         *_msg = msg;
  144     }
  145 
  146     return EOK;
  147 }
  148 
  149 static errno_t
  150 add_sids_from_rid_array_to_hash_table(struct dom_sid *dom_sid,
  151                                       struct samr_RidWithAttributeArray *groups,
  152                                       struct sss_idmap_ctx *idmap_ctx,
  153                                       hash_table_t *sid_table)
  154 {
  155     enum idmap_error_code err;
  156     char *dom_sid_str = NULL;
  157     size_t dom_sid_str_len;
  158     char *sid_str = NULL;
  159     char *rid_start;
  160     hash_key_t key;
  161     hash_value_t value;
  162     int ret;
  163     size_t c;
  164     TALLOC_CTX *tmp_ctx = NULL;
  165 
  166     tmp_ctx = talloc_new(NULL);
  167     if (tmp_ctx == NULL) {
  168         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
  169         return ENOMEM;
  170     }
  171 
  172     key.type = HASH_KEY_STRING;
  173     value.type = HASH_VALUE_ULONG;
  174 
  175     err = sss_idmap_smb_sid_to_sid(idmap_ctx, dom_sid, &dom_sid_str);
  176     if (err != IDMAP_SUCCESS) {
  177         DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n");
  178         ret = EFAULT;
  179         goto done;
  180     }
  181 
  182     dom_sid_str_len = strlen(dom_sid_str);
  183     sid_str = talloc_zero_size(tmp_ctx, dom_sid_str_len + 12);
  184     if (sid_str == NULL) {
  185         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
  186         ret = ENOMEM;
  187         goto done;
  188     }
  189     rid_start = sid_str + dom_sid_str_len;
  190 
  191     memcpy(sid_str, dom_sid_str, dom_sid_str_len);
  192 
  193     for (c = 0; c < groups->count; c++) {
  194         memset(rid_start, '\0', 12);
  195         ret = snprintf(rid_start, 12, "-%lu",
  196                        (unsigned long) groups->rids[c].rid);
  197         if (ret < 0 || ret > 12) {
  198             DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
  199             ret = EIO;
  200             goto done;
  201         }
  202 
  203         key.str = sid_str;
  204         value.ul = 0;
  205 
  206         ret = hash_enter(sid_table, &key, &value);
  207         if (ret != HASH_SUCCESS) {
  208             DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n",
  209                                       ret, hash_error_string(ret));
  210             ret = EIO;
  211             goto done;
  212         }
  213 
  214     }
  215 
  216     ret = EOK;
  217 
  218 done:
  219     sss_idmap_free_sid(idmap_ctx, dom_sid_str);
  220     talloc_free(tmp_ctx);
  221 
  222     return ret;
  223 }
  224 
  225 struct resource_groups {
  226     struct dom_sid2 *domain_sid;
  227     struct samr_RidWithAttributeArray groups;
  228 };
  229 
  230 errno_t ad_get_sids_from_pac(TALLOC_CTX *mem_ctx,
  231                              struct sss_idmap_ctx *idmap_ctx,
  232                              struct PAC_LOGON_INFO *logon_info,
  233                              char **_user_sid_str,
  234                              char **_primary_group_sid_str,
  235                              size_t *_num_sids,
  236                              char *** _sid_list)
  237 {
  238     int ret;
  239     size_t s;
  240     struct netr_SamInfo3 *info3;
  241     struct resource_groups resource_groups = { 0 };
  242     char *sid_str = NULL;
  243     char *msid_str = NULL;
  244     char *user_dom_sid_str = NULL;
  245     size_t user_dom_sid_str_len;
  246     enum idmap_error_code err;
  247     hash_table_t *sid_table = NULL;
  248     hash_key_t key;
  249     hash_value_t value;
  250     char *rid_start;
  251     char *user_sid_str = NULL;
  252     char *primary_group_sid_str = NULL;
  253     size_t c;
  254     size_t num_sids;
  255     char **sid_list = NULL;
  256     struct hash_iter_context_t *iter = NULL;
  257     hash_entry_t *entry;
  258     TALLOC_CTX *tmp_ctx;
  259 
  260     if (idmap_ctx == NULL || logon_info == NULL
  261             || _num_sids == NULL || _sid_list == NULL) {
  262         DEBUG(SSSDBG_OP_FAILURE, "Missing parameter.\n");
  263         return EINVAL;
  264     }
  265 
  266     tmp_ctx = talloc_new(NULL);
  267     if (tmp_ctx == NULL) {
  268         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
  269         return ENOMEM;
  270     }
  271 
  272     info3 = &logon_info->info3;
  273 #ifdef HAVE_STRUCT_PAC_LOGON_INFO_RESOURCE_GROUPS
  274     resource_groups.domain_sid = logon_info->resource_groups.domain_sid;
  275     resource_groups.groups.count = logon_info->resource_groups.groups.count;
  276     resource_groups.groups.rids = logon_info->resource_groups.groups.rids;
  277 #endif
  278 
  279     ret = sss_hash_create(tmp_ctx,
  280                           info3->sidcount + info3->base.groups.count + 2
  281                                           + resource_groups.groups.count,
  282                           &sid_table);
  283     if (ret != EOK) {
  284         DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n");
  285         goto done;
  286     }
  287 
  288     key.type = HASH_KEY_STRING;
  289     value.type = HASH_VALUE_ULONG;
  290 
  291     err = sss_idmap_smb_sid_to_sid(idmap_ctx, info3->base.domain_sid,
  292                                    &user_dom_sid_str);
  293     if (err != IDMAP_SUCCESS) {
  294         DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n");
  295         ret = EFAULT;
  296         goto done;
  297     }
  298 
  299     user_dom_sid_str_len = strlen(user_dom_sid_str);
  300     sid_str = talloc_zero_size(tmp_ctx, user_dom_sid_str_len + 12);
  301     if (sid_str == NULL) {
  302         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
  303         ret = ENOMEM;
  304         goto done;
  305     }
  306     rid_start = sid_str + user_dom_sid_str_len;
  307 
  308     memcpy(sid_str, user_dom_sid_str, user_dom_sid_str_len);
  309 
  310     memset(rid_start, '\0', 12);
  311     ret = snprintf(rid_start, 12, "-%lu",
  312                                   (unsigned long) info3->base.rid);
  313     if (ret < 0 || ret > 12) {
  314         DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
  315         ret = EIO;
  316         goto done;
  317     }
  318 
  319     user_sid_str = talloc_strdup(tmp_ctx, sid_str);
  320     if (user_sid_str == NULL) {
  321         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  322         ret = ENOMEM;
  323         goto done;
  324     }
  325 
  326     key.str = sid_str;
  327     value.ul = 0;
  328 
  329     memset(rid_start, '\0', 12);
  330     ret = snprintf(rid_start, 12, "-%lu",
  331                                   (unsigned long) info3->base.primary_gid);
  332     if (ret < 0 || ret > 12) {
  333         DEBUG(SSSDBG_OP_FAILURE, "snprintf failed.\n");
  334         ret = EIO;
  335         goto done;
  336     }
  337 
  338     primary_group_sid_str = talloc_strdup(tmp_ctx, sid_str);
  339     if (primary_group_sid_str == NULL) {
  340         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  341         ret = ENOMEM;
  342         goto done;
  343     }
  344 
  345     key.str = sid_str;
  346     value.ul = 0;
  347 
  348     ret = hash_enter(sid_table, &key, &value);
  349     if (ret != HASH_SUCCESS) {
  350         DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n",
  351                                   ret, hash_error_string(ret));
  352         ret = EIO;
  353         goto done;
  354     }
  355 
  356     ret = add_sids_from_rid_array_to_hash_table(info3->base.domain_sid,
  357                                                 &info3->base.groups,
  358                                                 idmap_ctx, sid_table);
  359     if (ret != EOK) {
  360         DEBUG(SSSDBG_OP_FAILURE,
  361               "add_sids_from_rid_array_to_hash_table failed.\n");
  362         goto done;
  363     }
  364 
  365     for(s = 0; s < info3->sidcount; s++) {
  366         err = sss_idmap_smb_sid_to_sid(idmap_ctx, info3->sids[s].sid,
  367                                        &msid_str);
  368         if (err != IDMAP_SUCCESS) {
  369             DEBUG(SSSDBG_OP_FAILURE, "sss_idmap_smb_sid_to_sid failed.\n");
  370             ret = EFAULT;
  371             goto done;
  372         }
  373 
  374         key.str = msid_str;
  375         value.ul = 0;
  376 
  377         ret = hash_enter(sid_table, &key, &value);
  378         sss_idmap_free_sid(idmap_ctx, msid_str);
  379         if (ret != HASH_SUCCESS) {
  380             DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed [%d][%s].\n",
  381                                       ret, hash_error_string(ret));
  382             ret = EIO;
  383             goto done;
  384         }
  385     }
  386 
  387     if (resource_groups.domain_sid != NULL) {
  388         ret = add_sids_from_rid_array_to_hash_table(resource_groups.domain_sid,
  389                                                     &resource_groups.groups,
  390                                                     idmap_ctx, sid_table);
  391         if (ret != EOK) {
  392             DEBUG(SSSDBG_OP_FAILURE,
  393                   "add_sids_from_rid_array_to_hash_table failed.\n");
  394             goto done;
  395         }
  396     }
  397 
  398     num_sids = hash_count(sid_table);
  399     sid_list = talloc_array(tmp_ctx, char *, num_sids);
  400     if (sid_list == NULL) {
  401         DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
  402         ret = ENOMEM;
  403         goto done;
  404     }
  405 
  406     iter = new_hash_iter_context(sid_table);
  407     if (iter == NULL) {
  408         DEBUG(SSSDBG_OP_FAILURE, "new_hash_iter_context failed.\n");
  409         ret = EINVAL;
  410         goto done;
  411     }
  412 
  413     c = 0;
  414     while ((entry = iter->next(iter)) != NULL) {
  415         sid_list[c] = talloc_strdup(sid_list, entry->key.str);
  416         if (sid_list[c] == NULL) {
  417             DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  418             ret = ENOMEM;
  419             goto done;
  420         }
  421         c++;
  422     }
  423 
  424     ret = EOK;
  425 
  426 done:
  427     sss_idmap_free_sid(idmap_ctx, user_dom_sid_str);
  428     hash_destroy(sid_table);
  429 
  430     if (ret == EOK) {
  431         *_sid_list = talloc_steal(mem_ctx, sid_list);
  432         *_user_sid_str = talloc_steal(mem_ctx, user_sid_str);
  433         *_num_sids = num_sids;
  434         *_primary_group_sid_str = talloc_steal(mem_ctx, primary_group_sid_str);
  435     }
  436 
  437     talloc_free(tmp_ctx);
  438 
  439     return ret;
  440 }
  441 
  442 errno_t ad_get_pac_data_from_user_entry(TALLOC_CTX *mem_ctx,
  443                                         struct ldb_message *msg,
  444                                         struct sss_idmap_ctx *idmap_ctx,
  445                                         char **_username,
  446                                         char **user_sid,
  447                                         char **primary_group_sid,
  448                                         size_t *num_sids,
  449                                         char ***group_sids)
  450 {
  451     int ret;
  452     struct ldb_message_element *el;
  453     struct PAC_LOGON_INFO *logon_info = NULL;
  454     const char *dummy;
  455     TALLOC_CTX *tmp_ctx = NULL;
  456     char *username;
  457 
  458     tmp_ctx = talloc_new(NULL);
  459     if (tmp_ctx == NULL) {
  460         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
  461         return ENOMEM;
  462     }
  463 
  464     el = ldb_msg_find_element(msg, SYSDB_PAC_BLOB);
  465     if (el == NULL) {
  466         DEBUG(SSSDBG_OP_FAILURE, "Missing PAC blob.\n");
  467         ret = EINVAL;
  468         goto done;
  469     }
  470 
  471     if (el->num_values != 1) {
  472         DEBUG(SSSDBG_OP_FAILURE, "Expected only one PAC blob.");
  473         ret = EINVAL;
  474         goto done;
  475     }
  476 
  477     ret = ad_get_data_from_pac(tmp_ctx, el->values[0].data,
  478                                el->values[0].length,
  479                                &logon_info);
  480     if (ret != EOK) {
  481         DEBUG(SSSDBG_OP_FAILURE, "get_data_from_pac failed.\n");
  482         goto done;
  483     }
  484 
  485     dummy = ldb_msg_find_attr_as_string(msg, SYSDB_NAME, NULL);
  486     if (dummy == NULL) {
  487         DEBUG(SSSDBG_OP_FAILURE, "Missing user name in cache entry.\n");
  488         ret = EINVAL;
  489         goto done;
  490     }
  491 
  492     username = talloc_strdup(tmp_ctx, dummy);
  493     if (username == NULL) {
  494         DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
  495         ret = ENOMEM;
  496         goto done;
  497     }
  498 
  499     ret = ad_get_sids_from_pac(mem_ctx, idmap_ctx, logon_info,
  500                                user_sid, primary_group_sid,
  501                                num_sids, group_sids);
  502     if (ret != EOK) {
  503         DEBUG(SSSDBG_OP_FAILURE, "get_sids_from_pac failed.\n");
  504         goto done;
  505     }
  506 
  507     *_username = talloc_steal(mem_ctx, username);
  508 
  509     ret = EOK;
  510 done:
  511     talloc_free(tmp_ctx);
  512 
  513     return ret;
  514 }
  515 
  516 struct ad_handle_pac_initgr_state {
  517     struct dp_id_data *ar;
  518     const char *err;
  519     int dp_error;
  520     int sdap_ret;
  521     struct sdap_options *opts;
  522 
  523     size_t num_missing_sids;
  524     char **missing_sids;
  525     size_t num_cached_groups;
  526     char **cached_groups;
  527     char *username;
  528     struct sss_domain_info *user_dom;
  529 };
  530 
  531 static void ad_handle_pac_initgr_lookup_sids_done(struct tevent_req *subreq);
  532 
  533 struct tevent_req *ad_handle_pac_initgr_send(TALLOC_CTX *mem_ctx,
  534                                              struct be_ctx *be_ctx,
  535                                              struct dp_id_data *ar,
  536                                              struct sdap_id_ctx *id_ctx,
  537                                              struct sdap_domain *sdom,
  538                                              struct sdap_id_conn_ctx *conn,
  539                                              bool noexist_delete,
  540                                              struct ldb_message *msg)
  541 {
  542     int ret;
  543     struct ad_handle_pac_initgr_state *state;
  544     struct tevent_req *req;
  545     struct tevent_req *subreq;
  546     char *user_sid;
  547     char *primary_group_sid;
  548     size_t num_sids;
  549     char **group_sids;
  550     bool use_id_mapping;
  551 
  552     req = tevent_req_create(mem_ctx, &state,
  553                             struct ad_handle_pac_initgr_state);
  554     if (req == NULL) {
  555         DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
  556         return NULL;
  557     }
  558     state->user_dom = sdom->dom;
  559     state->opts = id_ctx->opts;
  560 
  561     /* The following variables are currently unused because no sub-request
  562      * returns any of them. But they are needed to allow the same signature as
  563      * sdap_handle_acct_req_recv() from the alternative group-membership
  564      * lookup path. */
  565     state->err = NULL;
  566     state->dp_error = DP_ERR_OK;
  567     state->sdap_ret = EOK;
  568 
  569     ret = ad_get_pac_data_from_user_entry(state, msg,
  570                                           id_ctx->opts->idmap_ctx->map,
  571                                           &state->username,
  572                                           &user_sid, &primary_group_sid,
  573                                           &num_sids, &group_sids);
  574     if (ret != EOK) {
  575         DEBUG(SSSDBG_OP_FAILURE, "ad_get_pac_data_from_user_entry failed.\n");
  576         goto done;
  577     }
  578 
  579     use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(
  580                                                        id_ctx->opts->idmap_ctx,
  581                                                        sdom->dom->name,
  582                                                        sdom->dom->domain_id);
  583     if (use_id_mapping
  584             && sdom->dom->ignore_group_members == false) {
  585         /* In contrast to the tokenGroups based group-membership lookup the
  586          * PAC based approach can be used for sub-domains with id-mapping as
  587          * well because the PAC will only contain groups which are valid in
  588          * the target domain, i.e. it will not contain domain-local groups for
  589          * domains other than the user domain. This means the groups must not
  590          * be looked up immediately to determine if they are domain-local or
  591          * not.
  592          *
  593          * Additionally, as a temporary workaround until
  594          * https://fedorahosted.org/sssd/ticket/2522 is fixed, we also fetch
  595          * the group object if group members are ignored to avoid having to
  596          * transfer and retain members when the fake tokengroups object
  597          * without name is replaced by the full group object.
  598          */
  599 
  600         DEBUG(SSSDBG_TRACE_ALL, "Running PAC processing with id-mapping.\n");
  601 
  602         ret = sdap_ad_save_group_membership_with_idmapping(state->username,
  603                                                         state->opts,
  604                                                         sdom->dom,
  605                                                         id_ctx->opts->idmap_ctx,
  606                                                         num_sids, group_sids);
  607         if (ret != EOK) {
  608             DEBUG(SSSDBG_OP_FAILURE,
  609                   "sdap_ad_save_group_membership_with_idmapping failed.\n");
  610         }
  611 
  612         /* this path only includes cache operation, so we can finish the
  613          * request immediately */
  614         goto done;
  615     } else {
  616 
  617         DEBUG(SSSDBG_TRACE_ALL, "Running PAC processing with external IDs.\n");
  618 
  619         ret = sdap_ad_tokengroups_get_posix_members(state, sdom->dom,
  620                                                     num_sids, group_sids,
  621                                                     &state->num_missing_sids,
  622                                                     &state->missing_sids,
  623                                                     &state->num_cached_groups,
  624                                                     &state->cached_groups);
  625         if (ret != EOK) {
  626             DEBUG(SSSDBG_OP_FAILURE,
  627                   "sdap_ad_tokengroups_get_posix_members failed.\n");
  628             goto done;
  629         }
  630 
  631         /* download missing SIDs */
  632         subreq = sdap_ad_resolve_sids_send(state, be_ctx->ev, id_ctx,
  633                                            conn,
  634                                            id_ctx->opts, sdom->dom,
  635                                            state->missing_sids);
  636         if (subreq == NULL) {
  637             DEBUG(SSSDBG_OP_FAILURE, "sdap_ad_resolve_sids_send failed.\n");
  638             ret = ENOMEM;
  639             goto done;
  640         }
  641 
  642         tevent_req_set_callback(subreq, ad_handle_pac_initgr_lookup_sids_done,
  643                                 req);
  644 
  645     }
  646 
  647     return req;
  648 
  649 done:
  650     if (ret == EOK) {
  651         tevent_req_done(req);
  652     } else {
  653         tevent_req_error(req, ret);
  654     }
  655     tevent_req_post(req, be_ctx->ev);
  656 
  657     return req;
  658 }
  659 
  660 static void ad_handle_pac_initgr_lookup_sids_done(struct tevent_req *subreq)
  661 {
  662     struct ad_handle_pac_initgr_state *state;
  663     struct tevent_req *req = NULL;
  664     errno_t ret;
  665     char **cached_groups;
  666     size_t num_cached_groups;
  667 
  668     req = tevent_req_callback_data(subreq, struct tevent_req);
  669     state = tevent_req_data(req, struct ad_handle_pac_initgr_state);
  670 
  671     ret = sdap_ad_resolve_sids_recv(subreq);
  672     talloc_zfree(subreq);
  673     if (ret != EOK) {
  674         DEBUG(SSSDBG_CRIT_FAILURE, "Unable to resolve missing SIDs "
  675                                    "[%d]: %s\n", ret, strerror(ret));
  676         goto done;
  677     }
  678 
  679     ret = sdap_ad_tokengroups_get_posix_members(state, state->user_dom,
  680                                                 state->num_missing_sids,
  681                                                 state->missing_sids,
  682                                                 NULL, NULL,
  683                                                 &num_cached_groups,
  684                                                 &cached_groups);
  685     if (ret != EOK){
  686         DEBUG(SSSDBG_MINOR_FAILURE,
  687               "sdap_ad_tokengroups_get_posix_members failed [%d]: %s\n",
  688               ret, strerror(ret));
  689         goto done;
  690     }
  691 
  692     state->cached_groups = concatenate_string_array(state,
  693                                                     state->cached_groups,
  694                                                     state->num_cached_groups,
  695                                                     cached_groups,
  696                                                     num_cached_groups);
  697     if (state->cached_groups == NULL) {
  698         ret = ENOMEM;
  699         goto done;
  700     }
  701 
  702     /* update membership of existing groups */
  703     ret = sdap_ad_tokengroups_update_members(state->username,
  704                                              state->user_dom->sysdb,
  705                                              state->user_dom,
  706                                              state->cached_groups);
  707     if (ret != EOK) {
  708         DEBUG(SSSDBG_MINOR_FAILURE, "Membership update failed [%d]: %s\n",
  709                                      ret, strerror(ret));
  710         goto done;
  711     }
  712 
  713 done:
  714     if (ret != EOK) {
  715         tevent_req_error(req, ret);
  716         return;
  717     }
  718 
  719     tevent_req_done(req);
  720 }
  721 
  722 errno_t ad_handle_pac_initgr_recv(struct tevent_req *req,
  723                                   int *_dp_error, const char **_err,
  724                                   int *sdap_ret)
  725 {
  726     struct ad_handle_pac_initgr_state *state;
  727 
  728     state = tevent_req_data(req, struct ad_handle_pac_initgr_state);
  729 
  730     if (_dp_error) {
  731         *_dp_error = state->dp_error;
  732     }
  733 
  734     if (_err) {
  735         *_err = state->err;
  736     }
  737 
  738     if (sdap_ret) {
  739         *sdap_ret = state->sdap_ret;
  740     }
  741     TEVENT_REQ_RETURN_ON_ERROR(req);
  742 
  743     return EOK;
  744 }