LCOV - code coverage report
Current view: top level - providers/ipa - ipa_subdomains_ext_groups.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 570 0.0 %
Date: 2016-06-29 Functions: 0 19 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     IPA Identity Backend Module for sub-domains - evaluate external group
       5             :     memberships
       6             : 
       7             :     Authors:
       8             :         Sumit Bose <sbose@redhat.com>
       9             : 
      10             :     Copyright (C) 2013 Red Hat
      11             : 
      12             :     This program is free software; you can redistribute it and/or modify
      13             :     it under the terms of the GNU General Public License as published by
      14             :     the Free Software Foundation; either version 3 of the License, or
      15             :     (at your option) any later version.
      16             : 
      17             :     This program is distributed in the hope that it will be useful,
      18             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      19             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      20             :     GNU General Public License for more details.
      21             : 
      22             :     You should have received a copy of the GNU General Public License
      23             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      24             : */
      25             : 
      26             : #include "util/util.h"
      27             : #include "db/sysdb.h"
      28             : #include "providers/ldap/ldap_common.h"
      29             : #include "providers/ldap/sdap_async.h"
      30             : #include "providers/ipa/ipa_id.h"
      31             : #include "providers/ad/ad_id.h"
      32             : #include "providers/ipa/ipa_subdomains.h"
      33             : 
      34             : #define IPA_EXT_GROUPS_FILTER "objectClass=ipaexternalgroup"
      35             : 
      36             : struct ipa_ext_groups {
      37             :     time_t next_update;
      38             :     hash_table_t *ext_groups;
      39             : };
      40             : 
      41           0 : static errno_t process_ext_groups(TALLOC_CTX *mem_ctx, size_t reply_count,
      42             :                                   struct sysdb_attrs **reply,
      43             :                                   hash_table_t **_ext_group_hash)
      44             : {
      45             :     int ret;
      46           0 :     hash_table_t *ext_group_hash = NULL;
      47             :     hash_key_t key;
      48             :     hash_value_t value;
      49           0 :     hash_table_t *m_hash = NULL;
      50             :     hash_key_t m_key;
      51             :     hash_value_t m_value;
      52             :     size_t g;
      53             :     size_t s;
      54             :     size_t m;
      55           0 :     TALLOC_CTX *tmp_ctx = NULL;
      56             :     const char **ext_sids;
      57             :     const char **mof;
      58             : 
      59           0 :     tmp_ctx = talloc_new(NULL);
      60           0 :     if (tmp_ctx == NULL) {
      61           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
      62           0 :         ret = ENOMEM;
      63           0 :         goto done;
      64             :     }
      65             : 
      66           0 :     ret = sss_hash_create(mem_ctx, reply_count, &ext_group_hash);
      67           0 :     if (ret != HASH_SUCCESS) {
      68           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n");
      69           0 :         goto done;
      70             :     }
      71             : 
      72           0 :     key.type = HASH_KEY_STRING;
      73           0 :     m_key.type = HASH_KEY_STRING;
      74           0 :     m_value.type = HASH_VALUE_PTR;
      75           0 :     m_value.ptr = NULL;
      76             : 
      77           0 :     for (g = 0; g < reply_count; g++) {
      78           0 :         ret = sysdb_attrs_get_string_array(reply[g], "ipaExternalMember",
      79             :                                            tmp_ctx, &ext_sids);
      80           0 :         if (ret == ENOENT) {
      81             :             /* no external members, try next external group. */
      82           0 :             continue;
      83           0 :         } else if (ret != EOK) {
      84           0 :             DEBUG(SSSDBG_OP_FAILURE,
      85             :                   "sysdb_attrs_get_string_array failed.\n");
      86           0 :             goto done;
      87             :         }
      88             : 
      89           0 :         ret = sysdb_attrs_get_string_array(reply[g], "memberOf",
      90             :                                            tmp_ctx, &mof);
      91           0 :         if (ret == ENOENT) {
      92             :             /* no IPA groups, try next external group. */
      93           0 :             continue;
      94           0 :         } else if (ret != EOK) {
      95           0 :             DEBUG(SSSDBG_OP_FAILURE,
      96             :                   "sysdb_attrs_get_string_array failed.\n");
      97           0 :             goto done;
      98             :         }
      99             : 
     100           0 :         for (s = 0; ext_sids[s] != NULL; s++) {
     101             :             /* hash_lookup does not modify key.str. */
     102           0 :             key.str = discard_const(ext_sids[s]);
     103           0 :             ret = hash_lookup(ext_group_hash, &key, &value);
     104           0 :             if (ret == HASH_SUCCESS) {
     105           0 :                 if (value.type != HASH_VALUE_PTR) {
     106           0 :                     DEBUG(SSSDBG_OP_FAILURE, "Unexpected value type.\n");
     107           0 :                     ret = EINVAL;
     108           0 :                     goto done;
     109             :                 }
     110             : 
     111           0 :                 for (m = 0; mof[m] != NULL; m++) {
     112             :                     /* hash_enter does not modify m_key.str. */
     113           0 :                     m_key.str = discard_const(mof[m]);
     114           0 :                     DEBUG(SSSDBG_TRACE_ALL, "Adding group [%s] to SID [%s].\n",
     115             :                                              m_key.str, key.str);
     116           0 :                     ret = hash_enter(value.ptr, &m_key, &m_value);
     117           0 :                     if (ret != HASH_SUCCESS) {
     118           0 :                         DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed.\n");
     119           0 :                         goto done;
     120             :                     }
     121             :                 }
     122           0 :             } else if (ret == HASH_ERROR_KEY_NOT_FOUND) {
     123           0 :                 ret = sss_hash_create(ext_group_hash, 5, &m_hash);
     124           0 :                 if (ret != HASH_SUCCESS) {
     125           0 :                     DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n");
     126           0 :                     goto done;
     127             :                 }
     128             : 
     129           0 :                 value.type = HASH_VALUE_PTR;
     130           0 :                 value.ptr = m_hash;
     131             : 
     132           0 :                 DEBUG(SSSDBG_TRACE_ALL,
     133             :                       "Adding SID [%s] to external group hash.\n", key.str);
     134           0 :                 ret = hash_enter(ext_group_hash, &key, &value);
     135           0 :                 if (ret != HASH_SUCCESS) {
     136           0 :                     DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed.\n");
     137           0 :                     goto done;
     138             :                 }
     139             : 
     140           0 :                 for (m = 0; mof[m] != NULL; m++) {
     141             :                     /* hash_enter does not modify m_key.str. */
     142           0 :                     m_key.str = discard_const(mof[m]);
     143           0 :                     DEBUG(SSSDBG_TRACE_ALL, "Adding group [%s] to SID [%s].\n",
     144             :                                              m_key.str, key.str);
     145           0 :                     ret = hash_enter(m_hash, &m_key, &m_value);
     146           0 :                     if (ret != HASH_SUCCESS) {
     147           0 :                         DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed.\n");
     148           0 :                         goto done;
     149             :                     }
     150             :                 }
     151             :             } else {
     152           0 :                 DEBUG(SSSDBG_OP_FAILURE, "hash_lookup failed.\n");
     153           0 :                 goto done;
     154             :             }
     155             :         }
     156             :     }
     157             : 
     158           0 :     ret = EOK;
     159             : done:
     160           0 :     if (ret != EOK) {
     161           0 :         talloc_free(ext_group_hash);
     162             :     } else {
     163           0 :         *_ext_group_hash = ext_group_hash;
     164             :     }
     165             : 
     166           0 :     talloc_free(tmp_ctx);
     167             : 
     168           0 :     return ret;
     169             : }
     170             : 
     171           0 : static errno_t find_ipa_ext_memberships(TALLOC_CTX *mem_ctx,
     172             :                                         const char *user_name,
     173             :                                         struct sss_domain_info *user_dom,
     174             :                                         hash_table_t *ext_group_hash,
     175             :                                         struct ldb_dn **_user_dn,
     176             :                                         char ***_groups)
     177             : {
     178             :     int ret;
     179           0 :     TALLOC_CTX *tmp_ctx = NULL;
     180             :     struct ldb_result *result;
     181           0 :     char **groups = NULL;
     182             :     size_t c;
     183             :     const char *sid;
     184             :     hash_key_t key;
     185             :     hash_value_t value;
     186             :     hash_entry_t *entry;
     187             :     struct hash_iter_context_t *iter;
     188             :     hash_table_t *group_hash;
     189             :     size_t g_count;
     190           0 :     struct ldb_dn *user_dn = NULL;
     191             : 
     192           0 :     tmp_ctx = talloc_new(NULL);
     193           0 :     if (tmp_ctx == NULL) {
     194           0 :         return ENOMEM;
     195             :     }
     196             : 
     197           0 :     ret = sysdb_initgroups(tmp_ctx, user_dom, user_name, &result);
     198           0 :     if (ret != EOK) {
     199           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_initgroups failed.\n");
     200           0 :         goto done;
     201             :     }
     202             : 
     203           0 :     if (result->count == 0) {
     204           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "User [%s] not found in cache.\n",
     205             :                                      user_name);
     206           0 :         ret = EOK;
     207           0 :         goto done;
     208             :     }
     209             : 
     210           0 :     ret = sss_hash_create(tmp_ctx, 10, &group_hash);
     211           0 :     if (ret != HASH_SUCCESS) {
     212           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n");
     213           0 :         goto done;
     214             :     }
     215             : 
     216           0 :     key.type = HASH_KEY_STRING;
     217             : 
     218             :     /* The IPA external domains can have references to group and user SIDs.
     219             :      * This means that we not only want to look up the group SIDs but the SID
     220             :      * of the user (first element of result) as well. */
     221           0 :     for (c = 0; c < result->count; c++) {
     222           0 :         sid = ldb_msg_find_attr_as_string(result->msgs[c], SYSDB_SID_STR,
     223             :                                           NULL);
     224           0 :         if (sid == NULL) {
     225           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Group [%s] does not have a SID.\n",
     226             :                   ldb_dn_get_linearized(result->msgs[c]->dn));
     227           0 :             continue;
     228             :         }
     229             : 
     230           0 :         key.str = discard_const(sid);
     231           0 :         ret = hash_lookup(ext_group_hash, &key, &value);
     232           0 :         if (ret == HASH_ERROR_KEY_NOT_FOUND) {
     233           0 :             DEBUG(SSSDBG_TRACE_ALL, "SID [%s] not found in ext group hash.\n",
     234             :                                      sid);
     235           0 :         } else if (ret == HASH_SUCCESS) {
     236           0 :             iter = new_hash_iter_context(value.ptr);
     237           0 :             if (iter == NULL) {
     238           0 :                 DEBUG(SSSDBG_OP_FAILURE, "new_hash_iter_context failed.\n");
     239           0 :                 ret = EINVAL;
     240           0 :                 goto done;
     241             :             }
     242             : 
     243           0 :             while ((entry = iter->next(iter)) != NULL) {
     244           0 :                 ret = hash_enter(group_hash, &entry->key, &entry->value);
     245           0 :                 if (ret != HASH_SUCCESS) {
     246           0 :                     DEBUG(SSSDBG_OP_FAILURE, "Failed to add group [%s].\n",
     247             :                                               entry->key.str);
     248             :                 }
     249             :             }
     250             : 
     251           0 :             talloc_free(iter);
     252             :         } else {
     253           0 :             DEBUG(SSSDBG_OP_FAILURE, "hash_lookup failed for SID [%s].\n",
     254             :                                       sid);
     255             :         }
     256             :     }
     257             : 
     258           0 :     g_count = hash_count(group_hash);
     259           0 :     if (g_count == 0) {
     260           0 :         DEBUG(SSSDBG_TRACE_FUNC, "No external groupmemberships found.\n");
     261           0 :         ret = EOK;
     262           0 :         goto done;
     263             :     }
     264             : 
     265           0 :     groups = talloc_zero_array(mem_ctx, char *, g_count + 1);
     266           0 :     if (groups == NULL) {
     267           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
     268           0 :         ret = ENOMEM;
     269           0 :         goto done;
     270             :     }
     271             : 
     272           0 :     iter = new_hash_iter_context(group_hash);
     273           0 :     if (iter == NULL) {
     274           0 :         DEBUG(SSSDBG_OP_FAILURE, "new_hash_iter_context failed.\n");
     275           0 :         ret = EINVAL;
     276           0 :         goto done;
     277             :     }
     278             : 
     279           0 :     c = 0;
     280           0 :     while ((entry = iter->next(iter)) != NULL) {
     281           0 :         groups[c] = talloc_strdup(groups, entry->key.str);
     282           0 :         if (groups[c] == NULL) {
     283           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
     284           0 :             ret = ENOMEM;
     285           0 :             goto done;
     286             :         }
     287           0 :         c++;
     288             :     }
     289             : 
     290           0 :     user_dn = ldb_dn_copy(mem_ctx, result->msgs[0]->dn);
     291           0 :     if (user_dn == NULL) {
     292           0 :         DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n");
     293           0 :         ret = ENOMEM;
     294           0 :         goto done;
     295             :     }
     296             : 
     297           0 :     ret = EOK;
     298             : done:
     299           0 :     *_user_dn = user_dn;
     300           0 :     *_groups = groups;
     301             : 
     302           0 :     talloc_free(tmp_ctx);
     303             : 
     304           0 :     return ret;
     305             : }
     306             : 
     307           0 : static errno_t add_ad_user_to_cached_groups(struct ldb_dn *user_dn,
     308             :                                             struct sss_domain_info *user_dom,
     309             :                                             struct sss_domain_info *group_dom,
     310             :                                             char **groups,
     311             :                                             bool *missing_groups)
     312             : {
     313             :     size_t c;
     314             :     struct sysdb_attrs *user_attrs;
     315             :     size_t msgs_count;
     316             :     struct ldb_message **msgs;
     317             :     char *subfilter;
     318             :     TALLOC_CTX *tmp_ctx;
     319             :     int ret;
     320             : 
     321           0 :     *missing_groups = false;
     322             : 
     323           0 :     tmp_ctx = talloc_new(NULL);
     324           0 :     if (tmp_ctx == NULL) {
     325           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
     326           0 :         return ENOMEM;
     327             :     }
     328             : 
     329           0 :     for (c = 0; groups[c] != NULL; c++) {
     330           0 :         if (groups[c][0] == '\0') {
     331           0 :             continue;
     332             :         }
     333             : 
     334           0 :         subfilter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_ORIG_DN, groups[c]);
     335           0 :         if (subfilter == NULL) {
     336           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
     337           0 :             ret = ENOMEM;
     338           0 :             goto done;
     339             :         }
     340             : 
     341           0 :         ret = sysdb_search_groups(tmp_ctx, group_dom, subfilter, NULL,
     342             :                                   &msgs_count, &msgs);
     343           0 :         if (ret != EOK) {
     344           0 :             if (ret == ENOENT) {
     345           0 :                 DEBUG(SSSDBG_TRACE_ALL, "Group [%s] not in the cache.\n",
     346             :                                          groups[c]);
     347           0 :                 *missing_groups = true;
     348           0 :                 continue;
     349             :             } else {
     350           0 :                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n");
     351           0 :                 goto done;
     352             :             }
     353             :         }
     354             : 
     355             : /* TODO? Do we have to remove members as well? I think not because the AD
     356             :  * query before removes all memberships. */
     357             : 
     358           0 :         ret = sysdb_mod_group_member(group_dom, user_dn, msgs[0]->dn,
     359             :                                      LDB_FLAG_MOD_ADD);
     360           0 :         if (ret != EOK && ret != EEXIST) {
     361           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_mod_group_member failed.\n");
     362           0 :             goto done;
     363             :         }
     364             : 
     365           0 :         user_attrs = sysdb_new_attrs(tmp_ctx);
     366           0 :         if (user_attrs == NULL) {
     367           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
     368           0 :             ret = ENOMEM;
     369           0 :             goto done;
     370             :         }
     371             : 
     372           0 :         ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF,
     373           0 :                                      groups[c]);
     374           0 :         if (ret != EOK) {
     375           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
     376           0 :             goto done;
     377             :         }
     378             : 
     379           0 :         ret = sysdb_set_entry_attr(user_dom->sysdb, user_dn, user_attrs,
     380             :                                    LDB_FLAG_MOD_ADD);
     381           0 :         if (ret != EOK && ret != EEXIST) {
     382           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed.\n");
     383           0 :             goto done;
     384             :         }
     385             : 
     386             :         /* mark group as already processed */
     387           0 :         groups[c][0] = '\0';
     388             :     }
     389             : 
     390           0 :     ret = EOK;
     391             : done:
     392           0 :     talloc_free(tmp_ctx);
     393             : 
     394           0 :     return ret;
     395             : }
     396             : 
     397             : static struct tevent_req *ipa_add_ad_memberships_send(TALLOC_CTX *mem_ctx,
     398             :                                              struct tevent_context *ev,
     399             :                                              struct sdap_id_ctx *sdap_id_ctx,
     400             :                                              struct ldb_dn *user_dn,
     401             :                                              struct sss_domain_info *user_dom,
     402             :                                              char **groups,
     403             :                                              struct sss_domain_info *group_dom);
     404             : static void ipa_add_ad_memberships_done(struct tevent_req *subreq);
     405             : 
     406             : struct get_ad_membership_state {
     407             :     struct tevent_context *ev;
     408             :     struct ipa_server_mode_ctx *server_mode;
     409             :     struct sdap_id_op *sdap_op;
     410             :     struct sdap_id_ctx *sdap_id_ctx;
     411             :     struct fo_server *srv;
     412             :     char *user_name;
     413             :     struct sss_domain_info *user_dom;
     414             : 
     415             :     int dp_error;
     416             :     const char *domain;
     417             :     size_t reply_count;
     418             :     struct sysdb_attrs **reply;
     419             : };
     420             : 
     421             : static void ipa_get_ad_memberships_connect_done(struct tevent_req *subreq);
     422             : static void ipa_get_ext_groups_done(struct tevent_req *subreq);
     423             : static errno_t ipa_add_ext_groups_step(struct tevent_req *req);
     424             : static errno_t ipa_add_ad_memberships_recv(struct tevent_req *req,
     425             :                                            int *dp_error_out);
     426             : 
     427           0 : struct tevent_req *ipa_get_ad_memberships_send(TALLOC_CTX *mem_ctx,
     428             :                                         struct tevent_context *ev,
     429             :                                         struct be_acct_req *ar,
     430             :                                         struct ipa_server_mode_ctx *server_mode,
     431             :                                         struct sss_domain_info *user_dom,
     432             :                                         struct sdap_id_ctx *sdap_id_ctx,
     433             :                                         const char *domain)
     434             : {
     435             :     int ret;
     436             :     struct tevent_req *req;
     437             :     struct tevent_req *subreq;
     438             :     struct get_ad_membership_state *state;
     439             : 
     440           0 :     req = tevent_req_create(mem_ctx, &state, struct get_ad_membership_state);
     441           0 :     if (req == NULL) {
     442           0 :         DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
     443           0 :         return NULL;
     444             :     }
     445             : 
     446           0 :     state->ev = ev;
     447           0 :     state->user_dom = user_dom;
     448           0 :     state->sdap_id_ctx = sdap_id_ctx;
     449           0 :     state->srv = NULL;
     450           0 :     state->domain = domain;
     451           0 :     state->dp_error = -1;
     452             : 
     453           0 :     if (((ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS
     454           0 :             && (ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_USER)
     455           0 :             || ar->filter_type != BE_FILTER_NAME) {
     456           0 :         DEBUG(SSSDBG_OP_FAILURE, "Unsupported request type.\n");
     457           0 :         ret = EINVAL;
     458           0 :         goto done;
     459             :     }
     460             : 
     461           0 :     state->user_name = talloc_strdup(state, ar->filter_value);
     462           0 :     if (state->user_name == NULL) {
     463           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_Strdup failed.\n");
     464           0 :         ret = ENOMEM;
     465           0 :         goto done;
     466             :     }
     467             : 
     468           0 :     state->sdap_op = sdap_id_op_create(state,
     469           0 :                                        state->sdap_id_ctx->conn->conn_cache);
     470           0 :     if (state->sdap_op == NULL) {
     471           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
     472           0 :         ret = ENOMEM;
     473           0 :         goto done;
     474             :     }
     475             : 
     476           0 :     state->server_mode = server_mode;
     477           0 :     if (server_mode->ext_groups == NULL) {
     478           0 :         server_mode->ext_groups = talloc_zero(server_mode,
     479             :                                               struct ipa_ext_groups);
     480           0 :         if (server_mode->ext_groups == NULL) {
     481           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
     482           0 :             ret = ENOMEM;
     483           0 :             goto done;
     484             :         }
     485             :     }
     486             : 
     487           0 :     if (server_mode->ext_groups->next_update > time(NULL)) {
     488           0 :         DEBUG(SSSDBG_TRACE_FUNC, "External group information still valid.\n");
     489           0 :         ret = ipa_add_ext_groups_step(req);
     490           0 :         if (ret == EOK) {
     491           0 :             goto done;
     492           0 :         } else if (ret == EAGAIN) {
     493           0 :             return req;
     494             :         } else {
     495           0 :             DEBUG(SSSDBG_OP_FAILURE, "ipa_add_ext_groups_step failed.\n");
     496           0 :             goto done;
     497             :         }
     498             : 
     499             :     }
     500             : 
     501           0 :     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
     502           0 :     if (subreq == NULL) {
     503           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
     504             :                                   ret, strerror(ret));
     505           0 :         goto done;
     506             :     }
     507             : 
     508           0 :     tevent_req_set_callback(subreq, ipa_get_ad_memberships_connect_done, req);
     509             : 
     510           0 :     return req;
     511             : 
     512             : done:
     513           0 :     if (ret != EOK) {
     514           0 :         state->dp_error = DP_ERR_FATAL;
     515           0 :         tevent_req_error(req, ret);
     516             :     } else {
     517           0 :         state->dp_error = DP_ERR_OK;
     518           0 :         tevent_req_done(req);
     519             :     }
     520           0 :     tevent_req_post(req, state->ev);
     521             : 
     522           0 :     return req;
     523             : }
     524             : 
     525           0 : static void ipa_get_ad_memberships_connect_done(struct tevent_req *subreq)
     526             : {
     527           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     528             :                                                       struct tevent_req);
     529           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     530             :                                                 struct get_ad_membership_state);
     531             :     int ret;
     532             :     char *basedn;
     533             : 
     534           0 :     ret = sdap_id_op_connect_recv(subreq, &state->dp_error);
     535           0 :     talloc_zfree(subreq);
     536           0 :     if (ret != EOK) {
     537           0 :         if (state->dp_error == DP_ERR_OFFLINE) {
     538           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     539             :                   "No IPA server is available, going offline\n");
     540             :         } else {
     541           0 :             DEBUG(SSSDBG_OP_FAILURE,
     542             :                   "Failed to connect to IPA server: [%d](%s)\n",
     543             :                    ret, strerror(ret));
     544             :         }
     545             : 
     546           0 :         goto fail;
     547             :     }
     548             : 
     549             : 
     550           0 :     ret = domain_to_basedn(state, state->domain, &basedn);
     551           0 :     if (ret != EOK) {
     552           0 :         DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n");
     553           0 :         goto fail;
     554             :     }
     555             : 
     556           0 :     subreq = sdap_get_generic_send(state, state->ev, state->sdap_id_ctx->opts,
     557             :                                  sdap_id_op_handle(state->sdap_op), basedn,
     558             :                                  LDAP_SCOPE_SUBTREE,
     559             :                                  IPA_EXT_GROUPS_FILTER, NULL, NULL, 0,
     560           0 :                                  dp_opt_get_int(state->sdap_id_ctx->opts->basic,
     561             :                                                 SDAP_ENUM_SEARCH_TIMEOUT),
     562             :                                  false);
     563           0 :     if (subreq == NULL) {
     564           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
     565           0 :         ret = ENOMEM;
     566           0 :         goto fail;
     567             :     }
     568             : 
     569           0 :     tevent_req_set_callback(subreq, ipa_get_ext_groups_done, req);
     570           0 :     return;
     571             : 
     572             : fail:
     573           0 :     tevent_req_error(req, ret);
     574           0 :     return;
     575             : }
     576             : 
     577           0 : static void ipa_get_ext_groups_done(struct tevent_req *subreq)
     578             : {
     579           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     580             :                                                       struct tevent_req);
     581           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     582             :                                                 struct get_ad_membership_state);
     583             :     int ret;
     584             :     hash_table_t *ext_group_hash;
     585             : 
     586           0 :     ret = sdap_get_generic_recv(subreq, state,
     587             :                                 &state->reply_count, &state->reply);
     588           0 :     talloc_zfree(subreq);
     589           0 :     if (ret != EOK) {
     590           0 :         DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ext_groups request failed.\n");
     591           0 :         tevent_req_error(req, ret);
     592           0 :         return;
     593             :     }
     594             : 
     595           0 :     DEBUG(SSSDBG_TRACE_FUNC, "[%zu] external groups found.\n",
     596             :                               state->reply_count);
     597             : 
     598           0 :     ret = process_ext_groups(state->server_mode->ext_groups,
     599             :                              state->reply_count, state->reply, &ext_group_hash);
     600           0 :     if (ret != EOK) {
     601           0 :         DEBUG(SSSDBG_OP_FAILURE, "process_ext_groups failed.\n");
     602           0 :         goto fail;
     603             :     }
     604             : 
     605           0 :     state->server_mode->ext_groups->ext_groups = ext_group_hash;
     606             :     /* Do we have to make the update timeout configurable? */
     607           0 :     state->server_mode->ext_groups->next_update = time(NULL) + 10;
     608             : 
     609           0 :     ret = ipa_add_ext_groups_step(req);
     610           0 :     if (ret == EOK) {
     611           0 :         tevent_req_done(req);
     612           0 :         return;
     613           0 :     } else if (ret == EAGAIN) {
     614           0 :         return;
     615             :     } else {
     616           0 :         DEBUG(SSSDBG_OP_FAILURE, "ipa_add_ext_groups_step failed.\n");
     617           0 :         goto fail;
     618             :     }
     619             : 
     620             : fail:
     621           0 :     tevent_req_error(req, ret);
     622           0 :     return;
     623             : }
     624             : 
     625           0 : static errno_t ipa_add_ext_groups_step(struct tevent_req *req)
     626             : {
     627           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     628             :                                                 struct get_ad_membership_state);
     629             :     struct ldb_dn *user_dn;
     630             :     int ret;
     631           0 :     char **groups = NULL;
     632             :     struct tevent_req *subreq;
     633             : 
     634           0 :     ret = find_ipa_ext_memberships(state, state->user_name, state->user_dom,
     635           0 :                                    state->server_mode->ext_groups->ext_groups,
     636             :                                    &user_dn, &groups);
     637           0 :     if (ret != EOK) {
     638           0 :         DEBUG(SSSDBG_OP_FAILURE, "find_ipa_ext_memberships failed.\n");
     639           0 :         goto fail;
     640             :     }
     641             : 
     642           0 :     if (groups == NULL) {
     643           0 :         DEBUG(SSSDBG_TRACE_ALL, "No external groups memberships found.\n");
     644           0 :         state->dp_error = DP_ERR_OK;
     645           0 :         return EOK;
     646             :     }
     647             : 
     648           0 :     subreq = ipa_add_ad_memberships_send(state, state->ev, state->sdap_id_ctx,
     649             :                                          user_dn, state->user_dom, groups,
     650           0 :                                          state->sdap_id_ctx->be->domain);
     651           0 :     if (subreq == NULL) {
     652           0 :         DEBUG(SSSDBG_OP_FAILURE, "ipa_add_ad_memberships_send failed.\n");
     653           0 :         ret = ENOMEM;
     654           0 :         goto fail;
     655             :     }
     656             : 
     657           0 :     tevent_req_set_callback(subreq, ipa_add_ad_memberships_done, req);
     658           0 :     return EAGAIN;
     659             : 
     660             : fail:
     661           0 :     tevent_req_error(req, ret);
     662           0 :     return ret;
     663             : }
     664             : 
     665           0 : static void ipa_add_ad_memberships_done(struct tevent_req *subreq)
     666             : {
     667           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     668             :                                                       struct tevent_req);
     669           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     670             :                                                 struct get_ad_membership_state);
     671             :     int ret;
     672             : 
     673           0 :     ret = ipa_add_ad_memberships_recv(subreq, &state->dp_error);
     674           0 :     talloc_zfree(subreq);
     675           0 :     if (ret != EOK) {
     676           0 :         DEBUG(SSSDBG_OP_FAILURE, "ipa_add_ad_memberships request failed.\n");
     677           0 :         tevent_req_error(req, ret);
     678           0 :         return;
     679             :     }
     680             : 
     681           0 :     state->dp_error = DP_ERR_OK;
     682           0 :     tevent_req_done(req);
     683           0 :     return;
     684             : }
     685             : 
     686           0 : errno_t ipa_get_ad_memberships_recv(struct tevent_req *req, int *dp_error_out)
     687             : {
     688           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     689             :                                                 struct get_ad_membership_state);
     690             : 
     691           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     692             : 
     693           0 :     if (dp_error_out) {
     694           0 :         *dp_error_out = state->dp_error;
     695             :     }
     696             : 
     697           0 :     return EOK;
     698             : }
     699             : 
     700             : struct add_ad_membership_state {
     701             :     struct tevent_context *ev;
     702             :     struct sdap_id_ctx *sdap_id_ctx;
     703             :     struct sdap_id_op *sdap_op;
     704             :     struct ldb_dn *user_dn;
     705             :     struct sss_domain_info *user_dom;
     706             :     struct sss_domain_info *group_dom;
     707             :     char **groups;
     708             :     int dp_error;
     709             :     size_t iter;
     710             :     struct sdap_domain *group_sdom;
     711             : };
     712             : 
     713             : static void ipa_add_ad_memberships_connect_done(struct tevent_req *subreq);
     714             : static void ipa_add_ad_memberships_get_next(struct tevent_req *req);
     715             : static void ipa_add_ad_memberships_get_group_done(struct tevent_req *subreq);
     716           0 : static struct tevent_req *ipa_add_ad_memberships_send(TALLOC_CTX *mem_ctx,
     717             :                                              struct tevent_context *ev,
     718             :                                              struct sdap_id_ctx *sdap_id_ctx,
     719             :                                              struct ldb_dn *user_dn,
     720             :                                              struct sss_domain_info *user_dom,
     721             :                                              char **groups,
     722             :                                              struct sss_domain_info *group_dom)
     723             : {
     724             :     int ret;
     725             :     struct tevent_req *req;
     726             :     struct tevent_req *subreq;
     727             :     struct add_ad_membership_state *state;
     728           0 :     bool missing_groups = false;
     729             : 
     730           0 :     req = tevent_req_create(mem_ctx, &state, struct add_ad_membership_state);
     731           0 :     if (req == NULL) {
     732           0 :         DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
     733           0 :         return NULL;
     734             :     }
     735             : 
     736           0 :     state->ev = ev;
     737           0 :     state->user_dom = user_dom;
     738           0 :     state->sdap_id_ctx = sdap_id_ctx;
     739           0 :     state->user_dn = user_dn;
     740           0 :     state->group_dom = group_dom;
     741           0 :     state->groups = groups;
     742           0 :     state->dp_error = -1;
     743           0 :     state->iter = 0;
     744           0 :     state->group_sdom = sdap_domain_get(sdap_id_ctx->opts, group_dom);
     745           0 :     if (state->group_sdom == NULL) {
     746           0 :         ret = EIO;
     747           0 :         goto done;
     748             :     }
     749             : 
     750           0 :     ret = add_ad_user_to_cached_groups(user_dn, user_dom, group_dom, groups,
     751             :                                        &missing_groups);
     752           0 :     if (ret != EOK) {
     753           0 :         DEBUG(SSSDBG_OP_FAILURE, "add_ad_user_to_cached_groups failed.\n");
     754           0 :         goto done;
     755             :     }
     756             : 
     757           0 :     if (!missing_groups) {
     758           0 :         DEBUG(SSSDBG_TRACE_ALL, "All groups found in cache.\n");
     759           0 :         ret = EOK;
     760           0 :         goto done;
     761             :     }
     762             : 
     763           0 :     state->sdap_op = sdap_id_op_create(state,
     764           0 :                                        state->sdap_id_ctx->conn->conn_cache);
     765           0 :     if (state->sdap_op == NULL) {
     766           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
     767           0 :         ret = ENOMEM;
     768           0 :         goto done;
     769             :     }
     770             : 
     771           0 :     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
     772           0 :     if (subreq == NULL) {
     773           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
     774             :                                   ret, strerror(ret));
     775           0 :         goto done;
     776             :     }
     777             : 
     778           0 :     tevent_req_set_callback(subreq, ipa_add_ad_memberships_connect_done, req);
     779             : 
     780           0 :     return req;
     781             : 
     782             : done:
     783           0 :     if (ret != EOK) {
     784           0 :         state->dp_error = DP_ERR_FATAL;
     785           0 :         tevent_req_error(req, ret);
     786             :     } else {
     787           0 :         state->dp_error = DP_ERR_OK;
     788           0 :         tevent_req_done(req);
     789             :     }
     790           0 :     tevent_req_post(req, state->ev);
     791             : 
     792           0 :     return req;
     793             : }
     794             : 
     795           0 : static void ipa_add_ad_memberships_connect_done(struct tevent_req *subreq)
     796             : {
     797           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     798             :                                                       struct tevent_req);
     799           0 :     struct add_ad_membership_state *state = tevent_req_data(req,
     800             :                                                 struct add_ad_membership_state);
     801             :     int ret;
     802             : 
     803           0 :     ret = sdap_id_op_connect_recv(subreq, &state->dp_error);
     804           0 :     talloc_zfree(subreq);
     805           0 :     if (ret != EOK) {
     806           0 :         if (state->dp_error == DP_ERR_OFFLINE) {
     807           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     808             :                   "No IPA server is available, going offline\n");
     809             :         } else {
     810           0 :             DEBUG(SSSDBG_OP_FAILURE,
     811             :                   "Failed to connect to IPA server: [%d](%s)\n",
     812             :                    ret, strerror(ret));
     813             :         }
     814             : 
     815           0 :         tevent_req_error(req, ret);
     816           0 :         return;
     817             :     }
     818             : 
     819           0 :     state->iter = 0;
     820           0 :     ipa_add_ad_memberships_get_next(req);
     821             : }
     822             : 
     823           0 : static void ipa_add_ad_memberships_get_next(struct tevent_req *req)
     824             : {
     825           0 :     struct add_ad_membership_state *state = tevent_req_data(req,
     826             :                                                 struct add_ad_membership_state);
     827             :     struct tevent_req *subreq;
     828             :     struct ldb_dn *group_dn;
     829             :     int ret;
     830             :     const struct ldb_val *val;
     831             :     bool missing_groups;
     832             : 
     833           0 :     while (state->groups[state->iter] != NULL
     834           0 :             && state->groups[state->iter][0] == '\0') {
     835           0 :         state->iter++;
     836             :     }
     837             : 
     838           0 :     if (state->groups[state->iter] == NULL) {
     839           0 :         ret = add_ad_user_to_cached_groups(state->user_dn, state->user_dom,
     840             :                                            state->group_dom, state->groups,
     841             :                                            &missing_groups);
     842           0 :         if (ret != EOK) {
     843           0 :             DEBUG(SSSDBG_OP_FAILURE, "add_ad_user_to_cached_groups failed.\n");
     844           0 :             goto fail;
     845             :         }
     846             : 
     847           0 :         if (missing_groups) {
     848           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "There are unresolved external group "
     849             :                                        "memberships even after all groups "
     850             :                                        "have been looked up on the LDAP "
     851             :                                        "server.\n");
     852             :         }
     853           0 :         tevent_req_done(req);
     854           0 :         return;
     855             :     }
     856             : 
     857           0 :     group_dn = ldb_dn_new(state, sysdb_ctx_get_ldb(state->group_dom->sysdb),
     858           0 :                           state->groups[state->iter]);
     859           0 :     if (group_dn == NULL) {
     860           0 :         DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
     861           0 :         ret = ENOMEM;
     862           0 :         goto fail;
     863             :     }
     864             : 
     865           0 :     val = ldb_dn_get_rdn_val(group_dn);
     866           0 :     if (val == NULL || val->data == NULL) {
     867           0 :         DEBUG(SSSDBG_OP_FAILURE,
     868             :               "Invalid group DN [%s].\n", state->groups[state->iter]);
     869           0 :         ret = EINVAL;
     870           0 :         goto fail;
     871             :     }
     872             : 
     873             : /* TODO: here is would be useful for have a filter type like BE_FILTER_DN to
     874             :  * directly fetch the group with the corresponding DN. */
     875           0 :     subreq = groups_get_send(state, state->ev,
     876             :                                  state->sdap_id_ctx, state->group_sdom,
     877           0 :                                  state->sdap_id_ctx->conn,
     878           0 :                                  (const char *) val->data,
     879             :                                  BE_FILTER_NAME, BE_ATTR_CORE,
     880             :                                  false, false);
     881           0 :     if (subreq == NULL) {
     882           0 :         DEBUG(SSSDBG_OP_FAILURE, "groups_get_send failed.\n");
     883           0 :         ret = ENOMEM;
     884           0 :         goto fail;
     885             :     }
     886             : 
     887           0 :     tevent_req_set_callback(subreq, ipa_add_ad_memberships_get_group_done, req);
     888           0 :     return;
     889             : 
     890             : fail:
     891           0 :     tevent_req_error(req, ret);
     892             : }
     893             : 
     894           0 : static void ipa_add_ad_memberships_get_group_done(struct tevent_req *subreq)
     895             : {
     896           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     897             :                                                       struct tevent_req);
     898           0 :     struct add_ad_membership_state *state = tevent_req_data(req,
     899             :                                                 struct add_ad_membership_state);
     900             :     int ret;
     901             : 
     902           0 :     ret = groups_get_recv(subreq, &state->dp_error, NULL);
     903           0 :     talloc_zfree(subreq);
     904           0 :     if (ret != EOK) {
     905           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to read group [%s] from LDAP [%d](%s)\n",
     906             :               state->groups[state->iter], ret, strerror(ret));
     907             : 
     908           0 :         tevent_req_error(req, ret);
     909           0 :         return;
     910             :     }
     911             : 
     912           0 :     state->iter++;
     913           0 :     ipa_add_ad_memberships_get_next(req);
     914             : }
     915             : 
     916           0 : static errno_t ipa_add_ad_memberships_recv(struct tevent_req *req,
     917             :                                            int *dp_error_out)
     918             : {
     919           0 :     struct add_ad_membership_state *state = tevent_req_data(req,
     920             :                                                 struct add_ad_membership_state);
     921             : 
     922           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     923             : 
     924           0 :     if (dp_error_out) {
     925           0 :         *dp_error_out = state->dp_error;
     926             :     }
     927             : 
     928           0 :     return EOK;
     929             : }
     930             : 
     931             : static errno_t
     932           0 : search_user_or_group_by_sid_str(TALLOC_CTX *mem_ctx,
     933             :                                 struct sss_domain_info *domain,
     934             :                                 const char *sid_str,
     935             :                                 enum sysdb_member_type *_member_type,
     936             :                                 struct ldb_message **_msg)
     937             : {
     938             :     errno_t ret;
     939           0 :     struct ldb_message *msg = NULL;
     940           0 :     const char *attrs[] = { SYSDB_NAME,
     941             :                             SYSDB_SID_STR,
     942             :                             SYSDB_ORIG_DN,
     943             :                             SYSDB_OBJECTCLASS,
     944             :                             SYSDB_CACHE_EXPIRE,
     945             :                             NULL };
     946           0 :     TALLOC_CTX *tmp_ctx = NULL;
     947           0 :     char *sanitized_sid = NULL;
     948             : 
     949           0 :     tmp_ctx = talloc_new(NULL);
     950           0 :     if (tmp_ctx == NULL) {
     951           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
     952           0 :         return ENOMEM;
     953             :     }
     954             : 
     955             :     /* In theory SID shouldn't contain any special LDAP characters, but let's
     956             :      * be paranoid
     957             :      */
     958           0 :     ret = sss_filter_sanitize(tmp_ctx, sid_str, &sanitized_sid);
     959           0 :     if (ret != EOK) {
     960           0 :         goto done;
     961             :     }
     962             : 
     963           0 :     ret = sysdb_search_user_by_sid_str(tmp_ctx, domain,
     964             :                                        sid_str, attrs, &msg);
     965           0 :     if (ret == EOK) {
     966           0 :         *_member_type = SYSDB_MEMBER_USER;
     967           0 :     } else if (ret == ENOENT) {
     968           0 :         ret = sysdb_search_group_by_sid_str(tmp_ctx, domain,
     969             :                                             sid_str, attrs, &msg);
     970           0 :         if (ret == EOK) {
     971           0 :             *_member_type = SYSDB_MEMBER_GROUP;
     972             :         }
     973             :     }
     974             : 
     975           0 :     switch (ret) {
     976             :     case EOK:
     977           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Found %s in sysdb\n", sid_str);
     978           0 :         *_msg = talloc_steal(mem_ctx, msg);
     979           0 :         break;
     980             :     case ENOENT:
     981           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     982             :               "Could not find %s in sysdb", sid_str);
     983           0 :         break;
     984             :     default:
     985           0 :         DEBUG(SSSDBG_OP_FAILURE,
     986             :               "Error looking for %s in sysdb [%d]: %s\n",
     987             :               sid_str, ret, sss_strerror(ret));
     988           0 :         break;
     989             :     }
     990             : 
     991             : done:
     992           0 :     talloc_free(tmp_ctx);
     993           0 :     return ret;
     994             : }
     995             : 
     996             : static errno_t
     997           0 : ipa_ext_group_member_check(TALLOC_CTX *mem_ctx,
     998             :                            struct sss_domain_info *member_dom,
     999             :                            const char *ext_member,
    1000             :                            enum sysdb_member_type *_member_type,
    1001             :                            struct sysdb_attrs **_member)
    1002             : {
    1003           0 :     TALLOC_CTX *tmp_ctx = NULL;
    1004             :     errno_t ret;
    1005             :     uint64_t expire;
    1006           0 :     time_t now = time(NULL);
    1007             :     struct ldb_message *msg;
    1008             :     struct sysdb_attrs **members;
    1009             : 
    1010           0 :     tmp_ctx = talloc_new(NULL);
    1011           0 :     if (tmp_ctx == NULL) {
    1012           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_new() failed\n");
    1013           0 :         return ENOMEM;
    1014             :     }
    1015             : 
    1016           0 :     ret = search_user_or_group_by_sid_str(tmp_ctx, member_dom, ext_member,
    1017             :                                           _member_type, &msg);
    1018           0 :     if (ret != EOK) {
    1019           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1020             :               "Error looking up sid %s: [%d]: %s\n",
    1021             :                ext_member, ret, sss_strerror(ret));
    1022           0 :         goto done;
    1023             :     }
    1024             : 
    1025           0 :     ret = sysdb_msg2attrs(tmp_ctx, 1, &msg, &members);
    1026           0 :     if (ret != EOK) {
    1027           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1028             :               "Could not convert result to sysdb_attrs [%d]: %s\n",
    1029             :                ret, sss_strerror(ret));
    1030           0 :         goto done;
    1031             :     }
    1032             : 
    1033             :     /* Return the member both expired and valid */
    1034           0 :     *_member = talloc_steal(mem_ctx, members[0]);
    1035             : 
    1036           0 :     expire = ldb_msg_find_attr_as_uint64(msg, SYSDB_CACHE_EXPIRE, 0);
    1037           0 :     if (expire != 0 && expire <= now) {
    1038           0 :         DEBUG(SSSDBG_TRACE_FUNC, "%s is expired", ext_member);
    1039           0 :         ret = EAGAIN;
    1040           0 :         goto done;
    1041             :     }
    1042             : 
    1043             : done:
    1044           0 :     talloc_free(tmp_ctx);
    1045           0 :     return ret;
    1046             : }
    1047             : 
    1048             : /* For the IPA external member resolution, we expect a SID as the input.
    1049             :  * The _recv() function output is the member and a type (user/group)
    1050             :  * since nothing else can be a group member.
    1051             :  */
    1052             : struct ipa_ext_member_state {
    1053             :     const char *ext_member;
    1054             :     struct sss_domain_info *dom;
    1055             : 
    1056             :     enum sysdb_member_type member_type;
    1057             :     struct sysdb_attrs *member;
    1058             : };
    1059             : 
    1060             : static void ipa_ext_group_member_done(struct tevent_req *subreq);
    1061             : 
    1062           0 : struct tevent_req *ipa_ext_group_member_send(TALLOC_CTX *mem_ctx,
    1063             :                                              struct tevent_context *ev,
    1064             :                                              const char *ext_member,
    1065             :                                              void *pvt)
    1066             : {
    1067             :     struct ipa_id_ctx *ipa_ctx;
    1068             :     struct ipa_ext_member_state *state;
    1069             :     struct tevent_req *req;
    1070             :     struct tevent_req *subreq;
    1071             :     struct be_acct_req *ar;
    1072             :     errno_t ret;
    1073             : 
    1074           0 :     req = tevent_req_create(mem_ctx, &state, struct ipa_ext_member_state);
    1075           0 :     if (req == NULL) {
    1076           0 :         return NULL;
    1077             :     }
    1078           0 :     state->ext_member = ext_member;
    1079             : 
    1080           0 :     ipa_ctx = talloc_get_type(pvt, struct ipa_id_ctx);
    1081           0 :     if (ipa_ctx == NULL) {
    1082           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Wrong private context!\n");
    1083           0 :         ret = EINVAL;
    1084           0 :         goto immediate;
    1085             :     }
    1086             : 
    1087           0 :     state->dom = find_domain_by_sid(ipa_ctx->sdap_id_ctx->be->domain,
    1088             :                                     ext_member);
    1089           0 :     if (state->dom == NULL) {
    1090           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1091             :               "Cannot find domain of SID [%s]\n", ext_member);
    1092           0 :         ret = ENOENT;
    1093           0 :         goto immediate;
    1094             :     }
    1095             : 
    1096           0 :     ret = ipa_ext_group_member_check(state, state->dom, ext_member,
    1097           0 :                                      &state->member_type, &state->member);
    1098           0 :     if (ret == EOK) {
    1099           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
    1100             :               "external member %s already cached\n", ext_member);
    1101           0 :         goto immediate;
    1102             :     }
    1103             : 
    1104           0 :     ret = get_be_acct_req_for_sid(state, ext_member, state->dom->name, &ar);
    1105           0 :     if (ret != EOK) {
    1106           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1107             :               "Cannot create the account request for [%s]\n", ext_member);
    1108           0 :         goto immediate;
    1109             :     }
    1110             : 
    1111           0 :     subreq = dp_req_send(state, ipa_ctx->sdap_id_ctx->be->provider, NULL,
    1112           0 :                          ar->domain, "External Member",
    1113             :                          DPT_ID, DPM_ACCOUNT_HANDLER, 0, ar, NULL);
    1114           0 :     if (subreq == NULL) {
    1115           0 :         ret = ENOMEM;
    1116           0 :         goto immediate;
    1117             :     }
    1118           0 :     tevent_req_set_callback(subreq, ipa_ext_group_member_done, req);
    1119             : 
    1120           0 :     return req;
    1121             : 
    1122             : immediate:
    1123           0 :     if (ret != EOK) {
    1124           0 :         tevent_req_error(req, ret);
    1125             :     } else {
    1126           0 :         tevent_req_done(req);
    1127             :     }
    1128           0 :     tevent_req_post(req, ev);
    1129           0 :     return req;
    1130             : }
    1131             : 
    1132           0 : static void ipa_ext_group_member_done(struct tevent_req *subreq)
    1133             : {
    1134           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    1135             :                                                       struct tevent_req);
    1136           0 :     struct ipa_ext_member_state *state = tevent_req_data(req,
    1137             :                                                 struct ipa_ext_member_state);
    1138             :     errno_t ret;
    1139             :     struct ldb_message *msg;
    1140             :     struct sysdb_attrs **members;
    1141             :     struct dp_reply_std *reply;
    1142             : 
    1143             : 
    1144           0 :     ret = dp_req_recv_ptr(state, subreq, struct dp_reply_std, &reply);
    1145           0 :     talloc_free(subreq);
    1146           0 :     if (ret != EOK) {
    1147           0 :         DEBUG(SSSDBG_OP_FAILURE, "dp_req_recv failed\n");
    1148           0 :         tevent_req_error(req, ret);
    1149           0 :         return;
    1150           0 :     } else if (reply->dp_error != DP_ERR_OK) {
    1151           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    1152             :               "Cannot refresh data from DP: %u,%u: %s\n",
    1153             :               reply->dp_error, reply->error, reply->message);
    1154           0 :         tevent_req_error(req, EIO);
    1155           0 :         return;
    1156             :     }
    1157             : 
    1158           0 :     ret = search_user_or_group_by_sid_str(state,
    1159             :                                           state->dom,
    1160             :                                           state->ext_member,
    1161             :                                           &state->member_type,
    1162             :                                           &msg);
    1163           0 :     if (ret != EOK) {
    1164           0 :         DEBUG(ret == ENOENT ? SSSDBG_TRACE_FUNC : SSSDBG_OP_FAILURE,
    1165             :               "Could not find %s in sysdb [%d]: %s\n",
    1166             :               state->ext_member, ret, sss_strerror(ret));
    1167           0 :         tevent_req_error(req, ret);
    1168           0 :         return;
    1169             :     }
    1170             : 
    1171           0 :     ret = sysdb_msg2attrs(state, 1, &msg, &members);
    1172           0 :     if (ret != EOK) {
    1173           0 :         DEBUG(SSSDBG_OP_FAILURE,
    1174             :               "Could not convert result to sysdb_attrs [%d]: %s\n",
    1175             :                ret, sss_strerror(ret));
    1176           0 :         tevent_req_error(req, ret);
    1177           0 :         return;
    1178             :     }
    1179             : 
    1180           0 :     state->member = members[0];
    1181           0 :     tevent_req_done(req);
    1182             : }
    1183             : 
    1184           0 : errno_t ipa_ext_group_member_recv(TALLOC_CTX *mem_ctx,
    1185             :                                   struct tevent_req *req,
    1186             :                                   enum sysdb_member_type *_member_type,
    1187             :                                   struct sss_domain_info **_dom,
    1188             :                                   struct sysdb_attrs **_member)
    1189             : {
    1190           0 :     struct ipa_ext_member_state *state = tevent_req_data(req,
    1191             :                                                 struct ipa_ext_member_state);
    1192           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1193             : 
    1194           0 :     if (_member_type != NULL) {
    1195           0 :         *_member_type = state->member_type;
    1196             :     }
    1197             : 
    1198           0 :     if (_dom) {
    1199           0 :         *_dom = state->dom;
    1200             :     }
    1201             : 
    1202           0 :     if (_member != NULL) {
    1203           0 :         *_member = talloc_steal(mem_ctx, state->member);
    1204             :     }
    1205             : 
    1206           0 :     return EOK;
    1207             : }

Generated by: LCOV version 1.10