LCOV - code coverage report
Current view: top level - providers/ipa - ipa_subdomains_ext_groups.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 443 0.0 %
Date: 2015-10-19 Functions: 0 14 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             :         }
      84           0 :         if (ret != EOK) {
      85           0 :             DEBUG(SSSDBG_OP_FAILURE,
      86             :                   "sysdb_attrs_get_string_array failed.\n");
      87           0 :             goto done;
      88             :         }
      89             : 
      90           0 :         ret = sysdb_attrs_get_string_array(reply[g], "memberOf",
      91             :                                            tmp_ctx, &mof);
      92           0 :         if (ret == ENOENT) {
      93             :             /* no IPA groups, try next external group. */
      94           0 :             continue;
      95             :         }
      96           0 :         if (ret != EOK) {
      97           0 :             DEBUG(SSSDBG_OP_FAILURE,
      98             :                   "sysdb_attrs_get_string_array failed.\n");
      99           0 :             goto done;
     100             :         }
     101             : 
     102           0 :         for (s = 0; ext_sids[s] != NULL; s++) {
     103             :             /* hash_lookup does not modify key.str. */
     104           0 :             key.str = discard_const(ext_sids[s]);
     105           0 :             ret = hash_lookup(ext_group_hash, &key, &value);
     106           0 :             if (ret == HASH_SUCCESS) {
     107           0 :                 if (value.type != HASH_VALUE_PTR) {
     108           0 :                     DEBUG(SSSDBG_OP_FAILURE, "Unexpected value type.\n");
     109           0 :                     ret = EINVAL;
     110           0 :                     goto done;
     111             :                 }
     112             : 
     113           0 :                 for (m = 0; mof[m] != NULL; m++) {
     114             :                     /* hash_enter does not modify m_key.str. */
     115           0 :                     m_key.str = discard_const(mof[m]);
     116           0 :                     DEBUG(SSSDBG_TRACE_ALL, "Adding group [%s] to SID [%s].\n",
     117             :                                              m_key.str, key.str);
     118           0 :                     ret = hash_enter(value.ptr, &m_key, &m_value);
     119           0 :                     if (ret != HASH_SUCCESS) {
     120           0 :                         DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed.\n");
     121           0 :                         goto done;
     122             :                     }
     123             :                 }
     124           0 :             } else if (ret == HASH_ERROR_KEY_NOT_FOUND) {
     125           0 :                 ret = sss_hash_create(ext_group_hash, 5, &m_hash);
     126           0 :                 if (ret != HASH_SUCCESS) {
     127           0 :                     DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n");
     128           0 :                     goto done;
     129             :                 }
     130             : 
     131           0 :                 value.type = HASH_VALUE_PTR;
     132           0 :                 value.ptr = m_hash;
     133             : 
     134           0 :                 DEBUG(SSSDBG_TRACE_ALL,
     135             :                       "Adding SID [%s] to external group hash.\n", key.str);
     136           0 :                 ret = hash_enter(ext_group_hash, &key, &value);
     137           0 :                 if (ret != HASH_SUCCESS) {
     138           0 :                     DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed.\n");
     139           0 :                     goto done;
     140             :                 }
     141             : 
     142           0 :                 for (m = 0; mof[m] != NULL; m++) {
     143             :                     /* hash_enter does not modify m_key.str. */
     144           0 :                     m_key.str = discard_const(mof[m]);
     145           0 :                     DEBUG(SSSDBG_TRACE_ALL, "Adding group [%s] to SID [%s].\n",
     146             :                                              m_key.str, key.str);
     147           0 :                     ret = hash_enter(m_hash, &m_key, &m_value);
     148           0 :                     if (ret != HASH_SUCCESS) {
     149           0 :                         DEBUG(SSSDBG_OP_FAILURE, "hash_enter failed.\n");
     150           0 :                         goto done;
     151             :                     }
     152             :                 }
     153             :             } else {
     154           0 :                 DEBUG(SSSDBG_OP_FAILURE, "hash_lookup failed.\n");
     155           0 :                 goto done;
     156             :             }
     157             :         }
     158             :     }
     159             : 
     160           0 :     ret = EOK;
     161             : done:
     162           0 :     if (ret != EOK) {
     163           0 :         talloc_free(ext_group_hash);
     164             :     } else {
     165           0 :         *_ext_group_hash = ext_group_hash;
     166             :     }
     167             : 
     168           0 :     talloc_free(tmp_ctx);
     169             : 
     170           0 :     return ret;
     171             : }
     172             : 
     173           0 : static errno_t find_ipa_ext_memberships(TALLOC_CTX *mem_ctx,
     174             :                                         const char *user_name,
     175             :                                         struct sss_domain_info *user_dom,
     176             :                                         hash_table_t *ext_group_hash,
     177             :                                         struct ldb_dn **_user_dn,
     178             :                                         char ***_groups)
     179             : {
     180             :     int ret;
     181           0 :     TALLOC_CTX *tmp_ctx = NULL;
     182             :     struct ldb_result *result;
     183           0 :     char **groups = NULL;
     184             :     size_t c;
     185             :     const char *sid;
     186             :     hash_key_t key;
     187             :     hash_value_t value;
     188             :     hash_entry_t *entry;
     189             :     struct hash_iter_context_t *iter;
     190             :     hash_table_t *group_hash;
     191             :     size_t g_count;
     192           0 :     struct ldb_dn *user_dn = NULL;
     193             : 
     194           0 :     tmp_ctx = talloc_new(NULL);
     195           0 :     if (tmp_ctx == NULL) {
     196           0 :         return ENOMEM;
     197             :     }
     198             : 
     199           0 :     ret = sysdb_initgroups(tmp_ctx, user_dom, user_name, &result);
     200           0 :     if (ret != EOK) {
     201           0 :         DEBUG(SSSDBG_OP_FAILURE, "sysdb_initgroups failed.\n");
     202           0 :         goto done;
     203             :     }
     204             : 
     205           0 :     if (result->count == 0) {
     206           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "User [%s] not found in cache.\n",
     207             :                                      user_name);
     208           0 :         ret = EOK;
     209           0 :         goto done;
     210             :     }
     211             : 
     212           0 :     ret = sss_hash_create(tmp_ctx, 10, &group_hash);
     213           0 :     if (ret != HASH_SUCCESS) {
     214           0 :         DEBUG(SSSDBG_OP_FAILURE, "sss_hash_create failed.\n");
     215           0 :         goto done;
     216             :     }
     217             : 
     218           0 :     key.type = HASH_KEY_STRING;
     219             : 
     220             :     /* The IPA external domains can have references to group and user SIDs.
     221             :      * This means that we not only want to look up the group SIDs but the SID
     222             :      * of the user (first element of result) as well. */
     223           0 :     for (c = 0; c < result->count; c++) {
     224           0 :         sid = ldb_msg_find_attr_as_string(result->msgs[c], SYSDB_SID_STR,
     225             :                                           NULL);
     226           0 :         if (sid == NULL) {
     227           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Group [%s] does not have a SID.\n",
     228             :                   ldb_dn_get_linearized(result->msgs[c]->dn));
     229           0 :             continue;
     230             :         }
     231             : 
     232           0 :         key.str = discard_const(sid);
     233           0 :         ret = hash_lookup(ext_group_hash, &key, &value);
     234           0 :         if (ret == HASH_ERROR_KEY_NOT_FOUND) {
     235           0 :             DEBUG(SSSDBG_TRACE_ALL, "SID [%s] not found in ext group hash.\n",
     236             :                                      sid);
     237           0 :         } else if (ret == HASH_SUCCESS) {
     238           0 :             iter = new_hash_iter_context(value.ptr);
     239           0 :             if (iter == NULL) {
     240           0 :                 DEBUG(SSSDBG_OP_FAILURE, "new_hash_iter_context failed.\n");
     241           0 :                 ret = EINVAL;
     242           0 :                 goto done;
     243             :             }
     244             : 
     245           0 :             while ((entry = iter->next(iter)) != NULL) {
     246           0 :                 ret = hash_enter(group_hash, &entry->key, &entry->value);
     247           0 :                 if (ret != HASH_SUCCESS) {
     248           0 :                     DEBUG(SSSDBG_OP_FAILURE, "Failed to add group [%s].\n",
     249             :                                               entry->key.str);
     250             :                 }
     251             :             }
     252             : 
     253           0 :             talloc_free(iter);
     254             :         } else {
     255           0 :             DEBUG(SSSDBG_OP_FAILURE, "hash_lookup failed for SID [%s].\n",
     256             :                                       sid);
     257             :         }
     258             :     }
     259             : 
     260           0 :     g_count = hash_count(group_hash);
     261           0 :     if (g_count == 0) {
     262           0 :         DEBUG(SSSDBG_TRACE_FUNC, "No external groupmemberships found.\n");
     263           0 :         ret = EOK;
     264           0 :         goto done;
     265             :     }
     266             : 
     267           0 :     groups = talloc_zero_array(mem_ctx, char *, g_count + 1);
     268           0 :     if (groups == NULL) {
     269           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
     270           0 :         ret = ENOMEM;
     271           0 :         goto done;
     272             :     }
     273             : 
     274           0 :     iter = new_hash_iter_context(group_hash);
     275           0 :     if (iter == NULL) {
     276           0 :         DEBUG(SSSDBG_OP_FAILURE, "new_hash_iter_context failed.\n");
     277           0 :         ret = EINVAL;
     278           0 :         goto done;
     279             :     }
     280             : 
     281           0 :     c = 0;
     282           0 :     while ((entry = iter->next(iter)) != NULL) {
     283           0 :         groups[c] = talloc_strdup(groups, entry->key.str);
     284           0 :         if (groups[c] == NULL) {
     285           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_strdup failed.\n");
     286           0 :             ret = ENOMEM;
     287           0 :             goto done;
     288             :         }
     289           0 :         c++;
     290             :     }
     291             : 
     292           0 :     user_dn = ldb_dn_copy(mem_ctx, result->msgs[0]->dn);
     293           0 :     if (user_dn == NULL) {
     294           0 :         DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_copy failed.\n");
     295           0 :         ret = ENOMEM;
     296           0 :         goto done;
     297             :     }
     298             : 
     299           0 :     ret = EOK;
     300             : done:
     301           0 :     *_user_dn = user_dn;
     302           0 :     *_groups = groups;
     303             : 
     304           0 :     talloc_free(tmp_ctx);
     305             : 
     306           0 :     return ret;
     307             : }
     308             : 
     309           0 : static errno_t add_ad_user_to_cached_groups(struct ldb_dn *user_dn,
     310             :                                             struct sss_domain_info *user_dom,
     311             :                                             struct sss_domain_info *group_dom,
     312             :                                             char **groups,
     313             :                                             bool *missing_groups)
     314             : {
     315             :     size_t c;
     316             :     struct sysdb_attrs *user_attrs;
     317             :     size_t msgs_count;
     318             :     struct ldb_message **msgs;
     319             :     char *subfilter;
     320             :     TALLOC_CTX *tmp_ctx;
     321             :     int ret;
     322             : 
     323           0 :     *missing_groups = false;
     324             : 
     325           0 :     tmp_ctx = talloc_new(NULL);
     326           0 :     if (tmp_ctx == NULL) {
     327           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
     328           0 :         return ENOMEM;
     329             :     }
     330             : 
     331           0 :     for (c = 0; groups[c] != NULL; c++) {
     332           0 :         if (groups[c][0] == '\0') {
     333           0 :             continue;
     334             :         }
     335             : 
     336           0 :         subfilter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_ORIG_DN, groups[c]);
     337           0 :         if (subfilter == NULL) {
     338           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
     339           0 :             ret = ENOMEM;
     340           0 :             goto done;
     341             :         }
     342             : 
     343           0 :         ret = sysdb_search_groups(tmp_ctx, group_dom, subfilter, NULL,
     344             :                                   &msgs_count, &msgs);
     345           0 :         if (ret != EOK) {
     346           0 :             if (ret == ENOENT) {
     347           0 :                 DEBUG(SSSDBG_TRACE_ALL, "Group [%s] not in the cache.\n",
     348             :                                          groups[c]);
     349           0 :                 *missing_groups = true;
     350           0 :                 continue;
     351             :             } else {
     352           0 :                 DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n");
     353           0 :                 goto done;
     354             :             }
     355             :         }
     356             : 
     357             : /* TODO? Do we have to remove members as well? I think not because the AD
     358             :  * query before removes all memberships. */
     359             : 
     360           0 :         ret = sysdb_mod_group_member(group_dom, user_dn, msgs[0]->dn,
     361             :                                      LDB_FLAG_MOD_ADD);
     362           0 :         if (ret != EOK && ret != EEXIST) {
     363           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_mod_group_member failed.\n");
     364           0 :             goto done;
     365             :         }
     366             : 
     367           0 :         user_attrs = sysdb_new_attrs(tmp_ctx);
     368           0 :         if (user_attrs == NULL) {
     369           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n");
     370           0 :             ret = ENOMEM;
     371           0 :             goto done;
     372             :         }
     373             : 
     374           0 :         ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF,
     375           0 :                                      groups[c]);
     376           0 :         if (ret != EOK) {
     377           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n");
     378           0 :             goto done;
     379             :         }
     380             : 
     381           0 :         ret = sysdb_set_entry_attr(user_dom->sysdb, user_dn, user_attrs,
     382             :                                    LDB_FLAG_MOD_ADD);
     383           0 :         if (ret != EOK && ret != EEXIST) {
     384           0 :             DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed.\n");
     385           0 :             goto done;
     386             :         }
     387             : 
     388             :         /* mark group as already processed */
     389           0 :         groups[c][0] = '\0';
     390             :     }
     391             : 
     392           0 :     ret = EOK;
     393             : done:
     394           0 :     talloc_free(tmp_ctx);
     395             : 
     396           0 :     return ret;
     397             : }
     398             : 
     399             : static struct tevent_req *ipa_add_ad_memberships_send(TALLOC_CTX *mem_ctx,
     400             :                                              struct tevent_context *ev,
     401             :                                              struct sdap_id_ctx *sdap_id_ctx,
     402             :                                              struct ldb_dn *user_dn,
     403             :                                              struct sss_domain_info *user_dom,
     404             :                                              char **groups,
     405             :                                              struct sss_domain_info *group_dom);
     406             : static void ipa_add_ad_memberships_done(struct tevent_req *subreq);
     407             : 
     408             : struct get_ad_membership_state {
     409             :     struct tevent_context *ev;
     410             :     struct ipa_server_mode_ctx *server_mode;
     411             :     struct sdap_id_op *sdap_op;
     412             :     struct sdap_id_ctx *sdap_id_ctx;
     413             :     struct fo_server *srv;
     414             :     char *user_name;
     415             :     struct sss_domain_info *user_dom;
     416             : 
     417             :     int dp_error;
     418             :     const char *domain;
     419             :     size_t reply_count;
     420             :     struct sysdb_attrs **reply;
     421             : };
     422             : 
     423             : static void ipa_get_ad_memberships_connect_done(struct tevent_req *subreq);
     424             : static void ipa_get_ext_groups_done(struct tevent_req *subreq);
     425             : static errno_t ipa_add_ext_groups_step(struct tevent_req *req);
     426             : static errno_t ipa_add_ad_memberships_recv(struct tevent_req *req,
     427             :                                            int *dp_error_out);
     428             : 
     429           0 : struct tevent_req *ipa_get_ad_memberships_send(TALLOC_CTX *mem_ctx,
     430             :                                         struct tevent_context *ev,
     431             :                                         struct be_acct_req *ar,
     432             :                                         struct ipa_server_mode_ctx *server_mode,
     433             :                                         struct sss_domain_info *user_dom,
     434             :                                         struct sdap_id_ctx *sdap_id_ctx,
     435             :                                         const char *domain)
     436             : {
     437             :     int ret;
     438             :     struct tevent_req *req;
     439             :     struct tevent_req *subreq;
     440             :     struct get_ad_membership_state *state;
     441             : 
     442           0 :     req = tevent_req_create(mem_ctx, &state, struct get_ad_membership_state);
     443           0 :     if (req == NULL) {
     444           0 :         DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
     445           0 :         return NULL;
     446             :     }
     447             : 
     448           0 :     state->ev = ev;
     449           0 :     state->user_dom = user_dom;
     450           0 :     state->sdap_id_ctx = sdap_id_ctx;
     451           0 :     state->srv = NULL;
     452           0 :     state->domain = domain;
     453           0 :     state->dp_error = -1;
     454             : 
     455           0 :     if (((ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_INITGROUPS
     456           0 :             && (ar->entry_type & BE_REQ_TYPE_MASK) != BE_REQ_USER)
     457           0 :             || ar->filter_type != BE_FILTER_NAME) {
     458           0 :         DEBUG(SSSDBG_OP_FAILURE, "Unsupported request type.\n");
     459           0 :         ret = EINVAL;
     460           0 :         goto done;
     461             :     }
     462             : 
     463           0 :     state->user_name = talloc_strdup(state, ar->filter_value);
     464           0 :     if (state->user_name == NULL) {
     465           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_Strdup failed.\n");
     466           0 :         ret = ENOMEM;
     467           0 :         goto done;
     468             :     }
     469             : 
     470           0 :     state->sdap_op = sdap_id_op_create(state,
     471           0 :                                        state->sdap_id_ctx->conn->conn_cache);
     472           0 :     if (state->sdap_op == NULL) {
     473           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
     474           0 :         ret = ENOMEM;
     475           0 :         goto done;
     476             :     }
     477             : 
     478           0 :     state->server_mode = server_mode;
     479           0 :     if (server_mode->ext_groups == NULL) {
     480           0 :         server_mode->ext_groups = talloc_zero(server_mode,
     481             :                                               struct ipa_ext_groups);
     482           0 :         if (server_mode->ext_groups == NULL) {
     483           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_zero failed.\n");
     484           0 :             ret = ENOMEM;
     485           0 :             goto done;
     486             :         }
     487             :     }
     488             : 
     489           0 :     if (server_mode->ext_groups->next_update > time(NULL)) {
     490           0 :         DEBUG(SSSDBG_TRACE_FUNC, "External group information still valid.\n");
     491           0 :         ret = ipa_add_ext_groups_step(req);
     492           0 :         if (ret == EOK) {
     493           0 :             goto done;
     494           0 :         } else if (ret == EAGAIN) {
     495           0 :             return req;
     496             :         } else {
     497           0 :             DEBUG(SSSDBG_OP_FAILURE, "ipa_add_ext_groups_step failed.\n");
     498           0 :             goto done;
     499             :         }
     500             : 
     501             :     }
     502             : 
     503           0 :     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
     504           0 :     if (subreq == NULL) {
     505           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
     506             :                                   ret, strerror(ret));
     507           0 :         goto done;
     508             :     }
     509             : 
     510           0 :     tevent_req_set_callback(subreq, ipa_get_ad_memberships_connect_done, req);
     511             : 
     512           0 :     return req;
     513             : 
     514             : done:
     515           0 :     if (ret != EOK) {
     516           0 :         state->dp_error = DP_ERR_FATAL;
     517           0 :         tevent_req_error(req, ret);
     518             :     } else {
     519           0 :         state->dp_error = DP_ERR_OK;
     520           0 :         tevent_req_done(req);
     521             :     }
     522           0 :     tevent_req_post(req, state->ev);
     523             : 
     524           0 :     return req;
     525             : }
     526             : 
     527           0 : static void ipa_get_ad_memberships_connect_done(struct tevent_req *subreq)
     528             : {
     529           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     530             :                                                       struct tevent_req);
     531           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     532             :                                                 struct get_ad_membership_state);
     533             :     int ret;
     534             :     char *basedn;
     535             : 
     536           0 :     ret = sdap_id_op_connect_recv(subreq, &state->dp_error);
     537           0 :     talloc_zfree(subreq);
     538           0 :     if (ret != EOK) {
     539           0 :         if (state->dp_error == DP_ERR_OFFLINE) {
     540           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     541             :                   "No IPA server is available, going offline\n");
     542             :         } else {
     543           0 :             DEBUG(SSSDBG_OP_FAILURE,
     544             :                   "Failed to connect to IPA server: [%d](%s)\n",
     545             :                    ret, strerror(ret));
     546             :         }
     547             : 
     548           0 :         goto fail;
     549             :     }
     550             : 
     551             : 
     552           0 :     ret = domain_to_basedn(state, state->domain, &basedn);
     553           0 :     if (ret != EOK) {
     554           0 :         DEBUG(SSSDBG_OP_FAILURE, "domain_to_basedn failed.\n");
     555           0 :         goto fail;
     556             :     }
     557             : 
     558           0 :     subreq = sdap_get_generic_send(state, state->ev, state->sdap_id_ctx->opts,
     559             :                                  sdap_id_op_handle(state->sdap_op), basedn,
     560             :                                  LDAP_SCOPE_SUBTREE,
     561             :                                  IPA_EXT_GROUPS_FILTER, NULL, NULL, 0,
     562           0 :                                  dp_opt_get_int(state->sdap_id_ctx->opts->basic,
     563             :                                                 SDAP_ENUM_SEARCH_TIMEOUT),
     564             :                                  false);
     565           0 :     if (subreq == NULL) {
     566           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_get_generic_send failed.\n");
     567           0 :         ret = ENOMEM;
     568           0 :         goto fail;
     569             :     }
     570             : 
     571           0 :     tevent_req_set_callback(subreq, ipa_get_ext_groups_done, req);
     572           0 :     return;
     573             : 
     574             : fail:
     575           0 :     tevent_req_error(req, ret);
     576           0 :     return;
     577             : }
     578             : 
     579           0 : static void ipa_get_ext_groups_done(struct tevent_req *subreq)
     580             : {
     581           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     582             :                                                       struct tevent_req);
     583           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     584             :                                                 struct get_ad_membership_state);
     585             :     int ret;
     586             :     hash_table_t *ext_group_hash;
     587             : 
     588           0 :     ret = sdap_get_generic_recv(subreq, state,
     589             :                                 &state->reply_count, &state->reply);
     590           0 :     talloc_zfree(subreq);
     591           0 :     if (ret != EOK) {
     592           0 :         DEBUG(SSSDBG_OP_FAILURE, "ipa_get_ext_groups request failed.\n");
     593           0 :         tevent_req_error(req, ret);
     594           0 :         return;
     595             :     }
     596             : 
     597           0 :     DEBUG(SSSDBG_TRACE_FUNC, "[%zu] external groups found.\n",
     598             :                               state->reply_count);
     599             : 
     600           0 :     ret = process_ext_groups(state->server_mode->ext_groups,
     601             :                              state->reply_count, state->reply, &ext_group_hash);
     602           0 :     if (ret != EOK) {
     603           0 :         DEBUG(SSSDBG_OP_FAILURE, "process_ext_groups failed.\n");
     604           0 :         goto fail;
     605             :     }
     606             : 
     607           0 :     state->server_mode->ext_groups->ext_groups = ext_group_hash;
     608             :     /* Do we have to make the update timeout configurable? */
     609           0 :     state->server_mode->ext_groups->next_update = time(NULL) + 10;
     610             : 
     611           0 :     ret = ipa_add_ext_groups_step(req);
     612           0 :     if (ret == EOK) {
     613           0 :         tevent_req_done(req);
     614           0 :         return;
     615           0 :     } else if (ret == EAGAIN) {
     616           0 :         return;
     617             :     } else {
     618           0 :         DEBUG(SSSDBG_OP_FAILURE, "ipa_add_ext_groups_step failed.\n");
     619           0 :         goto fail;
     620             :     }
     621             : 
     622             : fail:
     623           0 :     tevent_req_error(req, ret);
     624           0 :     return;
     625             : }
     626             : 
     627           0 : static errno_t ipa_add_ext_groups_step(struct tevent_req *req)
     628             : {
     629           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     630             :                                                 struct get_ad_membership_state);
     631             :     struct ldb_dn *user_dn;
     632             :     int ret;
     633           0 :     char **groups = NULL;
     634             :     struct tevent_req *subreq;
     635             : 
     636           0 :     ret = find_ipa_ext_memberships(state, state->user_name, state->user_dom,
     637           0 :                                    state->server_mode->ext_groups->ext_groups,
     638             :                                    &user_dn, &groups);
     639           0 :     if (ret != EOK) {
     640           0 :         DEBUG(SSSDBG_OP_FAILURE, "find_ipa_ext_memberships failed.\n");
     641           0 :         goto fail;
     642             :     }
     643             : 
     644           0 :     if (groups == NULL) {
     645           0 :         DEBUG(SSSDBG_TRACE_ALL, "No external groups memberships found.\n");
     646           0 :         state->dp_error = DP_ERR_OK;
     647           0 :         return EOK;
     648             :     }
     649             : 
     650           0 :     subreq = ipa_add_ad_memberships_send(state, state->ev, state->sdap_id_ctx,
     651             :                                          user_dn, state->user_dom, groups,
     652           0 :                                          state->sdap_id_ctx->be->domain);
     653           0 :     if (subreq == NULL) {
     654           0 :         DEBUG(SSSDBG_OP_FAILURE, "ipa_add_ad_memberships_send failed.\n");
     655           0 :         ret = ENOMEM;
     656           0 :         goto fail;
     657             :     }
     658             : 
     659           0 :     tevent_req_set_callback(subreq, ipa_add_ad_memberships_done, req);
     660           0 :     return EAGAIN;
     661             : 
     662             : fail:
     663           0 :     tevent_req_error(req, ret);
     664           0 :     return ret;
     665             : }
     666             : 
     667           0 : static void ipa_add_ad_memberships_done(struct tevent_req *subreq)
     668             : {
     669           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     670             :                                                       struct tevent_req);
     671           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     672             :                                                 struct get_ad_membership_state);
     673             :     int ret;
     674             : 
     675           0 :     ret = ipa_add_ad_memberships_recv(subreq, &state->dp_error);
     676           0 :     talloc_zfree(subreq);
     677           0 :     if (ret != EOK) {
     678           0 :         DEBUG(SSSDBG_OP_FAILURE, "ipa_add_ad_memberships request failed.\n");
     679           0 :         tevent_req_error(req, ret);
     680           0 :         return;
     681             :     }
     682             : 
     683           0 :     state->dp_error = DP_ERR_OK;
     684           0 :     tevent_req_done(req);
     685           0 :     return;
     686             : }
     687             : 
     688           0 : errno_t ipa_get_ad_memberships_recv(struct tevent_req *req, int *dp_error_out)
     689             : {
     690           0 :     struct get_ad_membership_state *state = tevent_req_data(req,
     691             :                                                 struct get_ad_membership_state);
     692             : 
     693           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     694             : 
     695           0 :     if (dp_error_out) {
     696           0 :         *dp_error_out = state->dp_error;
     697             :     }
     698             : 
     699           0 :     return EOK;
     700             : }
     701             : 
     702             : struct add_ad_membership_state {
     703             :     struct tevent_context *ev;
     704             :     struct sdap_id_ctx *sdap_id_ctx;
     705             :     struct sdap_id_op *sdap_op;
     706             :     struct ldb_dn *user_dn;
     707             :     struct sss_domain_info *user_dom;
     708             :     struct sss_domain_info *group_dom;
     709             :     char **groups;
     710             :     int dp_error;
     711             :     size_t iter;
     712             :     struct sdap_domain *group_sdom;
     713             : };
     714             : 
     715             : static void ipa_add_ad_memberships_connect_done(struct tevent_req *subreq);
     716             : static void ipa_add_ad_memberships_get_next(struct tevent_req *req);
     717             : static void ipa_add_ad_memberships_get_group_done(struct tevent_req *subreq);
     718           0 : static struct tevent_req *ipa_add_ad_memberships_send(TALLOC_CTX *mem_ctx,
     719             :                                              struct tevent_context *ev,
     720             :                                              struct sdap_id_ctx *sdap_id_ctx,
     721             :                                              struct ldb_dn *user_dn,
     722             :                                              struct sss_domain_info *user_dom,
     723             :                                              char **groups,
     724             :                                              struct sss_domain_info *group_dom)
     725             : {
     726             :     int ret;
     727             :     struct tevent_req *req;
     728             :     struct tevent_req *subreq;
     729             :     struct add_ad_membership_state *state;
     730           0 :     bool missing_groups = false;
     731             : 
     732           0 :     req = tevent_req_create(mem_ctx, &state, struct add_ad_membership_state);
     733           0 :     if (req == NULL) {
     734           0 :         DEBUG(SSSDBG_OP_FAILURE, "tevent_req_create failed.\n");
     735           0 :         return NULL;
     736             :     }
     737             : 
     738           0 :     state->ev = ev;
     739           0 :     state->user_dom = user_dom;
     740           0 :     state->sdap_id_ctx = sdap_id_ctx;
     741           0 :     state->user_dn = user_dn;
     742           0 :     state->group_dom = group_dom;
     743           0 :     state->groups = groups;
     744           0 :     state->dp_error = -1;
     745           0 :     state->iter = 0;
     746           0 :     state->group_sdom = sdap_domain_get(sdap_id_ctx->opts, group_dom);
     747           0 :     if (state->group_sdom == NULL) {
     748           0 :         ret = EIO;
     749           0 :         goto done;
     750             :     }
     751             : 
     752           0 :     ret = add_ad_user_to_cached_groups(user_dn, user_dom, group_dom, groups,
     753             :                                        &missing_groups);
     754           0 :     if (ret != EOK) {
     755           0 :         DEBUG(SSSDBG_OP_FAILURE, "add_ad_user_to_cached_groups failed.\n");
     756           0 :         goto done;
     757             :     }
     758             : 
     759           0 :     if (!missing_groups) {
     760           0 :         DEBUG(SSSDBG_TRACE_ALL, "All groups found in cache.\n");
     761           0 :         ret = EOK;
     762           0 :         goto done;
     763             :     }
     764             : 
     765           0 :     state->sdap_op = sdap_id_op_create(state,
     766           0 :                                        state->sdap_id_ctx->conn->conn_cache);
     767           0 :     if (state->sdap_op == NULL) {
     768           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
     769           0 :         ret = ENOMEM;
     770           0 :         goto done;
     771             :     }
     772             : 
     773           0 :     subreq = sdap_id_op_connect_send(state->sdap_op, state, &ret);
     774           0 :     if (subreq == NULL) {
     775           0 :         DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_connect_send failed: %d(%s).\n",
     776             :                                   ret, strerror(ret));
     777           0 :         goto done;
     778             :     }
     779             : 
     780           0 :     tevent_req_set_callback(subreq, ipa_add_ad_memberships_connect_done, req);
     781             : 
     782           0 :     return req;
     783             : 
     784             : done:
     785           0 :     if (ret != EOK) {
     786           0 :         state->dp_error = DP_ERR_FATAL;
     787           0 :         tevent_req_error(req, ret);
     788             :     } else {
     789           0 :         state->dp_error = DP_ERR_OK;
     790           0 :         tevent_req_done(req);
     791             :     }
     792           0 :     tevent_req_post(req, state->ev);
     793             : 
     794           0 :     return req;
     795             : }
     796             : 
     797           0 : static void ipa_add_ad_memberships_connect_done(struct tevent_req *subreq)
     798             : {
     799           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     800             :                                                       struct tevent_req);
     801           0 :     struct add_ad_membership_state *state = tevent_req_data(req,
     802             :                                                 struct add_ad_membership_state);
     803             :     int ret;
     804             : 
     805           0 :     ret = sdap_id_op_connect_recv(subreq, &state->dp_error);
     806           0 :     talloc_zfree(subreq);
     807           0 :     if (ret != EOK) {
     808           0 :         if (state->dp_error == DP_ERR_OFFLINE) {
     809           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     810             :                   "No IPA server is available, going offline\n");
     811             :         } else {
     812           0 :             DEBUG(SSSDBG_OP_FAILURE,
     813             :                   "Failed to connect to IPA server: [%d](%s)\n",
     814             :                    ret, strerror(ret));
     815             :         }
     816             : 
     817           0 :         tevent_req_error(req, ret);
     818           0 :         return;
     819             :     }
     820             : 
     821           0 :     state->iter = 0;
     822           0 :     ipa_add_ad_memberships_get_next(req);
     823             : }
     824             : 
     825           0 : static void ipa_add_ad_memberships_get_next(struct tevent_req *req)
     826             : {
     827           0 :     struct add_ad_membership_state *state = tevent_req_data(req,
     828             :                                                 struct add_ad_membership_state);
     829             :     struct tevent_req *subreq;
     830             :     struct ldb_dn *group_dn;
     831             :     int ret;
     832             :     const struct ldb_val *val;
     833             :     bool missing_groups;
     834             : 
     835           0 :     while (state->groups[state->iter] != NULL
     836           0 :             && state->groups[state->iter][0] == '\0') {
     837           0 :         state->iter++;
     838             :     }
     839             : 
     840           0 :     if (state->groups[state->iter] == NULL) {
     841           0 :         ret = add_ad_user_to_cached_groups(state->user_dn, state->user_dom,
     842             :                                            state->group_dom, state->groups,
     843             :                                            &missing_groups);
     844           0 :         if (ret != EOK) {
     845           0 :             DEBUG(SSSDBG_OP_FAILURE, "add_ad_user_to_cached_groups failed.\n");
     846           0 :             goto fail;
     847             :         }
     848             : 
     849           0 :         if (missing_groups) {
     850           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "There are unresolved external group "
     851             :                                        "memberships even after all groups "
     852             :                                        "have been looked up on the LDAP "
     853             :                                        "server.\n");
     854             :         }
     855           0 :         tevent_req_done(req);
     856           0 :         return;
     857             :     }
     858             : 
     859           0 :     group_dn = ldb_dn_new(state, sysdb_ctx_get_ldb(state->group_dom->sysdb),
     860           0 :                           state->groups[state->iter]);
     861           0 :     if (group_dn == NULL) {
     862           0 :         DEBUG(SSSDBG_OP_FAILURE, "ldb_dn_new failed.\n");
     863           0 :         ret = ENOMEM;
     864           0 :         goto fail;
     865             :     }
     866             : 
     867           0 :     val = ldb_dn_get_component_val(group_dn, 0);
     868             : 
     869             : /* TODO: here is would be useful for have a filter type like BE_FILTER_DN to
     870             :  * directly fetch the group with the corresponding DN. */
     871           0 :     subreq = groups_get_send(state, state->ev,
     872             :                                  state->sdap_id_ctx, state->group_sdom,
     873           0 :                                  state->sdap_id_ctx->conn,
     874           0 :                                  (const char *) val->data,
     875             :                                  BE_FILTER_NAME, BE_ATTR_CORE,
     876             :                                  false, false);
     877           0 :     if (subreq == NULL) {
     878           0 :         DEBUG(SSSDBG_OP_FAILURE, "groups_get_send failed.\n");
     879           0 :         ret = ENOMEM;
     880           0 :         goto fail;
     881             :     }
     882             : 
     883           0 :     tevent_req_set_callback(subreq, ipa_add_ad_memberships_get_group_done, req);
     884           0 :     return;
     885             : 
     886             : fail:
     887           0 :     tevent_req_error(req, ret);
     888             : }
     889             : 
     890           0 : static void ipa_add_ad_memberships_get_group_done(struct tevent_req *subreq)
     891             : {
     892           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     893             :                                                       struct tevent_req);
     894           0 :     struct add_ad_membership_state *state = tevent_req_data(req,
     895             :                                                 struct add_ad_membership_state);
     896             :     int ret;
     897             : 
     898           0 :     ret = groups_get_recv(subreq, &state->dp_error, NULL);
     899           0 :     talloc_zfree(subreq);
     900           0 :     if (ret != EOK) {
     901           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to read group [%s] from LDAP [%d](%s)\n",
     902             :               state->groups[state->iter], ret, strerror(ret));
     903             : 
     904           0 :         tevent_req_error(req, ret);
     905           0 :         return;
     906             :     }
     907             : 
     908           0 :     state->iter++;
     909           0 :     ipa_add_ad_memberships_get_next(req);
     910             : }
     911             : 
     912           0 : static errno_t ipa_add_ad_memberships_recv(struct tevent_req *req,
     913             :                                            int *dp_error_out)
     914             : {
     915           0 :     struct add_ad_membership_state *state = tevent_req_data(req,
     916             :                                                 struct add_ad_membership_state);
     917             : 
     918           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     919             : 
     920           0 :     if (dp_error_out) {
     921           0 :         *dp_error_out = state->dp_error;
     922             :     }
     923             : 
     924           0 :     return EOK;
     925             : }

Generated by: LCOV version 1.10