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

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Async LDAP Helper routines - retrieving groups
       5             : 
       6             :     Copyright (C) Simo Sorce <ssorce@redhat.com> - 2009
       7             :     Copyright (C) 2010, Ralf Haferkamp <rhafer@suse.de>, Novell Inc.
       8             :     Copyright (C) Jan Zeleny <jzeleny@redhat.com> - 2011
       9             : 
      10             :     This program is free software; you can redistribute it and/or modify
      11             :     it under the terms of the GNU General Public License as published by
      12             :     the Free Software Foundation; either version 3 of the License, or
      13             :     (at your option) any later version.
      14             : 
      15             :     This program is distributed in the hope that it will be useful,
      16             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :     GNU General Public License for more details.
      19             : 
      20             :     You should have received a copy of the GNU General Public License
      21             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "util/util.h"
      25             : #include "db/sysdb.h"
      26             : #include "providers/ldap/sdap_async_private.h"
      27             : #include "providers/ldap/ldap_common.h"
      28             : #include "providers/ldap/sdap_idmap.h"
      29             : #include "providers/ad/ad_common.h"
      30             : 
      31             : /* ==Group-Parsing Routines=============================================== */
      32             : 
      33           0 : static int sdap_find_entry_by_origDN(TALLOC_CTX *memctx,
      34             :                                      struct sysdb_ctx *ctx,
      35             :                                      struct sss_domain_info *domain,
      36             :                                      const char *orig_dn,
      37             :                                      char **_localdn,
      38             :                                      bool *_is_group)
      39             : {
      40             :     TALLOC_CTX *tmpctx;
      41           0 :     const char *attrs[] = {SYSDB_OBJECTCLASS,  NULL};
      42             :     struct ldb_dn *base_dn;
      43             :     char *filter;
      44             :     struct ldb_message **msgs;
      45             :     size_t num_msgs;
      46             :     int ret;
      47             :     char *sanitized_dn;
      48             :     const char *objectclass;
      49             : 
      50           0 :     tmpctx = talloc_new(NULL);
      51           0 :     if (!tmpctx) {
      52           0 :         return ENOMEM;
      53             :     }
      54             : 
      55           0 :     ret = sss_filter_sanitize(tmpctx, orig_dn, &sanitized_dn);
      56           0 :     if (ret != EOK) {
      57           0 :         ret = ENOMEM;
      58           0 :         goto done;
      59             :     }
      60             : 
      61           0 :     filter = talloc_asprintf(tmpctx, "%s=%s", SYSDB_ORIG_DN, sanitized_dn);
      62           0 :     if (!filter) {
      63           0 :         ret = ENOMEM;
      64           0 :         goto done;
      65             :     }
      66             : 
      67           0 :     base_dn = sysdb_domain_dn(tmpctx, domain);
      68           0 :     if (!base_dn) {
      69           0 :         ret = ENOMEM;
      70           0 :         goto done;
      71             :     }
      72             : 
      73           0 :     DEBUG(SSSDBG_TRACE_ALL, "Searching cache for [%s].\n", sanitized_dn);
      74           0 :     ret = sysdb_search_entry(tmpctx, ctx,
      75             :                              base_dn, LDB_SCOPE_SUBTREE, filter, attrs,
      76             :                              &num_msgs, &msgs);
      77           0 :     if (ret) {
      78           0 :         goto done;
      79             :     }
      80           0 :     if (num_msgs != 1) {
      81           0 :         ret = ENOENT;
      82           0 :         goto done;
      83             :     }
      84             : 
      85           0 :     *_localdn = talloc_strdup(memctx, ldb_dn_get_linearized(msgs[0]->dn));
      86           0 :     if (!*_localdn) {
      87           0 :         ret = ENOENT;
      88           0 :         goto done;
      89             :     }
      90             : 
      91           0 :     if (_is_group != NULL) {
      92           0 :         objectclass = ldb_msg_find_attr_as_string(msgs[0], SYSDB_OBJECTCLASS,
      93             :                                                   NULL);
      94           0 :         if (objectclass == NULL) {
      95           0 :             DEBUG(SSSDBG_OP_FAILURE, "An antry without a %s?\n",
      96             :                   SYSDB_OBJECTCLASS);
      97           0 :             ret = EINVAL;
      98           0 :             goto done;
      99             :         }
     100             : 
     101           0 :         *_is_group = strcmp(SYSDB_GROUP_CLASS, objectclass) == 0;
     102             :     }
     103             : 
     104           0 :     ret = EOK;
     105             : 
     106             : done:
     107           0 :     talloc_zfree(tmpctx);
     108           0 :     return ret;
     109             : }
     110             : 
     111             : static errno_t
     112           0 : sdap_get_members_with_primary_gid(TALLOC_CTX *mem_ctx,
     113             :                                   struct sss_domain_info *domain,
     114             :                                   gid_t gid, char ***_localdn, size_t *_ndn)
     115             : {
     116             :     static const char *search_attrs[] = { SYSDB_NAME, NULL };
     117             :     char *filter;
     118             :     struct ldb_message **msgs;
     119             :     size_t count;
     120             :     size_t i;
     121             :     errno_t ret;
     122             :     char **localdn;
     123             : 
     124             :     /* Don't search if the group is non-posix */
     125           0 :     if (!gid) return EOK;
     126             : 
     127           0 :     filter = talloc_asprintf(mem_ctx, "(%s=%llu)", SYSDB_GIDNUM,
     128             :                              (unsigned long long) gid);
     129           0 :     if (!filter) {
     130           0 :         return ENOMEM;
     131             :     }
     132             : 
     133           0 :     ret = sysdb_search_users(mem_ctx, domain, filter,
     134             :                              search_attrs, &count, &msgs);
     135           0 :     talloc_free(filter);
     136           0 :     if (ret == ENOENT) {
     137           0 :         *_localdn = NULL;
     138           0 :         *_ndn = 0;
     139           0 :         return EOK;
     140           0 :     } else if (ret != EOK) {
     141           0 :         return ret;
     142             :     }
     143             : 
     144           0 :     localdn = talloc_array(mem_ctx, char *, count);
     145           0 :     if (!localdn) {
     146           0 :         talloc_free(msgs);
     147           0 :         return ENOMEM;
     148             :     }
     149             : 
     150           0 :     for (i=0; i < count; i++) {
     151           0 :         localdn[i] = talloc_strdup(localdn,
     152           0 :                                    ldb_dn_get_linearized(msgs[i]->dn));
     153           0 :         if (!localdn[i]) {
     154           0 :             talloc_free(localdn);
     155           0 :             talloc_free(msgs);
     156           0 :             return ENOMEM;
     157             :         }
     158             :     }
     159             : 
     160           0 :     talloc_free(msgs);
     161           0 :     *_localdn = localdn;
     162           0 :     *_ndn = count;
     163           0 :     return EOK;
     164             : }
     165             : 
     166             : static errno_t
     167           0 : sdap_dn_by_primary_gid(TALLOC_CTX *mem_ctx, struct sysdb_attrs *ldap_attrs,
     168             :                        struct sss_domain_info *domain,
     169             :                        struct sdap_options *opts,
     170             :                        char ***_dn_list, size_t *_count)
     171             : {
     172             :     gid_t gid;
     173             :     errno_t ret;
     174             : 
     175           0 :     ret = sysdb_attrs_get_uint32_t(ldap_attrs,
     176           0 :                                    opts->group_map[SDAP_AT_GROUP_GID].sys_name,
     177             :                                    &gid);
     178           0 :     if (ret == ENOENT) {
     179             :         /* Non-posix AD group. Skip. */
     180           0 :         *_dn_list = NULL;
     181           0 :         *_count = 0;
     182           0 :         return EOK;
     183           0 :     } else if (ret && ret != ENOENT) {
     184           0 :         return ret;
     185             :     }
     186             : 
     187           0 :     ret = sdap_get_members_with_primary_gid(mem_ctx, domain, gid,
     188             :                                             _dn_list, _count);
     189           0 :     if (ret) return ret;
     190             : 
     191           0 :     return EOK;
     192             : }
     193             : 
     194           0 : static bool has_member(struct ldb_message_element *member_el,
     195             :                        char *member)
     196             : {
     197             :     struct ldb_val val;
     198             : 
     199           0 :     val.data = (uint8_t *) member;
     200           0 :     val.length = strlen(member);
     201             : 
     202             :     /* This is bad complexity, but the this loop should only be invoked in
     203             :      * the very rare scenario of AD POSIX group that is primary group of
     204             :      * some users but has user member attributes at the same time
     205             :      */
     206           0 :     if (ldb_msg_find_val(member_el, &val) != NULL) {
     207           0 :         return true;
     208             :     }
     209             : 
     210           0 :     return false;
     211             : }
     212             : 
     213           0 : static void link_pgroup_members(struct sysdb_attrs *group_attrs,
     214             :                                 struct ldb_message_element *member_el,
     215             :                                 char **userdns,
     216             :                                 size_t nuserdns)
     217             : {
     218             :     int i, j;
     219             : 
     220           0 :     j = 0;
     221           0 :     for (i=0; i < nuserdns; i++) {
     222           0 :         if (has_member(member_el, userdns[i])) {
     223           0 :             DEBUG(SSSDBG_TRACE_INTERNAL,
     224             :                   "Member %s already included, skipping\n", userdns[i]);
     225           0 :             continue;
     226             :         }
     227             : 
     228           0 :         member_el->values[member_el->num_values + j].data = (uint8_t *) \
     229           0 :                                          talloc_steal(group_attrs, userdns[i]);
     230           0 :         member_el->values[member_el->num_values + j].length = \
     231           0 :                                          strlen(userdns[i]);
     232           0 :         j++;
     233             :     }
     234           0 :     member_el->num_values += j;
     235           0 : }
     236             : 
     237           0 : static int sdap_fill_memberships(struct sdap_options *opts,
     238             :                                  struct sysdb_attrs *group_attrs,
     239             :                                  struct sysdb_ctx *ctx,
     240             :                                  struct sss_domain_info *domain,
     241             :                                  hash_table_t *ghosts,
     242             :                                  struct ldb_val *values,
     243             :                                  int num_values,
     244             :                                  char **userdns,
     245             :                                  size_t nuserdns)
     246             : {
     247             :     struct ldb_message_element *el;
     248             :     int i, j;
     249             :     int ret;
     250             :     errno_t hret;
     251             :     hash_key_t key;
     252             :     hash_value_t value;
     253             :     struct sdap_domain *sdom;
     254             :     struct sysdb_ctx *member_sysdb;
     255             :     struct sss_domain_info *member_dom;
     256             : 
     257           0 :     ret = sysdb_attrs_get_el(group_attrs, SYSDB_MEMBER, &el);
     258           0 :     if (ret) {
     259           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_get_el failed\n");
     260           0 :         goto done;
     261             :     }
     262             : 
     263             :     /* Just allocate both big enough to contain all members for now */
     264           0 :     el->values = talloc_realloc(group_attrs, el->values, struct ldb_val,
     265             :                                 el->num_values + num_values + nuserdns);
     266           0 :     if (!el->values) {
     267           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "No memory to allocate group attrs\n");
     268           0 :         ret = ENOMEM;
     269           0 :         goto done;
     270             :     }
     271             : 
     272           0 :     j = el->num_values;
     273           0 :     for (i = 0; i < num_values; i++) {
     274           0 :         if (ghosts == NULL) {
     275           0 :             hret = HASH_ERROR_KEY_NOT_FOUND;
     276             :         } else {
     277           0 :             key.type = HASH_KEY_STRING;
     278           0 :             key.str = (char *)values[i].data;
     279           0 :             hret = hash_lookup(ghosts, &key, &value);
     280             :         }
     281             : 
     282           0 :         if (hret == HASH_ERROR_KEY_NOT_FOUND) {
     283           0 :             sdom = sdap_domain_get_by_dn(opts, (char *)values[i].data);
     284           0 :             if (sdom == NULL) {
     285           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Member [%s] is it out of domain "
     286             :                       "scope?\n", (char *)values[i].data);
     287           0 :                 member_sysdb = ctx;
     288           0 :                 member_dom = domain;
     289             :             } else {
     290           0 :                 member_sysdb = sdom->dom->sysdb;
     291           0 :                 member_dom = sdom->dom;
     292             :             }
     293             : 
     294             :             /* sync search entry with this as origDN */
     295           0 :             ret = sdap_find_entry_by_origDN(el->values, member_sysdb,
     296           0 :                                             member_dom, (char *)values[i].data,
     297           0 :                                             (char **)&el->values[j].data,
     298             :                                             NULL);
     299           0 :             if (ret == ENOENT) {
     300             :                 /* member may be outside of the configured search bases
     301             :                  * or out of scope of nesting limit */
     302           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "Member [%s] was not found in "
     303             :                       "cache. Is it out of scope?\n", (char *)values[i].data);
     304           0 :                 continue;
     305             :             }
     306           0 :             if (ret != EOK) {
     307           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
     308             :                       "'sdap_find_entry_by_origDN' failed for member [%s].\n",
     309             :                       (char *)values[i].data);
     310           0 :                 goto done;
     311             :             }
     312             : 
     313           0 :             DEBUG(SSSDBG_TRACE_LIBS, "    member #%d (%s): [%s]\n",
     314             :                       i, (char *)values[i].data,
     315             :                       (char *)el->values[j].data);
     316             : 
     317           0 :             el->values[j].length = strlen((char *)el->values[j].data);
     318           0 :             j++;
     319           0 :         } else if (hret != HASH_SUCCESS) {
     320           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     321             :                   "hash_lookup failed: [%d]: %s\n", hret, strerror(hret));
     322           0 :             ret = EFAULT;
     323           0 :             goto done;
     324             :         }
     325             : 
     326             :         /* If the member is in ghost table, it has
     327             :          * already been processed - just skip it */
     328             :     }
     329           0 :     el->num_values = j;
     330             : 
     331           0 :     link_pgroup_members(group_attrs, el, userdns, nuserdns);
     332           0 :     ret = EOK;
     333             : 
     334             : done:
     335           0 :     return ret;
     336             : }
     337             : 
     338             : /* ==Save-Group-Entry===================================================== */
     339             : 
     340             :     /* FIXME: support non legacy */
     341             :     /* FIXME: support storing additional attributes */
     342             : 
     343             : static errno_t
     344           0 : sdap_store_group_with_gid(struct sss_domain_info *domain,
     345             :                           const char *name,
     346             :                           gid_t gid,
     347             :                           struct sysdb_attrs *group_attrs,
     348             :                           uint64_t cache_timeout,
     349             :                           bool posix_group,
     350             :                           time_t now)
     351             : {
     352             :     errno_t ret;
     353             : 
     354             :     /* make sure that non-posix (empty or explicit gid=0) groups have the
     355             :      * gidNumber set to zero even if updating existing group */
     356           0 :     if (!posix_group) {
     357           0 :         ret = sysdb_attrs_add_uint32(group_attrs, SYSDB_GIDNUM, 0);
     358           0 :         if (ret) {
     359           0 :             DEBUG(SSSDBG_OP_FAILURE,
     360             :                   "Could not set explicit GID 0 for %s\n", name);
     361           0 :             return ret;
     362             :         }
     363             :     }
     364             : 
     365           0 :     ret = sysdb_store_group(domain, name, gid, group_attrs,
     366             :                             cache_timeout, now);
     367           0 :     if (ret) {
     368           0 :         DEBUG(SSSDBG_OP_FAILURE, "Could not store group %s\n", name);
     369           0 :         return ret;
     370             :     }
     371             : 
     372           0 :     return ret;
     373             : }
     374             : 
     375             : static errno_t
     376           0 : sdap_process_ghost_members(struct sysdb_attrs *attrs,
     377             :                            struct sdap_options *opts,
     378             :                            hash_table_t *ghosts,
     379             :                            bool populate_members,
     380             :                            bool store_original_member,
     381             :                            struct sysdb_attrs *sysdb_attrs)
     382             : {
     383             :     errno_t ret;
     384             :     struct ldb_message_element *gh;
     385             :     struct ldb_message_element *memberel;
     386             :     struct ldb_message_element *sysdb_memberel;
     387             :     struct ldb_message_element *ghostel;
     388             :     size_t cnt;
     389             :     int i;
     390             :     int hret;
     391             :     hash_key_t key;
     392             :     hash_value_t value;
     393             : 
     394           0 :     ret = sysdb_attrs_get_el(attrs, SYSDB_GHOST, &gh);
     395           0 :     if (ret != EOK) {
     396           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     397             :               "Error reading ghost attributes: [%s]\n",
     398             :                strerror(ret));
     399           0 :         return ret;
     400             :     }
     401             : 
     402           0 :     ret = sysdb_attrs_get_el_ext(attrs,
     403           0 :                              opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
     404             :                              false, &memberel);
     405           0 :     if (ret == ENOENT) {
     406             :         /* Create a dummy element with no values in order for the loop to just
     407             :          * fall through and make sure the attrs array is not reallocated.
     408             :          */
     409           0 :         memberel = talloc(attrs, struct ldb_message_element);
     410           0 :         if (memberel == NULL) {
     411           0 :             return ENOMEM;
     412             :         }
     413           0 :         memberel->num_values = 0;
     414           0 :         memberel->values = NULL;
     415           0 :     } else if (ret != EOK) {
     416           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     417             :                 "Error reading members: [%s]\n", strerror(ret));
     418           0 :         return ret;
     419             :     }
     420             : 
     421           0 :     if (store_original_member) {
     422           0 :         DEBUG(SSSDBG_TRACE_FUNC, "The group has %d members\n", memberel->num_values);
     423           0 :         for (i = 0; i < memberel->num_values; i++) {
     424           0 :             ret = sysdb_attrs_add_string(sysdb_attrs, SYSDB_ORIG_MEMBER,
     425           0 :                                         (const char *) memberel->values[i].data);
     426           0 :             if (ret) {
     427           0 :                 DEBUG(SSSDBG_OP_FAILURE, "Could not add member [%s]\n",
     428             :                       (const char *) memberel->values[i].data);
     429           0 :                 return ret;
     430             :             }
     431             :         }
     432             :     }
     433             : 
     434           0 :     if (populate_members) {
     435           0 :         ret = sysdb_attrs_get_el(sysdb_attrs, SYSDB_MEMBER, &sysdb_memberel);
     436           0 :         if (ret != EOK) {
     437           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     438             :                   "Error reading group members from group_attrs: [%s]\n",
     439             :                    strerror(ret));
     440           0 :             return ret;
     441             :         }
     442           0 :         sysdb_memberel->values = memberel->values;
     443           0 :         sysdb_memberel->num_values = memberel->num_values;
     444             :     }
     445             : 
     446           0 :     ret = sysdb_attrs_get_el(sysdb_attrs, SYSDB_GHOST, &ghostel);
     447           0 :     if (ret != EOK) {
     448           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     449             :               "Error getting ghost element: [%s]\n", strerror(ret));
     450           0 :         return ret;
     451             :     }
     452           0 :     ghostel->values = gh->values;
     453           0 :     ghostel->num_values = gh->num_values;
     454             : 
     455           0 :     cnt = ghostel->num_values + memberel->num_values;
     456           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Group has %zu members\n", cnt);
     457             : 
     458             :     /* Now process RFC2307bis ghost hash table */
     459           0 :     if (ghosts && cnt > 0) {
     460           0 :         ghostel->values = talloc_realloc(sysdb_attrs, ghostel->values,
     461             :                                          struct ldb_val, cnt);
     462           0 :         if (ghostel->values == NULL) {
     463           0 :             return ENOMEM;
     464             :         }
     465             : 
     466           0 :         for (i = 0; i < memberel->num_values; i++) {
     467           0 :             key.type = HASH_KEY_STRING;
     468           0 :             key.str = (char *) memberel->values[i].data;
     469           0 :             hret = hash_lookup(ghosts, &key, &value);
     470           0 :             if (hret == HASH_ERROR_KEY_NOT_FOUND) {
     471           0 :                 continue;
     472           0 :             } else if (hret != HASH_SUCCESS) {
     473           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
     474             :                       "Error checking hash table: [%s]\n",
     475             :                        hash_error_string(hret));
     476           0 :                 return EFAULT;
     477             :             }
     478             : 
     479           0 :             DEBUG(SSSDBG_TRACE_FUNC,
     480             :                   "Adding ghost member for group [%s]\n", (char *) value.ptr);
     481           0 :             ghostel->values[ghostel->num_values].data = \
     482           0 :                         (uint8_t *) talloc_strdup(ghostel->values, value.ptr);
     483           0 :             if (ghostel->values[ghostel->num_values].data == NULL) {
     484           0 :                 return ENOMEM;
     485             :             }
     486           0 :             ghostel->values[ghostel->num_values].length = strlen(value.ptr);
     487           0 :             ghostel->num_values++;
     488             :         }
     489             :     }
     490             : 
     491           0 :     return EOK;
     492             : }
     493             : 
     494           0 : static int sdap_save_group(TALLOC_CTX *memctx,
     495             :                            struct sdap_options *opts,
     496             :                            struct sss_domain_info *dom,
     497             :                            struct sysdb_attrs *attrs,
     498             :                            bool populate_members,
     499             :                            bool store_original_member,
     500             :                            hash_table_t *ghosts,
     501             :                            char **_usn_value,
     502             :                            time_t now)
     503             : {
     504             :     struct ldb_message_element *el;
     505             :     struct sysdb_attrs *group_attrs;
     506           0 :     const char *group_name = NULL;
     507             :     gid_t gid;
     508             :     errno_t ret;
     509           0 :     char *usn_value = NULL;
     510           0 :     TALLOC_CTX *tmpctx = NULL;
     511             :     bool posix_group;
     512             :     bool use_id_mapping;
     513             :     bool need_filter;
     514             :     char *sid_str;
     515             :     struct sss_domain_info *subdomain;
     516             : 
     517           0 :     tmpctx = talloc_new(NULL);
     518           0 :     if (!tmpctx) {
     519           0 :         ret = ENOMEM;
     520           0 :         goto done;
     521             :     }
     522             : 
     523           0 :     group_attrs = sysdb_new_attrs(tmpctx);
     524           0 :     if (group_attrs == NULL) {
     525           0 :         ret = ENOMEM;
     526           0 :         goto done;
     527             :     }
     528             : 
     529             :     /* Always store SID string if available */
     530           0 :     ret = sdap_attrs_get_sid_str(tmpctx, opts->idmap_ctx, attrs,
     531           0 :                               opts->group_map[SDAP_AT_GROUP_OBJECTSID].sys_name,
     532             :                               &sid_str);
     533           0 :     if (ret == EOK) {
     534           0 :         ret = sysdb_attrs_add_string(group_attrs, SYSDB_SID_STR, sid_str);
     535           0 :         if (ret != EOK) {
     536           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Could not add SID string: [%s]\n",
     537             :                                          sss_strerror(ret));
     538           0 :             goto done;
     539             :         }
     540           0 :     } else if (ret == ENOENT) {
     541           0 :         DEBUG(SSSDBG_TRACE_ALL, "objectSID: not available for group [%s].\n",
     542             :                                  group_name);
     543           0 :         sid_str = NULL;
     544             :     } else {
     545           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "Could not identify objectSID: [%s]\n",
     546             :                                      sss_strerror(ret));
     547           0 :         sid_str = NULL;
     548             :     }
     549             : 
     550             :     /* Always store UUID if available */
     551           0 :     ret = sysdb_handle_original_uuid(
     552           0 :                                    opts->group_map[SDAP_AT_GROUP_UUID].def_name,
     553             :                                    attrs,
     554           0 :                                    opts->group_map[SDAP_AT_GROUP_UUID].sys_name,
     555             :                                    group_attrs, SYSDB_UUID);
     556           0 :     if (ret != EOK) {
     557           0 :         DEBUG((ret == ENOENT) ? SSSDBG_TRACE_ALL : SSSDBG_MINOR_FAILURE,
     558             :               "Failed to retrieve UUID [%d][%s].\n", ret, sss_strerror(ret));
     559             :     }
     560             : 
     561             :     /* If this object has a SID available, we will determine the correct
     562             :      * domain by its SID. */
     563           0 :     if (sid_str != NULL) {
     564           0 :         subdomain = sss_get_domain_by_sid_ldap_fallback(get_domains_head(dom),
     565             :                                                         sid_str);
     566           0 :         if (subdomain) {
     567           0 :             dom = subdomain;
     568             :         } else {
     569           0 :             DEBUG(SSSDBG_TRACE_FUNC, "SID %s does not belong to any known "
     570             :                                       "domain\n", sid_str);
     571             :         }
     572             :     }
     573             : 
     574           0 :     ret = sdap_get_group_primary_name(tmpctx, opts, attrs, dom, &group_name);
     575           0 :     if (ret != EOK) {
     576           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to get group name\n");
     577           0 :         goto done;
     578             :     }
     579           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Processing group %s\n", group_name);
     580             : 
     581           0 :     posix_group = true;
     582           0 :     ret = sdap_check_ad_group_type(dom, opts, attrs, group_name,
     583             :                                    &need_filter);
     584           0 :     if (ret != EOK) {
     585           0 :         goto done;
     586             :     }
     587           0 :     if (need_filter) {
     588           0 :         posix_group = false;
     589           0 :         gid = 0;
     590             : 
     591           0 :         ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, false);
     592           0 :         if (ret != EOK) {
     593           0 :             DEBUG(SSSDBG_OP_FAILURE,
     594             :                   "Error: Failed to mark group as non-posix!\n");
     595           0 :             goto done;
     596             :         }
     597             :     }
     598             : 
     599           0 :     if (posix_group) {
     600           0 :         use_id_mapping = sdap_idmap_domain_has_algorithmic_mapping(opts->idmap_ctx,
     601           0 :                                                                    dom->name,
     602             :                                                                    sid_str);
     603           0 :         if (use_id_mapping) {
     604           0 :             posix_group = true;
     605             : 
     606           0 :             if (sid_str == NULL) {
     607           0 :                 DEBUG(SSSDBG_MINOR_FAILURE, "SID not available, cannot map a " \
     608             :                                              "unix ID to group [%s].\n", group_name);
     609           0 :                 ret = ENOENT;
     610           0 :                 goto done;
     611             :             }
     612             : 
     613           0 :             DEBUG(SSSDBG_TRACE_LIBS,
     614             :                   "Mapping group [%s] objectSID [%s] to unix ID\n",
     615             :                    group_name, sid_str);
     616             : 
     617             :             /* Convert the SID into a UNIX group ID */
     618           0 :             ret = sdap_idmap_sid_to_unix(opts->idmap_ctx, sid_str, &gid);
     619           0 :             if (ret == ENOTSUP) {
     620             :                 /* ENOTSUP is returned if built-in SID was provided
     621             :                  * => do not store the group, but return EOK */
     622           0 :                 DEBUG(SSSDBG_TRACE_FUNC, "Skipping built-in object.\n");
     623           0 :                 ret = EOK;
     624           0 :                 goto done;
     625           0 :             } else if (ret != EOK) {
     626           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
     627             :                       "Could not convert SID string: [%s]\n",
     628             :                        sss_strerror(ret));
     629           0 :                 goto done;
     630             :             }
     631             : 
     632             :             /* Store the GID in the ldap_attrs so it doesn't get
     633             :              * treated as a missing attribute from LDAP and removed.
     634             :              */
     635           0 :             ret = sdap_replace_id(attrs, SYSDB_GIDNUM, gid);
     636           0 :             if (ret) {
     637           0 :                 DEBUG(SSSDBG_OP_FAILURE, "Cannot set the id-mapped GID\n");
     638           0 :                 goto done;
     639             :             }
     640             :         } else {
     641           0 :             ret = sysdb_attrs_get_bool(attrs, SYSDB_POSIX, &posix_group);
     642           0 :             if (ret == ENOENT) {
     643           0 :                 posix_group = true;
     644           0 :             } else if (ret != EOK) {
     645           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
     646             :                       "Error reading posix attribute: [%s]\n",
     647             :                        sss_strerror(ret));
     648           0 :                 goto done;
     649             :             }
     650             : 
     651           0 :             DEBUG(SSSDBG_TRACE_INTERNAL,
     652             :                   "This is%s a posix group\n", (posix_group)?"":" not");
     653           0 :             ret = sysdb_attrs_add_bool(group_attrs, SYSDB_POSIX, posix_group);
     654           0 :             if (ret != EOK) {
     655           0 :                 DEBUG(SSSDBG_MINOR_FAILURE,
     656             :                       "Error setting posix attribute: [%s]\n",
     657             :                        sss_strerror(ret));
     658           0 :                 goto done;
     659             :             }
     660             : 
     661           0 :             ret = sysdb_attrs_get_uint32_t(attrs,
     662           0 :                                            opts->group_map[SDAP_AT_GROUP_GID].sys_name,
     663             :                                            &gid);
     664           0 :             if (ret != EOK) {
     665           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     666             :                       "no gid provided for [%s] in domain [%s].\n",
     667             :                           group_name, dom->name);
     668           0 :                 ret = EINVAL;
     669           0 :                 goto done;
     670             :             }
     671             :         }
     672             :     }
     673             : 
     674             :     /* check that the gid is valid for this domain */
     675           0 :     if (posix_group) {
     676           0 :         if (OUT_OF_ID_RANGE(gid, dom->id_min, dom->id_max)) {
     677           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     678             :                   "Group [%s] filtered out! (id out of range)\n", group_name);
     679           0 :             ret = EINVAL;
     680           0 :             goto done;
     681             :         }
     682             :         /* Group ID OK */
     683             :     }
     684             : 
     685           0 :     ret = sdap_attrs_add_string(attrs, SYSDB_ORIG_DN, "original DN",
     686             :                                 group_name, group_attrs);
     687           0 :     if (ret != EOK) {
     688           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     689             :               "Error setting original DN: [%s]\n",
     690             :                sss_strerror(ret));
     691           0 :         goto done;
     692             :     }
     693             : 
     694           0 :     ret = sdap_attrs_add_string(attrs,
     695             :                             opts->group_map[SDAP_AT_GROUP_MODSTAMP].sys_name,
     696             :                             "original mod-Timestamp",
     697             :                             group_name, group_attrs);
     698           0 :     if (ret != EOK) {
     699           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     700             :               "Error setting mod timestamp: [%s]\n",
     701             :                sss_strerror(ret));
     702           0 :         goto done;
     703             :     }
     704             : 
     705           0 :     ret = sysdb_attrs_get_el(attrs,
     706           0 :                       opts->group_map[SDAP_AT_GROUP_USN].sys_name, &el);
     707           0 :     if (ret) {
     708           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     709             :               "Error looking up group USN: [%s]\n",
     710             :                sss_strerror(ret));
     711           0 :         goto done;
     712             :     }
     713           0 :     if (el->num_values == 0) {
     714           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     715             :               "Original USN value is not available for [%s].\n", group_name);
     716             :     } else {
     717           0 :         ret = sysdb_attrs_add_string(group_attrs,
     718           0 :                           opts->group_map[SDAP_AT_GROUP_USN].sys_name,
     719           0 :                           (const char*)el->values[0].data);
     720           0 :         if (ret) {
     721           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     722             :                   "Error setting group USN: [%s]\n",
     723             :                    sss_strerror(ret));
     724           0 :             goto done;
     725             :         }
     726           0 :         usn_value = talloc_strdup(tmpctx, (const char*)el->values[0].data);
     727           0 :         if (!usn_value) {
     728           0 :             ret = ENOMEM;
     729           0 :             goto done;
     730             :         }
     731             :     }
     732             : 
     733           0 :     ret = sdap_process_ghost_members(attrs, opts, ghosts,
     734             :                                      populate_members, store_original_member,
     735             :                                      group_attrs);
     736           0 :     if (ret != EOK) {
     737           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to save ghost members\n");
     738           0 :         goto done;
     739             :     }
     740             : 
     741           0 :     ret = sdap_save_all_names(group_name, attrs, dom, group_attrs);
     742           0 :     if (ret != EOK) {
     743           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to save group names\n");
     744           0 :         goto done;
     745             :     }
     746           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Storing info for group %s\n", group_name);
     747             : 
     748           0 :     ret = sdap_store_group_with_gid(dom, group_name, gid, group_attrs,
     749           0 :                                     dom->group_timeout,
     750             :                                     posix_group, now);
     751           0 :     if (ret) {
     752           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     753             :               "Could not store group with GID: [%s]\n",
     754             :                sss_strerror(ret));
     755           0 :         goto done;
     756             :     }
     757             : 
     758           0 :     if (_usn_value) {
     759           0 :         *_usn_value = talloc_steal(memctx, usn_value);
     760             :     }
     761             : 
     762           0 :     talloc_steal(memctx, group_attrs);
     763           0 :     ret = EOK;
     764             : 
     765             : done:
     766           0 :     if (ret) {
     767           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     768             :               "Failed to save group [%s]: [%s]\n",
     769             :                group_name ? group_name : "Unknown",
     770             :                sss_strerror(ret));
     771             :     }
     772           0 :     talloc_free(tmpctx);
     773           0 :     return ret;
     774             : }
     775             : 
     776             : static errno_t
     777           0 : are_sids_from_same_dom(const char *sid1, const char *sid2, bool *_result)
     778             : {
     779             :     size_t len_prefix_sid1;
     780             :     size_t len_prefix_sid2;
     781             :     char *rid1, *rid2;
     782             :     bool result;
     783             : 
     784           0 :     rid1 = strrchr(sid1, '-');
     785           0 :     if (rid1 == NULL) {
     786           0 :         return EINVAL;
     787             :     }
     788             : 
     789           0 :     rid2 = strrchr(sid2, '-');
     790           0 :     if (rid2 == NULL) {
     791           0 :         return EINVAL;
     792             :     }
     793             : 
     794           0 :     len_prefix_sid1 = rid1 - sid1;
     795           0 :     len_prefix_sid2 = rid2 - sid2;
     796             : 
     797           0 :     result = (len_prefix_sid1 == len_prefix_sid2) &&
     798           0 :         (strncmp(sid1, sid2, len_prefix_sid1) == 0);
     799             : 
     800           0 :     *_result = result;
     801             : 
     802           0 :     return EOK;
     803             : }
     804             : 
     805             : static errno_t
     806           0 : retain_extern_members(TALLOC_CTX *mem_ctx,
     807             :                       struct sss_domain_info *dom,
     808             :                       const char *group_name,
     809             :                       const char *group_sid,
     810             :                       char ***_userdns,
     811             :                       size_t *_nuserdns)
     812             : {
     813             :     TALLOC_CTX *tmp_ctx;
     814             :     const char **sids, **dns;
     815             :     bool same_domain;
     816             :     errno_t ret;
     817             :     size_t i, n;
     818           0 :     size_t nuserdns = 0;
     819           0 :     const char **userdns = NULL;
     820             : 
     821           0 :     tmp_ctx = talloc_new(NULL);
     822           0 :     if (tmp_ctx == NULL) {
     823           0 :         return ENOMEM;
     824             :     }
     825             : 
     826           0 :     ret = sysdb_get_sids_of_members(tmp_ctx, dom, group_name, &sids, &dns, &n);
     827           0 :     if (ret != EOK) {
     828           0 :         if (ret != ENOENT) {
     829           0 :             DEBUG(SSSDBG_TRACE_ALL,
     830             :                   "get_sids_of_members failed: %d [%s]\n",
     831             :                   ret, sss_strerror(ret));
     832             :         }
     833           0 :         goto done;
     834             :     }
     835             : 
     836           0 :     for (i=0; i < n; i++) {
     837           0 :         ret = are_sids_from_same_dom(group_sid, sids[i], &same_domain);
     838           0 :         if (ret == EOK && !same_domain) {
     839           0 :             DEBUG(SSSDBG_TRACE_ALL, "extern member: %s\n", dns[i]);
     840           0 :             nuserdns++;
     841           0 :             userdns = talloc_realloc(tmp_ctx, userdns, const char*, nuserdns);
     842           0 :             if (userdns == NULL) {
     843           0 :                 ret = ENOMEM;
     844           0 :                 goto done;
     845             :             }
     846           0 :             userdns[nuserdns-1] = talloc_steal(userdns, dns[i]);
     847             :         }
     848             :     }
     849           0 :     *_nuserdns = nuserdns;
     850           0 :     *_userdns = discard_const(talloc_steal(mem_ctx, userdns));
     851           0 :     ret = EOK;
     852             : 
     853             : done:
     854           0 :     talloc_free(tmp_ctx);
     855           0 :     return ret;
     856             : }
     857             : 
     858             : /* ==Save-Group-Memebrs=================================================== */
     859             : 
     860             :     /* FIXME: support non legacy */
     861             :     /* FIXME: support storing additional attributes */
     862             : 
     863           0 : static int sdap_save_grpmem(TALLOC_CTX *memctx,
     864             :                             struct sysdb_ctx *ctx,
     865             :                             struct sdap_options *opts,
     866             :                             struct sss_domain_info *dom,
     867             :                             struct sysdb_attrs *attrs,
     868             :                             hash_table_t *ghosts,
     869             :                             time_t now)
     870             : {
     871             :     struct ldb_message_element *el;
     872           0 :     struct sysdb_attrs *group_attrs = NULL;
     873             :     const char *group_sid;
     874             :     const char *group_name;
     875           0 :     char **userdns = NULL;
     876           0 :     size_t nuserdns = 0;
     877             :     int ret;
     878             : 
     879           0 :     ret = sdap_get_group_primary_name(memctx, opts, attrs, dom, &group_name);
     880           0 :     if (ret != EOK) {
     881           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to get group name\n");
     882           0 :         goto fail;
     883             :     }
     884           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Processing group %s\n", group_name);
     885             : 
     886             :     /* With AD we also want to merge in parent groups of primary GID as they
     887             :      * are reported with tokenGroups, too
     888             :      */
     889           0 :     if (opts->schema_type == SDAP_SCHEMA_AD) {
     890           0 :         ret = sdap_dn_by_primary_gid(memctx, attrs, dom, opts,
     891             :                                      &userdns, &nuserdns);
     892           0 :         if (ret != EOK) {
     893           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
     894             :                   "sdap_dn_by_primary_gid failed: [%d][%s].\n",
     895             :                   ret, strerror(ret));
     896           0 :             goto fail;
     897             :         }
     898             :     }
     899             : 
     900             :     /* This is a temporal solution until the IPA provider is able to
     901             :      * resolve external group membership.
     902             :      * https://fedorahosted.org/sssd/ticket/2522
     903             :      */
     904           0 :     if (opts->schema_type == SDAP_SCHEMA_IPA_V1) {
     905           0 :         ret = sysdb_attrs_get_string(attrs, SYSDB_SID_STR, &group_sid);
     906           0 :         if (ret != EOK) {
     907           0 :             DEBUG(SSSDBG_TRACE_FUNC, "Failed to get group sid\n");
     908           0 :             group_sid = NULL;
     909             :         }
     910             : 
     911           0 :         if (group_sid != NULL) {
     912           0 :             ret = retain_extern_members(memctx, dom, group_name, group_sid,
     913             :                                         &userdns, &nuserdns);
     914           0 :             if (ret != EOK) {
     915           0 :                 DEBUG(SSSDBG_TRACE_INTERNAL,
     916             :                       "retain_extern_members failed: %d:[%s].\n",
     917             :                       ret, sss_strerror(ret));
     918             :             }
     919             :         }
     920             :     }
     921             : 
     922           0 :     ret = sysdb_attrs_get_el(attrs,
     923           0 :                     opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name, &el);
     924           0 :     if (ret != EOK) {
     925           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_attrs_get_el failed: [%d][%s].\n",
     926             :               ret, strerror(ret));
     927           0 :         goto fail;
     928             :     }
     929             : 
     930           0 :     if (el->num_values == 0 && nuserdns == 0) {
     931           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     932             :               "No members for group [%s]\n", group_name);
     933             :     } else {
     934           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     935             :               "Adding member users to group [%s]\n", group_name);
     936             : 
     937           0 :         group_attrs = sysdb_new_attrs(memctx);
     938           0 :         if (!group_attrs) {
     939           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_new_attrs failed\n");
     940           0 :             ret = ENOMEM;
     941           0 :             goto fail;
     942             :         }
     943             : 
     944           0 :         ret = sdap_fill_memberships(opts, group_attrs, ctx, dom, ghosts,
     945           0 :                                     el->values, el->num_values,
     946             :                                     userdns, nuserdns);
     947           0 :         if (ret) {
     948           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     949             :                   "sdap_fill_memberships failed with [%d]: %s\n", ret,
     950             :                    strerror(ret));
     951           0 :             goto fail;
     952             :         }
     953             :     }
     954             : 
     955           0 :     ret = sysdb_store_group(dom, group_name, 0, group_attrs,
     956           0 :                             dom->group_timeout, now);
     957           0 :     if (ret) {
     958           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "sysdb_store_group failed: [%d][%s].\n",
     959             :               ret, strerror(ret));
     960           0 :         goto fail;
     961             :     }
     962             : 
     963           0 :     return EOK;
     964             : 
     965             : fail:
     966           0 :     DEBUG(SSSDBG_OP_FAILURE,
     967             :            "Failed to save members of group %s\n", group_name);
     968           0 :     return ret;
     969             : }
     970             : 
     971             : 
     972             : /* ==Generic-Function-to-save-multiple-groups============================= */
     973             : 
     974           0 : static int sdap_save_groups(TALLOC_CTX *memctx,
     975             :                             struct sysdb_ctx *sysdb,
     976             :                             struct sss_domain_info *dom,
     977             :                             struct sdap_options *opts,
     978             :                             struct sysdb_attrs **groups,
     979             :                             int num_groups,
     980             :                             bool populate_members,
     981             :                             hash_table_t *ghosts,
     982             :                             bool save_orig_member,
     983             :                             char **_usn_value)
     984             : {
     985             :     TALLOC_CTX *tmpctx;
     986           0 :     char *higher_usn = NULL;
     987             :     char *usn_value;
     988             :     bool twopass;
     989           0 :     bool has_nesting = false;
     990             :     int ret;
     991             :     errno_t sret;
     992             :     int i;
     993           0 :     struct sysdb_attrs **saved_groups = NULL;
     994           0 :     int nsaved_groups = 0;
     995             :     time_t now;
     996           0 :     bool in_transaction = false;
     997             : 
     998           0 :     switch (opts->schema_type) {
     999             :     case SDAP_SCHEMA_RFC2307:
    1000           0 :         twopass = false;
    1001           0 :         break;
    1002             : 
    1003             :     case SDAP_SCHEMA_RFC2307BIS:
    1004             :     case SDAP_SCHEMA_IPA_V1:
    1005             :     case SDAP_SCHEMA_AD:
    1006           0 :         twopass = true;
    1007           0 :         has_nesting = true;
    1008           0 :         break;
    1009             : 
    1010             :     default:
    1011           0 :         return EINVAL;
    1012             :     }
    1013             : 
    1014           0 :     tmpctx = talloc_new(memctx);
    1015           0 :     if (!tmpctx) {
    1016           0 :         return ENOMEM;
    1017             :     }
    1018             : 
    1019           0 :     ret = sysdb_transaction_start(sysdb);
    1020           0 :     if (ret) {
    1021           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
    1022           0 :         goto done;
    1023             :     }
    1024           0 :     in_transaction = true;
    1025             : 
    1026           0 :     if (twopass && !populate_members) {
    1027           0 :         saved_groups = talloc_array(tmpctx, struct sysdb_attrs *,
    1028             :                                     num_groups);
    1029           0 :         if (!saved_groups) {
    1030           0 :             ret = ENOMEM;
    1031           0 :             goto done;
    1032             :         }
    1033             :     }
    1034             : 
    1035           0 :     now = time(NULL);
    1036           0 :     for (i = 0; i < num_groups; i++) {
    1037           0 :         usn_value = NULL;
    1038             : 
    1039             :         /* if 2 pass savemembers = false */
    1040           0 :         ret = sdap_save_group(tmpctx, opts, dom, groups[i],
    1041             :                               populate_members,
    1042           0 :                               has_nesting && save_orig_member,
    1043             :                               ghosts, &usn_value, now);
    1044             : 
    1045             :         /* Do not fail completely on errors.
    1046             :          * Just report the failure to save and go on */
    1047           0 :         if (ret) {
    1048           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1049             :                   "Failed to store group %d. Ignoring.\n", i);
    1050             :         } else {
    1051           0 :             DEBUG(SSSDBG_TRACE_ALL, "Group %d processed!\n", i);
    1052           0 :             if (twopass && !populate_members) {
    1053           0 :                 saved_groups[nsaved_groups] = groups[i];
    1054           0 :                 nsaved_groups++;
    1055             :             }
    1056             :         }
    1057             : 
    1058           0 :         if (usn_value) {
    1059           0 :             if (higher_usn) {
    1060           0 :                 if ((strlen(usn_value) > strlen(higher_usn)) ||
    1061           0 :                     (strcmp(usn_value, higher_usn) > 0)) {
    1062           0 :                     talloc_zfree(higher_usn);
    1063           0 :                     higher_usn = usn_value;
    1064             :                 } else {
    1065           0 :                     talloc_zfree(usn_value);
    1066             :                 }
    1067             :             } else {
    1068           0 :                 higher_usn = usn_value;
    1069             :             }
    1070             :         }
    1071             :     }
    1072             : 
    1073           0 :     if (twopass && !populate_members) {
    1074             : 
    1075           0 :         for (i = 0; i < nsaved_groups; i++) {
    1076             : 
    1077           0 :             ret = sdap_save_grpmem(tmpctx, sysdb, opts, dom, saved_groups[i],
    1078             :                                    ghosts, now);
    1079             :             /* Do not fail completely on errors.
    1080             :              * Just report the failure to save and go on */
    1081           0 :             if (ret) {
    1082           0 :                 DEBUG(SSSDBG_OP_FAILURE,
    1083             :                       "Failed to store group %d members.\n", i);
    1084             :             } else {
    1085           0 :                 DEBUG(SSSDBG_TRACE_ALL, "Group %d members processed!\n", i);
    1086             :             }
    1087             :         }
    1088             :     }
    1089             : 
    1090           0 :     ret = sysdb_transaction_commit(sysdb);
    1091           0 :     if (ret) {
    1092           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n");
    1093           0 :         goto done;
    1094             :     }
    1095           0 :     in_transaction = false;
    1096             : 
    1097           0 :     if (_usn_value) {
    1098           0 :         *_usn_value = talloc_steal(memctx, higher_usn);
    1099             :     }
    1100             : 
    1101             : done:
    1102           0 :     if (in_transaction) {
    1103           0 :         sret = sysdb_transaction_cancel(sysdb);
    1104           0 :         if (sret != EOK) {
    1105           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
    1106             :         }
    1107             :     }
    1108           0 :     talloc_zfree(tmpctx);
    1109           0 :     return ret;
    1110             : }
    1111             : 
    1112             : 
    1113             : /* ==Process-Groups======================================================= */
    1114             : 
    1115             : struct sdap_process_group_state {
    1116             :     struct tevent_context *ev;
    1117             :     struct sdap_options *opts;
    1118             :     struct sdap_handle *sh;
    1119             :     struct sss_domain_info *dom;
    1120             :     struct sysdb_ctx *sysdb;
    1121             : 
    1122             :     struct sysdb_attrs *group;
    1123             :     struct ldb_message_element* sysdb_dns;
    1124             :     struct ldb_message_element* ghost_dns;
    1125             :     char **queued_members;
    1126             :     int queue_len;
    1127             :     const char **attrs;
    1128             :     const char *filter;
    1129             :     size_t queue_idx;
    1130             :     size_t count;
    1131             :     size_t check_count;
    1132             : 
    1133             :     bool enumeration;
    1134             : };
    1135             : 
    1136             : #define GROUPMEMBER_REQ_PARALLEL 50
    1137             : static void sdap_process_group_members(struct tevent_req *subreq);
    1138             : 
    1139             : static int sdap_process_group_members_2307bis(struct tevent_req *req,
    1140             :                                    struct sdap_process_group_state *state,
    1141             :                                    struct ldb_message_element *memberel);
    1142             : static int sdap_process_group_members_2307(struct sdap_process_group_state *state,
    1143             :                                    struct ldb_message_element *memberel,
    1144             :                                    struct ldb_message_element *ghostel);
    1145             : 
    1146           0 : static errno_t sdap_process_group_create_dns(TALLOC_CTX *mem_ctx,
    1147             :                                              size_t num_values,
    1148             :                                              struct ldb_message_element **_dns)
    1149             : {
    1150             :     struct ldb_message_element *dns;
    1151             : 
    1152           0 :     dns = talloc(mem_ctx, struct ldb_message_element);
    1153           0 :     if (dns == NULL) {
    1154           0 :         return ENOMEM;
    1155             :     }
    1156             : 
    1157           0 :     dns->num_values = 0;
    1158           0 :     dns->values = talloc_array(dns, struct ldb_val,
    1159             :                                num_values);
    1160           0 :     if (dns->values == NULL) {
    1161           0 :         talloc_zfree(dns);
    1162           0 :         return ENOMEM;
    1163             :     }
    1164             : 
    1165           0 :     *_dns = dns;
    1166             : 
    1167           0 :     return EOK;
    1168             : }
    1169             : 
    1170           0 : struct tevent_req *sdap_process_group_send(TALLOC_CTX *memctx,
    1171             :                                            struct tevent_context *ev,
    1172             :                                            struct sss_domain_info *dom,
    1173             :                                            struct sysdb_ctx *sysdb,
    1174             :                                            struct sdap_options *opts,
    1175             :                                            struct sdap_handle *sh,
    1176             :                                            struct sysdb_attrs *group,
    1177             :                                            bool enumeration)
    1178             : {
    1179             :     struct ldb_message_element *el;
    1180             :     struct ldb_message_element *ghostel;
    1181             :     struct sdap_process_group_state *grp_state;
    1182           0 :     struct tevent_req *req = NULL;
    1183             :     const char **attrs;
    1184             :     char* filter;
    1185             :     int ret;
    1186             : 
    1187           0 :     req = tevent_req_create(memctx, &grp_state,
    1188             :                             struct sdap_process_group_state);
    1189           0 :     if (!req) return NULL;
    1190             : 
    1191           0 :     ret = build_attrs_from_map(grp_state, opts->user_map, opts->user_map_cnt,
    1192             :                                NULL, &attrs, NULL);
    1193           0 :     if (ret) {
    1194           0 :         goto done;
    1195             :     }
    1196             : 
    1197             :     /* FIXME: we ignore nested rfc2307bis groups for now */
    1198           0 :     filter = talloc_asprintf(grp_state, "(objectclass=%s)",
    1199           0 :                              opts->user_map[SDAP_OC_USER].name);
    1200           0 :     if (!filter) {
    1201           0 :         talloc_zfree(req);
    1202           0 :         return NULL;
    1203             :     }
    1204             : 
    1205           0 :     grp_state->ev = ev;
    1206           0 :     grp_state->opts = opts;
    1207           0 :     grp_state->dom = dom;
    1208           0 :     grp_state->sh = sh;
    1209           0 :     grp_state->sysdb = sysdb;
    1210           0 :     grp_state->group =  group;
    1211           0 :     grp_state->check_count = 0;
    1212           0 :     grp_state->queue_idx = 0;
    1213           0 :     grp_state->queued_members = NULL;
    1214           0 :     grp_state->queue_len = 0;
    1215           0 :     grp_state->filter = filter;
    1216           0 :     grp_state->attrs = attrs;
    1217           0 :     grp_state->enumeration = enumeration;
    1218             : 
    1219           0 :     ret = sysdb_attrs_get_el(group,
    1220           0 :                              opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
    1221             :                              &el);
    1222           0 :     if (ret) {
    1223           0 :         goto done;
    1224             :     }
    1225             : 
    1226             :     /* Group without members */
    1227           0 :     if (el->num_values == 0) {
    1228           0 :         DEBUG(SSSDBG_OP_FAILURE, "No Members. Done!\n");
    1229           0 :         ret = EOK;
    1230           0 :         goto done;
    1231             :     }
    1232             : 
    1233           0 :     ret = sysdb_attrs_get_el(group,
    1234             :                              SYSDB_GHOST,
    1235             :                              &ghostel);
    1236           0 :     if (ret) {
    1237           0 :         goto done;
    1238             :     }
    1239             : 
    1240           0 :     if (ghostel->num_values == 0) {
    1241             :         /* Element was probably newly created, look for "member" again */
    1242           0 :         ret = sysdb_attrs_get_el(group,
    1243           0 :                                  opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
    1244             :                                  &el);
    1245           0 :         if (ret != EOK) {
    1246           0 :             goto done;
    1247             :         }
    1248             :     }
    1249             : 
    1250             : 
    1251           0 :     ret = sdap_process_group_create_dns(grp_state, el->num_values,
    1252           0 :                                         &grp_state->sysdb_dns);
    1253           0 :     if (ret != EOK) {
    1254           0 :         goto done;
    1255             :     }
    1256             : 
    1257           0 :     ret = sdap_process_group_create_dns(grp_state, el->num_values,
    1258           0 :                                         &grp_state->ghost_dns);
    1259           0 :     if (ret != EOK) {
    1260           0 :         goto done;
    1261             :     }
    1262             : 
    1263           0 :     switch (opts->schema_type) {
    1264             :         case SDAP_SCHEMA_RFC2307:
    1265           0 :             ret = sdap_process_group_members_2307(grp_state, el, ghostel);
    1266           0 :             break;
    1267             : 
    1268             :         case SDAP_SCHEMA_IPA_V1:
    1269             :         case SDAP_SCHEMA_AD:
    1270             :         case SDAP_SCHEMA_RFC2307BIS:
    1271             :             /* Note that this code branch will be used only if
    1272             :              * ldap_nesting_level = 0 is set in config file
    1273             :              */
    1274           0 :             ret = sdap_process_group_members_2307bis(req, grp_state, el);
    1275           0 :             break;
    1276             : 
    1277             :         default:
    1278           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1279             :                   "Unknown schema type %d\n", opts->schema_type);
    1280           0 :             ret = EINVAL;
    1281           0 :             break;
    1282             :     }
    1283             : 
    1284             : done:
    1285             :     /* We managed to process all the entries */
    1286             :     /* EBUSY means we need to wait for entries in LDAP */
    1287           0 :     if (ret == EOK) {
    1288           0 :         DEBUG(SSSDBG_TRACE_LIBS, "All group members processed\n");
    1289           0 :         tevent_req_done(req);
    1290           0 :         tevent_req_post(req, ev);
    1291             :     }
    1292             : 
    1293           0 :     if (ret != EOK && ret != EBUSY) {
    1294           0 :         tevent_req_error(req, ret);
    1295           0 :         tevent_req_post(req, ev);
    1296             :     }
    1297           0 :     return req;
    1298             : }
    1299             : 
    1300             : static int
    1301           0 : sdap_process_missing_member_2307bis(struct tevent_req *req,
    1302             :                                     char *user_dn,
    1303             :                                     unsigned num_users)
    1304             : {
    1305           0 :     struct sdap_process_group_state *grp_state =
    1306           0 :         tevent_req_data(req, struct sdap_process_group_state);
    1307             :     struct tevent_req *subreq;
    1308             : 
    1309             :     /*
    1310             :      * Issue at most GROUPMEMBER_REQ_PARALLEL LDAP searches at once.
    1311             :      * The rest is sent while the results are being processed.
    1312             :      * We limit the number as of request here, as the Server might
    1313             :      * enforce limits on the number of pending operations per
    1314             :      * connection.
    1315             :      */
    1316           0 :     if (grp_state->check_count > GROUPMEMBER_REQ_PARALLEL) {
    1317           0 :         DEBUG(SSSDBG_TRACE_LIBS, " queueing search for: %s\n", user_dn);
    1318           0 :         if (!grp_state->queued_members) {
    1319           0 :             DEBUG(SSSDBG_TRACE_LIBS,
    1320             :                   "Allocating queue for %zu members\n",
    1321             :                    num_users - grp_state->check_count);
    1322             : 
    1323           0 :             grp_state->queued_members = talloc_array(grp_state, char *,
    1324             :                     num_users - grp_state->check_count + 1);
    1325           0 :             if (!grp_state->queued_members) {
    1326           0 :                 return ENOMEM;
    1327             :             }
    1328             :         }
    1329           0 :         grp_state->queued_members[grp_state->queue_len] = user_dn;
    1330           0 :         grp_state->queue_len++;
    1331             :     } else {
    1332           0 :         subreq = sdap_get_generic_send(grp_state,
    1333             :                                        grp_state->ev,
    1334             :                                        grp_state->opts,
    1335             :                                        grp_state->sh,
    1336             :                                        user_dn,
    1337             :                                        LDAP_SCOPE_BASE,
    1338             :                                        grp_state->filter,
    1339             :                                        grp_state->attrs,
    1340           0 :                                        grp_state->opts->user_map,
    1341           0 :                                        grp_state->opts->user_map_cnt,
    1342           0 :                                        dp_opt_get_int(grp_state->opts->basic,
    1343             :                                                       SDAP_SEARCH_TIMEOUT),
    1344             :                                        false);
    1345           0 :         if (!subreq) {
    1346           0 :             return ENOMEM;
    1347             :         }
    1348           0 :         tevent_req_set_callback(subreq, sdap_process_group_members, req);
    1349             :     }
    1350             : 
    1351           0 :     grp_state->check_count++;
    1352           0 :     return EOK;
    1353             : }
    1354             : 
    1355             : static int
    1356           0 : sdap_process_group_members_2307bis(struct tevent_req *req,
    1357             :                                    struct sdap_process_group_state *state,
    1358             :                                    struct ldb_message_element *memberel)
    1359             : {
    1360             :     char *member_dn;
    1361             :     char *strdn;
    1362             :     int ret;
    1363             :     int i;
    1364             :     int nesting_level;
    1365             :     bool is_group;
    1366             : 
    1367           0 :     nesting_level = dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL);
    1368             : 
    1369           0 :     for (i=0; i < memberel->num_values; i++) {
    1370           0 :         member_dn = (char *)memberel->values[i].data;
    1371             : 
    1372           0 :         ret = sdap_find_entry_by_origDN(state->sysdb_dns->values,
    1373             :                                         state->sysdb,
    1374             :                                         state->dom,
    1375             :                                         member_dn,
    1376             :                                         &strdn,
    1377             :                                         &is_group);
    1378             : 
    1379           0 :         if (ret == EOK) {
    1380           0 :             if (nesting_level == 0 && is_group) {
    1381             :                 /* Ignore group members which are groups themselves. */
    1382           0 :                 continue;
    1383             :             }
    1384             : 
    1385             :             /*
    1386             :              * User already cached in sysdb. Remember the sysdb DN for later
    1387             :              * use by sdap_save_groups()
    1388             :              */
    1389           0 :             DEBUG(SSSDBG_TRACE_LIBS, "sysdbdn: %s\n", strdn);
    1390           0 :             state->sysdb_dns->values[state->sysdb_dns->num_values].data =
    1391             :                 (uint8_t*) strdn;
    1392           0 :             state->sysdb_dns->values[state->sysdb_dns->num_values].length =
    1393           0 :                 strlen(strdn);
    1394           0 :             state->sysdb_dns->num_values++;
    1395           0 :         } else if (ret == ENOENT) {
    1396           0 :             if (!state->enumeration) {
    1397             :                 /* The user is not in sysdb, need to add it
    1398             :                  * We don't need to do this if we're in an enumeration,
    1399             :                  * because all real members should all be populated
    1400             :                  * already by the first pass of the enumeration.
    1401             :                  * Also, we don't want to be holding the sysdb
    1402             :                  * transaction while we're performing LDAP lookups.
    1403             :                  */
    1404           0 :                 DEBUG(SSSDBG_TRACE_LIBS,
    1405             :                       "Searching LDAP for missing user entry\n");
    1406           0 :                 ret = sdap_process_missing_member_2307bis(req,
    1407             :                                                           member_dn,
    1408             :                                                           memberel->num_values);
    1409           0 :                 if (ret != EOK) {
    1410           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
    1411             :                           "Error processing missing member #%d (%s):\n",
    1412             :                               i, member_dn);
    1413           0 :                     return ret;
    1414             :                 }
    1415             :             }
    1416             :         } else {
    1417           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1418             :                   "Error checking cache for member #%d (%s):\n",
    1419             :                        i, (char *)memberel->values[i].data);
    1420           0 :             return ret;
    1421             :         }
    1422             :     }
    1423             : 
    1424           0 :     if (state->queue_len > 0) {
    1425           0 :         state->queued_members[state->queue_len]=NULL;
    1426             :     }
    1427             : 
    1428           0 :     if (state->check_count == 0) {
    1429             :         /*
    1430             :          * All group members are already cached in sysdb, we are done
    1431             :          * with this group. To avoid redundant sysdb lookups, populate the
    1432             :          * "member" attribute of the group entry with the sysdb DNs of
    1433             :          * the members.
    1434             :          */
    1435           0 :         ret = EOK;
    1436           0 :         memberel->values = talloc_steal(state->group, state->sysdb_dns->values);
    1437           0 :         memberel->num_values = state->sysdb_dns->num_values;
    1438             :     } else {
    1439           0 :         state->count = state->check_count;
    1440           0 :         ret = EBUSY;
    1441             :     }
    1442             : 
    1443           0 :     return ret;
    1444             : }
    1445             : 
    1446             : static int
    1447           0 : sdap_add_group_member_2307(struct ldb_message_element *sysdb_dns,
    1448             :                            const char *username)
    1449             : {
    1450           0 :     sysdb_dns->values[sysdb_dns->num_values].data =
    1451           0 :             (uint8_t *) talloc_strdup(sysdb_dns->values, username);
    1452           0 :     if (sysdb_dns->values[sysdb_dns->num_values].data == NULL) {
    1453           0 :         return ENOMEM;
    1454             :     }
    1455           0 :     sysdb_dns->values[sysdb_dns->num_values].length =
    1456           0 :             strlen(username);
    1457           0 :     sysdb_dns->num_values++;
    1458             : 
    1459           0 :     return EOK;
    1460             : }
    1461             : 
    1462             : static int
    1463           0 : sdap_process_missing_member_2307(struct sdap_process_group_state *state,
    1464             :                                  char *member_name)
    1465             : {
    1466             :     int ret;
    1467             :     TALLOC_CTX *tmp_ctx;
    1468             :     const char *filter;
    1469             :     const char *username;
    1470             :     const char *user_dn;
    1471             :     size_t count;
    1472           0 :     struct ldb_message **msgs = NULL;
    1473             :     static const char *attrs[] = { SYSDB_NAME, NULL };
    1474             : 
    1475           0 :     tmp_ctx = talloc_new(NULL);
    1476           0 :     if (!tmp_ctx) return ENOMEM;
    1477             : 
    1478             :     /* Check for the alias in the sysdb */
    1479           0 :     filter = talloc_asprintf(tmp_ctx, "(%s=%s)", SYSDB_NAME_ALIAS, member_name);
    1480           0 :     if (!filter) {
    1481           0 :         ret = ENOMEM;
    1482           0 :         goto done;
    1483             :     }
    1484             : 
    1485           0 :     ret = sysdb_search_users(tmp_ctx, state->dom, filter,
    1486             :                              attrs, &count, &msgs);
    1487           0 :     if (ret == EOK && count > 0) {
    1488             :         /* Entry exists but the group references it with an alias. */
    1489             : 
    1490           0 :         if (count != 1) {
    1491           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1492             :                   "More than one entry with this alias?\n");
    1493           0 :             ret = EIO;
    1494           0 :             goto done;
    1495             :         }
    1496             : 
    1497             :         /* fill username with primary name */
    1498           0 :         username = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
    1499           0 :         if (username == NULL) {
    1500           0 :             ret = EINVAL;
    1501           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Inconsistent sysdb: user "
    1502             :                                          "without primary name?\n");
    1503           0 :             goto done;
    1504             :         }
    1505           0 :         user_dn = sysdb_user_strdn(tmp_ctx, state->dom->name, username);
    1506           0 :         if (user_dn == NULL) {
    1507           0 :             return ENOMEM;
    1508             :         }
    1509             : 
    1510           0 :         ret = sdap_add_group_member_2307(state->sysdb_dns, user_dn);
    1511           0 :         if (ret != EOK) {
    1512           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not add group member %s\n", username);
    1513             :         }
    1514           0 :     } else if (ret == ENOENT || count == 0) {
    1515             :         /* The entry really does not exist, add a ghost */
    1516           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Adding a ghost entry\n");
    1517           0 :         ret = sdap_add_group_member_2307(state->ghost_dns, member_name);
    1518           0 :         if (ret != EOK) {
    1519           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not add group member %s\n", member_name);
    1520             :         }
    1521             :     } else {
    1522           0 :         ret = EIO;
    1523             :     }
    1524             : 
    1525             : done:
    1526           0 :     talloc_free(tmp_ctx);
    1527           0 :     return ret;
    1528             : }
    1529             : 
    1530             : static int
    1531           0 : sdap_process_group_members_2307(struct sdap_process_group_state *state,
    1532             :                                 struct ldb_message_element *memberel,
    1533             :                                 struct ldb_message_element *ghostel)
    1534             : {
    1535             :     struct ldb_message *msg;
    1536             :     char *member_name;
    1537             :     char *userdn;
    1538             :     int ret;
    1539             :     int i;
    1540             : 
    1541           0 :     for (i=0; i < memberel->num_values; i++) {
    1542           0 :         member_name = (char *)memberel->values[i].data;
    1543             : 
    1544             :         /* We need to skip over zero-length usernames */
    1545           0 :         if (member_name[0] == '\0') continue;
    1546             : 
    1547           0 :         ret = sysdb_search_user_by_name(state, state->dom, member_name,
    1548             :                                         NULL, &msg);
    1549           0 :         if (ret == EOK) {
    1550             :             /*
    1551             :              * User already cached in sysdb. Remember the sysdb DN for later
    1552             :              * use by sdap_save_groups()
    1553             :              */
    1554           0 :             DEBUG(SSSDBG_TRACE_LIBS,
    1555             :                   "Member already cached in sysdb: %s\n", member_name);
    1556             : 
    1557           0 :             userdn = sysdb_user_strdn(state->sysdb_dns, state->dom->name, member_name);
    1558           0 :             if (userdn == NULL) {
    1559           0 :                 return ENOMEM;
    1560             :             }
    1561             : 
    1562           0 :             ret = sdap_add_group_member_2307(state->sysdb_dns, userdn);
    1563           0 :             if (ret != EOK) {
    1564           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    1565             :                       "Could not add member %s into sysdb\n", member_name);
    1566           0 :                 goto done;
    1567             :             }
    1568           0 :         } else if (ret == ENOENT) {
    1569             :             /* The user is not in sysdb, need to add it */
    1570           0 :             DEBUG(SSSDBG_TRACE_LIBS, "member #%d (%s): not found in sysdb\n",
    1571             :                        i, member_name);
    1572             : 
    1573           0 :             ret = sdap_process_missing_member_2307(state, member_name);
    1574           0 :             if (ret != EOK) {
    1575           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    1576             :                       "Error processing missing member #%d (%s):\n",
    1577             :                           i, member_name);
    1578           0 :                 goto done;
    1579             :             }
    1580             :         } else {
    1581           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1582             :                   "Error checking cache for member #%d (%s):\n",
    1583             :                        i, (char *) memberel->values[i].data);
    1584           0 :             goto done;
    1585             :         }
    1586             :     }
    1587             : 
    1588           0 :     ret = EOK;
    1589           0 :     talloc_free(memberel->values);
    1590           0 :     memberel->values = talloc_steal(state->group, state->sysdb_dns->values);
    1591           0 :     memberel->num_values = state->sysdb_dns->num_values;
    1592           0 :     talloc_free(ghostel->values);
    1593           0 :     ghostel->values = talloc_steal(state->group, state->ghost_dns->values);
    1594           0 :     ghostel->num_values = state->ghost_dns->num_values;
    1595             : 
    1596             : done:
    1597           0 :     return ret;
    1598             : }
    1599             : 
    1600           0 : static void sdap_process_group_members(struct tevent_req *subreq)
    1601             : {
    1602             :     struct sysdb_attrs **usr_attrs;
    1603             :     size_t count;
    1604             :     int ret;
    1605           0 :     struct tevent_req *req =
    1606           0 :                         tevent_req_callback_data(subreq, struct tevent_req);
    1607           0 :     struct sdap_process_group_state *state =
    1608           0 :                         tevent_req_data(req, struct sdap_process_group_state);
    1609             :     struct ldb_message_element *el;
    1610             :     uint8_t* name_string;
    1611             : 
    1612           0 :     state->check_count--;
    1613           0 :     DEBUG(SSSDBG_TRACE_ALL, "Members remaining: %zu\n", state->check_count);
    1614             : 
    1615           0 :     ret = sdap_get_generic_recv(subreq, state, &count, &usr_attrs);
    1616           0 :     talloc_zfree(subreq);
    1617           0 :     if (ret) {
    1618           0 :         goto next;
    1619             :     }
    1620           0 :     if (count != 1) {
    1621           0 :         ret = EINVAL;
    1622           0 :         DEBUG(SSSDBG_TRACE_LIBS,
    1623             :               "Expected one user entry and got %zu\n", count);
    1624           0 :         goto next;
    1625             :     }
    1626           0 :     ret = sysdb_attrs_get_el(usr_attrs[0],
    1627           0 :             state->opts->user_map[SDAP_AT_USER_NAME].sys_name, &el);
    1628           0 :     if (el->num_values == 0) {
    1629           0 :         ret = EINVAL;
    1630             :     }
    1631           0 :     if (ret) {
    1632           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to get the member's name\n");
    1633           0 :         goto next;
    1634             :     }
    1635             : 
    1636           0 :     name_string = el[0].values[0].data;
    1637           0 :     state->ghost_dns->values[state->ghost_dns->num_values].data =
    1638           0 :             talloc_steal(state->ghost_dns->values, name_string);
    1639           0 :     state->ghost_dns->values[state->ghost_dns->num_values].length =
    1640           0 :             strlen((char *)name_string);
    1641           0 :     state->ghost_dns->num_values++;
    1642             : 
    1643             : next:
    1644           0 :     if (ret) {
    1645           0 :         DEBUG(SSSDBG_TRACE_FUNC,
    1646             :               "Error reading group member[%d]: %s. Skipping\n",
    1647             :                ret, strerror(ret));
    1648           0 :         state->count--;
    1649             :     }
    1650             :     /* Are there more searches for uncached users to submit ? */
    1651           0 :     if (state->queued_members && state->queued_members[state->queue_idx]) {
    1652           0 :         subreq = sdap_get_generic_send(state,
    1653             :                                        state->ev, state->opts, state->sh,
    1654           0 :                                        state->queued_members[state->queue_idx],
    1655             :                                        LDAP_SCOPE_BASE,
    1656             :                                        state->filter,
    1657             :                                        state->attrs,
    1658           0 :                                        state->opts->user_map,
    1659           0 :                                        state->opts->user_map_cnt,
    1660           0 :                                        dp_opt_get_int(state->opts->basic,
    1661             :                                                       SDAP_SEARCH_TIMEOUT),
    1662             :                                        false);
    1663           0 :         if (!subreq) {
    1664           0 :             tevent_req_error(req, ENOMEM);
    1665           0 :             return;
    1666             :         }
    1667             : 
    1668           0 :         tevent_req_set_callback(subreq,
    1669             :                                 sdap_process_group_members, req);
    1670           0 :         state->queue_idx++;
    1671             :     }
    1672             : 
    1673           0 :     if (state->check_count == 0) {
    1674             :         /*
    1675             :          * To avoid redundant sysdb lookups, populate the "member" attribute
    1676             :          * of the group entry with the sysdb DNs of the members.
    1677             :          */
    1678           0 :         ret = sysdb_attrs_get_el(state->group,
    1679           0 :                         state->opts->group_map[SDAP_AT_GROUP_MEMBER].sys_name,
    1680             :                         &el);
    1681           0 :         if (ret != EOK) {
    1682           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1683             :                   "Failed to get the group member attribute [%d]: %s\n",
    1684             :                   ret, strerror(ret));
    1685           0 :             tevent_req_error(req, ret);
    1686           0 :             return;
    1687             :         }
    1688           0 :         el->values = talloc_steal(state->group, state->sysdb_dns->values);
    1689           0 :         el->num_values = state->sysdb_dns->num_values;
    1690             : 
    1691           0 :         ret = sysdb_attrs_get_el(state->group, SYSDB_GHOST, &el);
    1692           0 :         if (ret != EOK) {
    1693           0 :             tevent_req_error(req, ret);
    1694           0 :             return;
    1695             :         }
    1696           0 :         el->values = talloc_steal(state->group, state->ghost_dns->values);
    1697           0 :         el->num_values = state->ghost_dns->num_values;
    1698           0 :         DEBUG(SSSDBG_TRACE_ALL, "Processed Group - Done\n");
    1699           0 :         tevent_req_done(req);
    1700             :     }
    1701             : }
    1702             : 
    1703           0 : static int sdap_process_group_recv(struct tevent_req *req)
    1704             : {
    1705           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    1706             : 
    1707           0 :     return EOK;
    1708             : }
    1709             : 
    1710             : 
    1711             : /* ==Search-Groups-with-filter============================================ */
    1712             : 
    1713             : struct sdap_get_groups_state {
    1714             :     struct tevent_context *ev;
    1715             :     struct sdap_options *opts;
    1716             :     struct sdap_handle *sh;
    1717             :     struct sss_domain_info *dom;
    1718             :     struct sdap_domain *sdom;
    1719             :     struct sysdb_ctx *sysdb;
    1720             :     const char **attrs;
    1721             :     const char *base_filter;
    1722             :     char *filter;
    1723             :     int timeout;
    1724             :     enum sdap_entry_lookup_type lookup_type;
    1725             :     bool no_members;
    1726             : 
    1727             :     char *higher_usn;
    1728             :     struct sysdb_attrs **groups;
    1729             :     size_t count;
    1730             :     size_t check_count;
    1731             : 
    1732             :     hash_table_t *user_hash;
    1733             :     hash_table_t *group_hash;
    1734             : 
    1735             :     size_t base_iter;
    1736             :     struct sdap_search_base **search_bases;
    1737             : 
    1738             :     struct sdap_handle *ldap_sh;
    1739             :     struct sdap_id_op *op;
    1740             : };
    1741             : 
    1742             : static errno_t sdap_get_groups_next_base(struct tevent_req *req);
    1743             : static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq);
    1744             : static void sdap_get_groups_process(struct tevent_req *subreq);
    1745             : static void sdap_get_groups_done(struct tevent_req *subreq);
    1746             : 
    1747           0 : struct tevent_req *sdap_get_groups_send(TALLOC_CTX *memctx,
    1748             :                                        struct tevent_context *ev,
    1749             :                                        struct sdap_domain *sdom,
    1750             :                                        struct sdap_options *opts,
    1751             :                                        struct sdap_handle *sh,
    1752             :                                        const char **attrs,
    1753             :                                        const char *filter,
    1754             :                                        int timeout,
    1755             :                                        enum sdap_entry_lookup_type lookup_type,
    1756             :                                        bool no_members)
    1757             : {
    1758             :     errno_t ret;
    1759             :     struct tevent_req *req;
    1760             :     struct tevent_req *subreq;
    1761             :     struct sdap_get_groups_state *state;
    1762             :     struct ad_id_ctx *subdom_id_ctx;
    1763             : 
    1764           0 :     req = tevent_req_create(memctx, &state, struct sdap_get_groups_state);
    1765           0 :     if (!req) return NULL;
    1766             : 
    1767           0 :     state->ev = ev;
    1768           0 :     state->opts = opts;
    1769           0 :     state->sdom = sdom;
    1770           0 :     state->dom = sdom->dom;
    1771           0 :     state->sh = sh;
    1772           0 :     state->sysdb = sdom->dom->sysdb;
    1773           0 :     state->attrs = attrs;
    1774           0 :     state->higher_usn = NULL;
    1775           0 :     state->groups =  NULL;
    1776           0 :     state->count = 0;
    1777           0 :     state->timeout = timeout;
    1778           0 :     state->lookup_type = lookup_type;
    1779           0 :     state->no_members = no_members;
    1780           0 :     state->base_filter = filter;
    1781           0 :     state->base_iter = 0;
    1782           0 :     state->search_bases = sdom->group_search_bases;
    1783             : 
    1784           0 :     if (!state->search_bases) {
    1785           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1786             :               "Group lookup request without a search base\n");
    1787           0 :         ret = EINVAL;
    1788           0 :         goto done;
    1789             :     }
    1790             : 
    1791             :     /* With AD by default the Global Catalog is used for lookup. But the GC
    1792             :      * group object might not have full group membership data. To make sure we
    1793             :      * connect to an LDAP server of the group's domain. */
    1794           0 :     if (state->opts->schema_type == SDAP_SCHEMA_AD && sdom->pvt != NULL) {
    1795           0 :         subdom_id_ctx = talloc_get_type(sdom->pvt, struct ad_id_ctx);
    1796           0 :         state->op = sdap_id_op_create(state, subdom_id_ctx->ldap_ctx->conn_cache);
    1797           0 :         if (!state->op) {
    1798           0 :             DEBUG(SSSDBG_OP_FAILURE, "sdap_id_op_create failed\n");
    1799           0 :             ret = ENOMEM;
    1800           0 :             goto done;
    1801             :         }
    1802             : 
    1803           0 :         subreq = sdap_id_op_connect_send(state->op, state, &ret);
    1804           0 :         if (subreq == NULL) {
    1805           0 :             ret = ENOMEM;
    1806           0 :             goto done;
    1807             :         }
    1808             : 
    1809           0 :         tevent_req_set_callback(subreq,
    1810             :                                 sdap_get_groups_ldap_connect_done,
    1811             :                                 req);
    1812           0 :         return req;
    1813             :     }
    1814             : 
    1815           0 :     ret = sdap_get_groups_next_base(req);
    1816             : 
    1817             : done:
    1818           0 :     if (ret != EOK) {
    1819           0 :         tevent_req_error(req, ret);
    1820           0 :         tevent_req_post(req, ev);
    1821             :     }
    1822             : 
    1823           0 :     return req;
    1824             : }
    1825             : 
    1826           0 : static void sdap_get_groups_ldap_connect_done(struct tevent_req *subreq)
    1827             : {
    1828             :     struct tevent_req *req;
    1829             :     struct sdap_get_groups_state *state;
    1830             :     int ret;
    1831             :     int dp_error;
    1832             : 
    1833           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
    1834           0 :     state = tevent_req_data(req, struct sdap_get_groups_state);
    1835             : 
    1836           0 :     ret = sdap_id_op_connect_recv(subreq, &dp_error);
    1837           0 :     talloc_zfree(subreq);
    1838             : 
    1839           0 :     if (ret != EOK) {
    1840           0 :         tevent_req_error(req, ret);
    1841           0 :         return;
    1842             :     }
    1843             : 
    1844           0 :     state->ldap_sh = sdap_id_op_handle(state->op);
    1845             : 
    1846           0 :     ret = sdap_get_groups_next_base(req);
    1847           0 :     if (ret != EOK) {
    1848           0 :         tevent_req_error(req, ret);
    1849             :     }
    1850             : 
    1851           0 :     return;
    1852             : }
    1853             : 
    1854           0 : static errno_t sdap_get_groups_next_base(struct tevent_req *req)
    1855             : {
    1856             :     struct tevent_req *subreq;
    1857             :     struct sdap_get_groups_state *state;
    1858           0 :     bool need_paging = false;
    1859           0 :     int sizelimit = 0;
    1860             : 
    1861           0 :     state = tevent_req_data(req, struct sdap_get_groups_state);
    1862             : 
    1863           0 :     talloc_zfree(state->filter);
    1864           0 :     state->filter = sdap_get_id_specific_filter(state,
    1865             :                         state->base_filter,
    1866           0 :                         state->search_bases[state->base_iter]->filter);
    1867           0 :     if (!state->filter) {
    1868           0 :         return ENOMEM;
    1869             :     }
    1870             : 
    1871           0 :     DEBUG(SSSDBG_TRACE_FUNC,
    1872             :           "Searching for groups with base [%s]\n",
    1873             :            state->search_bases[state->base_iter]->basedn);
    1874             : 
    1875           0 :     switch (state->lookup_type) {
    1876             :     case SDAP_LOOKUP_SINGLE:
    1877           0 :         break;
    1878             :     /* Only requests that can return multiple entries should require
    1879             :      * the paging control
    1880             :      */
    1881             :     case SDAP_LOOKUP_WILDCARD:
    1882           0 :         sizelimit = dp_opt_get_int(state->opts->basic, SDAP_WILDCARD_LIMIT);
    1883           0 :         need_paging = true;
    1884           0 :         break;
    1885             :     case SDAP_LOOKUP_ENUMERATE:
    1886           0 :         need_paging = true;
    1887           0 :         break;
    1888             :     }
    1889             : 
    1890           0 :     subreq = sdap_get_and_parse_generic_send(
    1891             :             state, state->ev, state->opts,
    1892           0 :             state->ldap_sh != NULL ? state->ldap_sh : state->sh,
    1893           0 :             state->search_bases[state->base_iter]->basedn,
    1894           0 :             state->search_bases[state->base_iter]->scope,
    1895           0 :             state->filter, state->attrs,
    1896           0 :             state->opts->group_map, SDAP_OPTS_GROUP,
    1897             :             0, NULL, NULL, sizelimit, state->timeout,
    1898             :             need_paging);
    1899           0 :     if (!subreq) {
    1900           0 :         return ENOMEM;
    1901             :     }
    1902           0 :     tevent_req_set_callback(subreq, sdap_get_groups_process, req);
    1903             : 
    1904           0 :     return EOK;
    1905             : }
    1906             : 
    1907             : static void sdap_nested_done(struct tevent_req *req);
    1908             : static void sdap_search_group_copy_batch(struct sdap_get_groups_state *state,
    1909             :                                          struct sysdb_attrs **groups,
    1910             :                                          size_t count);
    1911             : static void sdap_ad_match_rule_members_process(struct tevent_req *subreq);
    1912             : 
    1913           0 : static void sdap_get_groups_process(struct tevent_req *subreq)
    1914             : {
    1915           0 :     struct tevent_req *req =
    1916           0 :                         tevent_req_callback_data(subreq, struct tevent_req);
    1917           0 :     struct sdap_get_groups_state *state =
    1918           0 :                         tevent_req_data(req, struct sdap_get_groups_state);
    1919             :     int ret;
    1920             :     int i;
    1921           0 :     bool next_base = false;
    1922             :     size_t count;
    1923             :     struct sysdb_attrs **groups;
    1924             :     char **groupnamelist;
    1925             : 
    1926           0 :     ret = sdap_get_and_parse_generic_recv(subreq, state,
    1927             :                                           &count, &groups);
    1928           0 :     talloc_zfree(subreq);
    1929           0 :     if (ret) {
    1930           0 :         tevent_req_error(req, ret);
    1931           0 :         return;
    1932             :     }
    1933             : 
    1934           0 :     DEBUG(SSSDBG_TRACE_FUNC,
    1935             :           "Search for groups, returned %zu results.\n", count);
    1936             : 
    1937           0 :     if (state->lookup_type == SDAP_LOOKUP_WILDCARD || \
    1938           0 :             state->lookup_type == SDAP_LOOKUP_ENUMERATE || \
    1939           0 :         count == 0) {
    1940             :         /* No users found in this search or looking up multiple entries */
    1941           0 :         next_base = true;
    1942             :     }
    1943             : 
    1944             :     /* Add this batch of groups to the list */
    1945           0 :     if (count > 0) {
    1946           0 :         state->groups =
    1947           0 :                 talloc_realloc(state,
    1948             :                                state->groups,
    1949             :                                struct sysdb_attrs *,
    1950             :                                state->count + count + 1);
    1951           0 :         if (!state->groups) {
    1952           0 :             tevent_req_error(req, ENOMEM);
    1953           0 :             return;
    1954             :         }
    1955             : 
    1956           0 :         sdap_search_group_copy_batch(state, groups, count);
    1957             :     }
    1958             : 
    1959           0 :     if (next_base) {
    1960           0 :         state->base_iter++;
    1961           0 :         if (state->search_bases[state->base_iter]) {
    1962             :             /* There are more search bases to try */
    1963           0 :             ret = sdap_get_groups_next_base(req);
    1964           0 :             if (ret != EOK) {
    1965           0 :                 tevent_req_error(req, ret);
    1966             :             }
    1967           0 :             return;
    1968             :         }
    1969             :     }
    1970             : 
    1971             :     /* No more search bases
    1972             :      * Return ENOENT if no groups were found
    1973             :      */
    1974           0 :     if (state->count == 0) {
    1975           0 :         tevent_req_error(req, ENOENT);
    1976           0 :         return;
    1977             :     }
    1978             : 
    1979           0 :     if (state->no_members) {
    1980           0 :         ret = sysdb_attrs_primary_name_list(state->sysdb, state,
    1981             :                                 state->groups, state->count,
    1982           0 :                                 state->opts->group_map[SDAP_AT_GROUP_NAME].name,
    1983             :                                 &groupnamelist);
    1984           0 :         if (ret != EOK) {
    1985           0 :             DEBUG(SSSDBG_OP_FAILURE,
    1986             :                   "sysdb_attrs_primary_name_list failed.\n");
    1987           0 :             tevent_req_error(req, ret);
    1988           0 :             return;
    1989             :         }
    1990             : 
    1991           0 :         ret = sdap_add_incomplete_groups(state->sysdb, state->dom, state->opts,
    1992             :                                          groupnamelist, state->groups,
    1993           0 :                                          state->count);
    1994           0 :         if (ret == EOK) {
    1995           0 :             DEBUG(SSSDBG_TRACE_LIBS,
    1996             :                   "Writing only group data without members was successful.\n");
    1997           0 :             tevent_req_done(req);
    1998             :         } else {
    1999           0 :             DEBUG(SSSDBG_OP_FAILURE, "sdap_add_incomplete_groups failed.\n");
    2000           0 :             tevent_req_error(req, ret);
    2001             :         }
    2002           0 :         return;
    2003             :     }
    2004             : 
    2005             :     /* Check whether we need to do nested searches
    2006             :      * for RFC2307bis/FreeIPA/ActiveDirectory
    2007             :      * We don't need to do this for enumeration,
    2008             :      * because all groups will be picked up anyway.
    2009             :      *
    2010             :      * We can also skip this if we're using the
    2011             :      * LDAP_MATCHING_RULE_IN_CHAIN available in
    2012             :      * AD 2008 and later
    2013             :      */
    2014           0 :     if (state->lookup_type == SDAP_LOOKUP_SINGLE) {
    2015           0 :         if ((state->opts->schema_type != SDAP_SCHEMA_RFC2307)
    2016           0 :                 && (dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0)
    2017           0 :                 && !dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_GROUPS)) {
    2018           0 :             subreq = sdap_nested_group_send(state, state->ev, state->sdom,
    2019             :                                             state->opts, state->sh,
    2020           0 :                                             state->groups[0]);
    2021           0 :             if (!subreq) {
    2022           0 :                 tevent_req_error(req, EIO);
    2023           0 :                 return;
    2024             :             }
    2025             : 
    2026           0 :             tevent_req_set_callback(subreq, sdap_nested_done, req);
    2027           0 :             return;
    2028             :         }
    2029             :     }
    2030             : 
    2031             :     /* We have all of the groups. Save them to the sysdb */
    2032           0 :     state->check_count = state->count;
    2033             : 
    2034             :     /* If we're using LDAP_MATCHING_RULE_IN_CHAIN, start a subreq to
    2035             :      * retrieve the members so we can save them in a single step.
    2036             :      */
    2037           0 :     if (state->lookup_type == SDAP_LOOKUP_SINGLE
    2038           0 :             && (state->opts->schema_type != SDAP_SCHEMA_RFC2307)
    2039           0 :             && state->opts->support_matching_rule
    2040           0 :             && dp_opt_get_bool(state->opts->basic, SDAP_AD_MATCHING_RULE_GROUPS)) {
    2041           0 :         subreq = sdap_get_ad_match_rule_members_send(
    2042             :                 state, state->ev, state->opts, state->sh,
    2043           0 :                 state->groups[0], state->timeout);
    2044           0 :         if (!subreq) {
    2045           0 :             tevent_req_error(req, ENOMEM);
    2046           0 :             return;
    2047             :         }
    2048           0 :         tevent_req_set_callback(subreq,
    2049             :                                 sdap_ad_match_rule_members_process,
    2050             :                                 req);
    2051           0 :         return;
    2052             :     }
    2053             : 
    2054           0 :     ret = sysdb_transaction_start(state->sysdb);
    2055           0 :     if (ret != EOK) {
    2056           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to start transaction\n");
    2057           0 :         tevent_req_error(req, ret);
    2058           0 :         return;
    2059             :     }
    2060             : 
    2061           0 :     if ((state->lookup_type == SDAP_LOOKUP_ENUMERATE
    2062           0 :                 || state->lookup_type == SDAP_LOOKUP_WILDCARD)
    2063           0 :             && state->opts->schema_type != SDAP_SCHEMA_RFC2307
    2064           0 :             && dp_opt_get_int(state->opts->basic, SDAP_NESTING_LEVEL) != 0) {
    2065           0 :         DEBUG(SSSDBG_TRACE_ALL, "Saving groups without members first "
    2066             :                   "to allow unrolling of nested groups.\n");
    2067           0 :         ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
    2068           0 :                                state->groups, state->count, false,
    2069             :                                NULL, true, NULL);
    2070           0 :         if (ret) {
    2071           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to store groups.\n");
    2072           0 :             tevent_req_error(req, ret);
    2073           0 :             return;
    2074             :         }
    2075             :     }
    2076             : 
    2077           0 :     for (i = 0; i < state->count; i++) {
    2078           0 :         subreq = sdap_process_group_send(state, state->ev, state->dom,
    2079             :                                          state->sysdb, state->opts,
    2080           0 :                                          state->sh, state->groups[i],
    2081           0 :                                          state->lookup_type == SDAP_LOOKUP_ENUMERATE);
    2082             : 
    2083           0 :         if (!subreq) {
    2084           0 :             tevent_req_error(req, ENOMEM);
    2085           0 :             return;
    2086             :         }
    2087           0 :         tevent_req_set_callback(subreq, sdap_get_groups_done, req);
    2088             :     }
    2089             : }
    2090             : 
    2091           0 : static void sdap_search_group_copy_batch(struct sdap_get_groups_state *state,
    2092             :                                          struct sysdb_attrs **groups,
    2093             :                                          size_t count)
    2094             : {
    2095             :     size_t copied;
    2096             :     bool filter;
    2097             : 
    2098             :     /* Always copy all objects for wildcard lookups. */
    2099           0 :     filter = state->lookup_type == SDAP_LOOKUP_SINGLE ? true : false;
    2100             : 
    2101           0 :     copied = sdap_steal_objects_in_dom(state->opts,
    2102             :                                        state->groups,
    2103             :                                        state->count,
    2104             :                                        state->dom,
    2105             :                                        groups, count, filter);
    2106             : 
    2107           0 :     state->count += copied;
    2108           0 :     state->groups[state->count] = NULL;
    2109           0 : }
    2110             : 
    2111           0 : static void sdap_get_groups_done(struct tevent_req *subreq)
    2112             : {
    2113           0 :     struct tevent_req *req =
    2114           0 :                         tevent_req_callback_data(subreq, struct tevent_req);
    2115           0 :     struct sdap_get_groups_state *state =
    2116           0 :                         tevent_req_data(req, struct sdap_get_groups_state);
    2117             : 
    2118             :     int ret;
    2119             :     errno_t sysret;
    2120             : 
    2121           0 :     ret = sdap_process_group_recv(subreq);
    2122           0 :     talloc_zfree(subreq);
    2123           0 :     if (ret) {
    2124           0 :         sysret = sysdb_transaction_cancel(state->sysdb);
    2125           0 :         if (sysret != EOK) {
    2126           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Could not cancel sysdb transaction\n");
    2127             :         }
    2128           0 :         tevent_req_error(req, ret);
    2129           0 :         return;
    2130             :     }
    2131             : 
    2132           0 :     state->check_count--;
    2133           0 :     DEBUG(SSSDBG_TRACE_ALL, "Groups remaining: %zu\n", state->check_count);
    2134             : 
    2135             : 
    2136           0 :     if (state->check_count == 0) {
    2137           0 :         DEBUG(SSSDBG_TRACE_ALL, "All groups processed\n");
    2138             : 
    2139             :         /* If ignore_group_members is set for the domain, don't update
    2140             :          * group memberships in the cache.
    2141             :          *
    2142             :          * If enumeration is on, don't overwrite orig_members as they've been
    2143             :          * saved earlier.
    2144             :          */
    2145           0 :         ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
    2146           0 :                                state->groups, state->count,
    2147           0 :                                !state->dom->ignore_group_members, NULL,
    2148           0 :                                state->lookup_type == SDAP_LOOKUP_SINGLE,
    2149             :                                &state->higher_usn);
    2150           0 :         if (ret) {
    2151           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to store groups.\n");
    2152           0 :             tevent_req_error(req, ret);
    2153           0 :             return;
    2154             :         }
    2155           0 :         DEBUG(SSSDBG_TRACE_ALL, "Saving %zu Groups - Done\n", state->count);
    2156           0 :         sysret = sysdb_transaction_commit(state->sysdb);
    2157           0 :         if (sysret != EOK) {
    2158           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Couldn't commit transaction\n");
    2159           0 :             tevent_req_error(req, sysret);
    2160             :         } else {
    2161           0 :             tevent_req_done(req);
    2162             :         }
    2163             :     }
    2164             : }
    2165             : 
    2166             : static errno_t sdap_nested_group_populate_users(TALLOC_CTX *mem_ctx,
    2167             :                                                 struct sysdb_ctx *sysdb,
    2168             :                                                 struct sss_domain_info *domain,
    2169             :                                                 struct sdap_options *opts,
    2170             :                                                 struct sysdb_attrs **users,
    2171             :                                                 int num_users,
    2172             :                                                 hash_table_t **_ghosts);
    2173             : 
    2174           0 : static void sdap_ad_match_rule_members_process(struct tevent_req *subreq)
    2175             : {
    2176             :     errno_t ret;
    2177           0 :     TALLOC_CTX *tmp_ctx = NULL;
    2178           0 :     struct tevent_req *req =
    2179           0 :             tevent_req_callback_data(subreq, struct tevent_req);
    2180           0 :     struct sdap_get_groups_state *state = tevent_req_data(req,
    2181             :                                             struct sdap_get_groups_state);
    2182             :     struct sysdb_attrs **users;
    2183           0 :     struct sysdb_attrs *group = state->groups[0];
    2184             :     struct ldb_message_element *member_el;
    2185             :     struct ldb_message_element *orig_dn_el;
    2186           0 :     size_t count = 0;
    2187             :     size_t i;
    2188             :     hash_table_t *ghosts;
    2189             : 
    2190           0 :     ret = sdap_get_ad_match_rule_members_recv(subreq, state,
    2191             :                                               &count, &users);
    2192           0 :     talloc_zfree(subreq);
    2193           0 :     if (ret != EOK && ret != ENOENT) {
    2194           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    2195             :               "Could not retrieve members using AD match rule. [%s]\n",
    2196             :                strerror(ret));
    2197             : 
    2198           0 :         goto done;
    2199             :     }
    2200             : 
    2201             :     /* Save the group and users to the cache */
    2202             : 
    2203             :     /* Truncate the member attribute of the group.
    2204             :      * It will be repopulated below, and it may currently
    2205             :      * be incomplete anyway, thanks to the range extension.
    2206             :      */
    2207             : 
    2208           0 :     ret = sysdb_attrs_get_el(group, SYSDB_MEMBER, &member_el);
    2209           0 :     if (ret != EOK) {
    2210           0 :         goto done;
    2211             :     }
    2212             : 
    2213           0 :     member_el->num_values = 0;
    2214           0 :     talloc_zfree(member_el->values);
    2215             : 
    2216           0 :     tmp_ctx = talloc_new(NULL);
    2217           0 :     if (!tmp_ctx) {
    2218           0 :         ret = ENOMEM;
    2219           0 :         goto done;
    2220             :     }
    2221             : 
    2222             :     /* Figure out which users are already cached in the sysdb and
    2223             :      * which ones need to be added as ghost users.
    2224             :      */
    2225           0 :     ret = sdap_nested_group_populate_users(tmp_ctx, state->sysdb, state->dom,
    2226             :                                            state->opts, users, count,
    2227             :                                            &ghosts);
    2228           0 :     if (ret != EOK) {
    2229           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    2230             :               "Could not determine which users are ghosts: [%s]\n",
    2231             :                strerror(ret));
    2232           0 :         goto done;
    2233             :     }
    2234             : 
    2235             :     /* Add any entries that aren't in the ghost hash table to the
    2236             :      * member element of the group. This will get converted to a
    2237             :      * native sysdb representation later in sdap_save_groups().
    2238             :      */
    2239             : 
    2240             :     /* Add all of the users as members
    2241             :      */
    2242           0 :     member_el->values = talloc_zero_array(tmp_ctx, struct ldb_val, count);
    2243           0 :     if (!member_el->values) {
    2244           0 :         ret = ENOMEM;
    2245           0 :         goto done;
    2246             :     }
    2247             : 
    2248             :     /* Copy the origDN values of the users into the member element */
    2249           0 :     for (i = 0; i < count; i++) {
    2250           0 :         ret = sysdb_attrs_get_el(users[i], SYSDB_ORIG_DN,
    2251             :                                  &orig_dn_el);
    2252           0 :         if (ret != EOK) {
    2253             :             /* This should never happen. Every entry should have
    2254             :              * an originalDN.
    2255             :              */
    2256           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    2257             :                   "BUG: Missing originalDN for user?\n");
    2258           0 :             goto done;
    2259             :         }
    2260             : 
    2261             :         /* These values will have the same lifespan, so instead
    2262             :          * of copying them, just point at the data.
    2263             :          */
    2264           0 :         member_el->values[i].data = orig_dn_el->values[0].data;
    2265           0 :         member_el->values[i].length = orig_dn_el->values[0].length;
    2266             :     }
    2267           0 :     member_el->num_values = count;
    2268             : 
    2269             :     /* Now save the group, users and ghosts to the cache */
    2270           0 :     ret = sdap_save_groups(tmp_ctx, state->sysdb, state->dom,
    2271             :                            state->opts, state->groups, 1,
    2272             :                            false, ghosts, true, NULL);
    2273           0 :     if (ret != EOK) {
    2274           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
    2275             :               "Could not save group to the cache: [%s]\n",
    2276             :                strerror(ret));
    2277           0 :         goto done;
    2278             :     }
    2279             : 
    2280           0 :     ret = EOK;
    2281             : 
    2282             : done:
    2283           0 :     talloc_free(tmp_ctx);
    2284             : 
    2285           0 :     if (ret == EOK) {
    2286           0 :         tevent_req_done(req);
    2287             :     } else {
    2288           0 :         tevent_req_error(req, ret);
    2289             :     }
    2290           0 : }
    2291             : 
    2292           0 : int sdap_get_groups_recv(struct tevent_req *req,
    2293             :                          TALLOC_CTX *mem_ctx, char **usn_value)
    2294             : {
    2295           0 :     struct sdap_get_groups_state *state = tevent_req_data(req,
    2296             :                                             struct sdap_get_groups_state);
    2297             : 
    2298           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
    2299             : 
    2300           0 :     if (usn_value) {
    2301           0 :         *usn_value = talloc_steal(mem_ctx, state->higher_usn);
    2302             :     }
    2303             : 
    2304           0 :     return EOK;
    2305             : }
    2306             : 
    2307           0 : static void sdap_nested_done(struct tevent_req *subreq)
    2308             : {
    2309             :     errno_t ret, tret;
    2310             :     unsigned long user_count;
    2311             :     unsigned long group_count;
    2312           0 :     bool in_transaction = false;
    2313           0 :     struct sysdb_attrs **users = NULL;
    2314           0 :     struct sysdb_attrs **groups = NULL;
    2315             :     hash_table_t *ghosts;
    2316           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
    2317             :                                                       struct tevent_req);
    2318           0 :     struct sdap_get_groups_state *state = tevent_req_data(req,
    2319             :                                             struct sdap_get_groups_state);
    2320             : 
    2321           0 :     ret = sdap_nested_group_recv(state, subreq, &user_count, &users,
    2322             :                                  &group_count, &groups);
    2323           0 :     talloc_zfree(subreq);
    2324           0 :     if (ret != EOK) {
    2325           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Nested group processing failed: [%d][%s]\n",
    2326             :                   ret, strerror(ret));
    2327           0 :         goto fail;
    2328             :     }
    2329             : 
    2330             :     /* Save all of the users first so that they are in
    2331             :      * place for the groups to add them.
    2332             :      */
    2333           0 :     ret = sysdb_transaction_start(state->sysdb);
    2334           0 :     if (ret != EOK) {
    2335           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction\n");
    2336           0 :         goto fail;
    2337             :     }
    2338           0 :     in_transaction = true;
    2339             : 
    2340           0 :     ret = sdap_nested_group_populate_users(state, state->sysdb,
    2341             :                                            state->dom, state->opts,
    2342             :                                            users, user_count, &ghosts);
    2343           0 :     if (ret != EOK) {
    2344           0 :         goto fail;
    2345             :     }
    2346             : 
    2347           0 :     ret = sdap_save_groups(state, state->sysdb, state->dom, state->opts,
    2348             :                            groups, group_count, false, ghosts, true,
    2349             :                            &state->higher_usn);
    2350           0 :     if (ret != EOK) {
    2351           0 :         goto fail;
    2352             :     }
    2353             : 
    2354           0 :     ret = sysdb_transaction_commit(state->sysdb);
    2355           0 :     if (ret != EOK) {
    2356           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n");
    2357           0 :         goto fail;
    2358             :     }
    2359           0 :     in_transaction = false;
    2360             : 
    2361             :     /* Processing complete */
    2362           0 :     tevent_req_done(req);
    2363           0 :     return;
    2364             : 
    2365             : fail:
    2366           0 :     if (in_transaction) {
    2367           0 :         tret = sysdb_transaction_cancel(state->sysdb);
    2368           0 :         if (tret != EOK) {
    2369           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Failed to cancel transaction\n");
    2370             :         }
    2371             :     }
    2372           0 :     tevent_req_error(req, ret);
    2373             : }
    2374             : 
    2375           0 : static errno_t sdap_nested_group_populate_users(TALLOC_CTX *mem_ctx,
    2376             :                                                 struct sysdb_ctx *sysdb,
    2377             :                                                 struct sss_domain_info *domain,
    2378             :                                                 struct sdap_options *opts,
    2379             :                                                 struct sysdb_attrs **users,
    2380             :                                                 int num_users,
    2381             :                                                 hash_table_t **_ghosts)
    2382             : {
    2383             :     int i;
    2384             :     errno_t ret, sret;
    2385             :     struct ldb_message_element *el;
    2386             :     const char *username;
    2387             :     char *clean_orig_dn;
    2388             :     const char *original_dn;
    2389             :     struct sss_domain_info *user_dom;
    2390             :     struct sdap_domain *sdap_dom;
    2391             : 
    2392             :     TALLOC_CTX *tmp_ctx;
    2393             :     struct ldb_message **msgs;
    2394             :     char *filter;
    2395             :     const char *sysdb_name;
    2396             :     struct sysdb_attrs *attrs;
    2397             :     static const char *search_attrs[] = { SYSDB_NAME, NULL };
    2398             :     hash_table_t *ghosts;
    2399             :     hash_key_t key;
    2400             :     hash_value_t value;
    2401             :     size_t count;
    2402           0 :     bool in_transaction = false;
    2403             : 
    2404           0 :     if (_ghosts == NULL) {
    2405           0 :         return EINVAL;
    2406             :     }
    2407             : 
    2408           0 :     if (num_users == 0) {
    2409             :         /* Nothing to do if there are no users */
    2410           0 :         *_ghosts = NULL;
    2411           0 :         return EOK;
    2412             :     }
    2413             : 
    2414           0 :     tmp_ctx = talloc_new(NULL);
    2415           0 :     if (!tmp_ctx) return ENOMEM;
    2416             : 
    2417           0 :     ret = sss_hash_create(tmp_ctx, num_users, &ghosts);
    2418           0 :     if (ret != HASH_SUCCESS) {
    2419           0 :         ret = ENOMEM;
    2420           0 :         goto done;
    2421             :     }
    2422             : 
    2423           0 :     ret = sysdb_transaction_start(sysdb);
    2424           0 :     if (ret) {
    2425           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to start transaction!\n");
    2426           0 :         goto done;
    2427             :     }
    2428           0 :     in_transaction = true;
    2429             : 
    2430           0 :     for (i = 0; i < num_users; i++) {
    2431           0 :         ret = sysdb_attrs_get_el(users[i], SYSDB_ORIG_DN, &el);
    2432           0 :         if (el->num_values == 0) {
    2433           0 :             ret = EINVAL;
    2434             :         }
    2435           0 :         if (ret != EOK) {
    2436           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2437             :                   "User entry %d has no originalDN attribute\n", i);
    2438           0 :             goto done;
    2439             :         }
    2440           0 :         original_dn = (const char *) el->values[0].data;
    2441             : 
    2442           0 :         ret = sss_filter_sanitize(tmp_ctx, original_dn,
    2443             :                                   &clean_orig_dn);
    2444           0 :         if (ret != EOK) {
    2445           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    2446             :                   "Cannot sanitize originalDN [%s]\n", original_dn);
    2447           0 :             goto done;
    2448             :         }
    2449             : 
    2450           0 :         sdap_dom = sdap_domain_get_by_dn(opts, original_dn);
    2451           0 :         user_dom = sdap_dom == NULL ? domain : sdap_dom->dom;
    2452             : 
    2453           0 :         ret = sdap_get_user_primary_name(tmp_ctx, opts, users[i],
    2454             :                                          user_dom, &username);
    2455           0 :         if (ret != EOK) {
    2456           0 :             DEBUG(SSSDBG_MINOR_FAILURE,
    2457             :                   "User entry %d has no name attribute. Skipping\n", i);
    2458           0 :             continue;
    2459             :         }
    2460             : 
    2461             :         /* Check for the specified origDN in the sysdb */
    2462           0 :         filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
    2463             :                                  SYSDB_ORIG_DN,
    2464             :                                  clean_orig_dn);
    2465           0 :         if (!filter) {
    2466           0 :             ret = ENOMEM;
    2467           0 :             goto done;
    2468             :         }
    2469           0 :         ret = sysdb_search_users(tmp_ctx, domain, filter,
    2470             :                                  search_attrs, &count, &msgs);
    2471           0 :         talloc_zfree(filter);
    2472           0 :         talloc_zfree(clean_orig_dn);
    2473           0 :         if (ret != EOK && ret != ENOENT) {
    2474           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Error checking cache for user entry\n");
    2475           0 :             goto done;
    2476           0 :         } else if (ret == EOK) {
    2477             :             /* The entry is cached but expired. Update the username
    2478             :              * if needed. */
    2479           0 :             if (count != 1) {
    2480           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
    2481             :                       "More than one entry with this origDN? Skipping\n");
    2482           0 :                 continue;
    2483             :             }
    2484             : 
    2485           0 :             sysdb_name = ldb_msg_find_attr_as_string(msgs[0], SYSDB_NAME, NULL);
    2486           0 :             if (strcmp(sysdb_name, username) == 0) {
    2487             :                 /* Username is correct, continue */
    2488           0 :                 continue;
    2489             :             }
    2490             : 
    2491           0 :             attrs = sysdb_new_attrs(tmp_ctx);
    2492           0 :             if (!attrs) {
    2493           0 :                 ret = ENOMEM;
    2494           0 :                 goto done;
    2495             :             }
    2496             : 
    2497           0 :             ret = sysdb_attrs_add_string(attrs, SYSDB_NAME, username);
    2498           0 :             if (ret) goto done;
    2499           0 :             ret = sysdb_set_entry_attr(user_dom->sysdb, msgs[0]->dn, attrs,
    2500             :                                        SYSDB_MOD_REP);
    2501           0 :             if (ret != EOK) goto done;
    2502             :         } else {
    2503           0 :             key.type = HASH_KEY_STRING;
    2504           0 :             key.str = talloc_steal(ghosts, discard_const(original_dn));
    2505           0 :             value.type = HASH_VALUE_PTR;
    2506           0 :             value.ptr = talloc_steal(ghosts, discard_const(username));
    2507           0 :             ret = hash_enter(ghosts, &key, &value);
    2508           0 :             if (ret != HASH_SUCCESS) {
    2509           0 :                 talloc_free(key.str);
    2510           0 :                 talloc_free(value.ptr);
    2511           0 :                 ret = ENOMEM;
    2512           0 :                 goto done;
    2513             :             }
    2514             :         }
    2515             :     }
    2516             : 
    2517           0 :     ret = sysdb_transaction_commit(sysdb);
    2518           0 :     if (ret) {
    2519           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction!\n");
    2520           0 :         goto done;
    2521             :     }
    2522           0 :     in_transaction = false;
    2523             : 
    2524           0 :     ret = EOK;
    2525             : done:
    2526           0 :     if (in_transaction) {
    2527           0 :         sret = sysdb_transaction_cancel(sysdb);
    2528           0 :         if (sret != EOK) {
    2529           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n");
    2530             :         }
    2531             :     }
    2532             : 
    2533           0 :     if (ret != EOK) {
    2534           0 :         *_ghosts = NULL;
    2535             :     } else {
    2536           0 :         *_ghosts = talloc_steal(mem_ctx, ghosts);
    2537             :     }
    2538           0 :     talloc_zfree(tmp_ctx);
    2539           0 :     return ret;
    2540             : }

Generated by: LCOV version 1.10