Blame SOURCES/0071-AD-Establish-cross-domain-memberships-after-enumerat.patch

2fc102
From 8c714cbf1d0ce2cbddc4222ade51e1f93f36dbe8 Mon Sep 17 00:00:00 2001
2fc102
From: Jakub Hrozek <jhrozek@redhat.com>
2fc102
Date: Wed, 22 Jan 2014 15:21:24 +0100
2fc102
Subject: [PATCH 71/71] AD: Establish cross-domain memberships after
2fc102
 enumeration finishes
2fc102
2fc102
Because domain enumeration currently works for each domain separately,
2fc102
the code has to establish cross-domain memberships after all domains are
2fc102
enumerated. The code works as follows:
2fc102
2fc102
    1) check if any *sub*domains were enumerated. If not, do nothing
2fc102
    2) if any of the groups saved had more original members than
2fc102
       sysdb members, check if members of these groups can be linked now
2fc102
       that all users and groups are saved using the orig_member
2fc102
       attribute of the group matched against originalDN member of the
2fc102
       user.
2fc102
2fc102
Related:
2fc102
https://fedorahosted.org/sssd/ticket/2142
2fc102
---
2fc102
 src/providers/ad/ad_id.c         | 390 +++++++++++++++++++++++++++++++++++++--
2fc102
 src/providers/ad/ad_subdomains.c |  11 --
2fc102
 2 files changed, 379 insertions(+), 22 deletions(-)
2fc102
2fc102
diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
2fc102
index a47aa4f75ab348b0f4597fea264d770b5abe3184..e3302c15774ab1c24b16cefc274313e447b31e5c 100644
2fc102
--- a/src/providers/ad/ad_id.c
2fc102
+++ b/src/providers/ad/ad_id.c
2fc102
@@ -420,10 +420,13 @@ struct ad_enumeration_state {
2fc102
     struct tevent_context *ev;
2fc102
 
2fc102
     struct sdap_domain *sdom;
2fc102
+    struct sdap_domain *sditer;
2fc102
 };
2fc102
 
2fc102
 static void ad_enumeration_conn_done(struct tevent_req *subreq);
2fc102
 static void ad_enumeration_master_done(struct tevent_req *subreq);
2fc102
+static errno_t ad_enum_sdom(struct tevent_req *req, struct sdap_domain *sd,
2fc102
+                            struct ad_id_ctx *id_ctx);
2fc102
 static void ad_enumeration_done(struct tevent_req *subreq);
2fc102
 
2fc102
 struct tevent_req *
2fc102
@@ -452,6 +455,7 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
2fc102
     state->ectx = ectx;
2fc102
     state->ev = ev;
2fc102
     state->sdom = ectx->sdom;
2fc102
+    state->sditer = state->sdom;
2fc102
     state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
2fc102
 
2fc102
     state->sdap_op = sdap_id_op_create(state,
2fc102
@@ -526,7 +530,6 @@ ad_enumeration_master_done(struct tevent_req *subreq)
2fc102
     char *flat_name;
2fc102
     char *master_sid;
2fc102
     char *forest;
2fc102
-    struct sdap_id_conn_ctx *user_conn;
2fc102
 
2fc102
     ret = ad_master_domain_recv(subreq, state,
2fc102
                                 &flat_name, &master_sid, &forest);
2fc102
@@ -545,32 +548,57 @@ ad_enumeration_master_done(struct tevent_req *subreq)
2fc102
         return;
2fc102
     }
2fc102
 
2fc102
-    if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) {
2fc102
-        user_conn = state->id_ctx->gc_ctx;
2fc102
+    ret = ad_enum_sdom(req, state->sdom, state->id_ctx);
2fc102
+    if (ret != EOK) {
2fc102
+        DEBUG(SSSDBG_OP_FAILURE,
2fc102
+                ("Could not enumerate domain %s\n", state->sdom->dom->name));
2fc102
+        tevent_req_error(req, ret);
2fc102
+        return;
2fc102
+    }
2fc102
+
2fc102
+    /* Execution will resume in ad_enumeration_done */
2fc102
+}
2fc102
+
2fc102
+static errno_t
2fc102
+ad_enum_sdom(struct tevent_req *req,
2fc102
+             struct sdap_domain *sd,
2fc102
+             struct ad_id_ctx *id_ctx)
2fc102
+{
2fc102
+    struct sdap_id_conn_ctx *user_conn;
2fc102
+    struct tevent_req *subreq;
2fc102
+    struct ad_enumeration_state *state = tevent_req_data(req,
2fc102
+                                                struct ad_enumeration_state);
2fc102
+
2fc102
+    if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC)) {
2fc102
+        user_conn = id_ctx->gc_ctx;
2fc102
     } else {
2fc102
-        user_conn = state->id_ctx->ldap_ctx;
2fc102
+        user_conn = id_ctx->ldap_ctx;
2fc102
     }
2fc102
 
2fc102
     /* Groups are searched for in LDAP, users in GC. Services (if present,
2fc102
      * which is unlikely in AD) from LDAP as well
2fc102
      */
2fc102
     subreq = sdap_dom_enum_ex_send(state, state->ev,
2fc102
-                                   state->id_ctx->sdap_id_ctx,
2fc102
-                                   state->sdom,
2fc102
-                                   user_conn,                /* Users    */
2fc102
-                                   state->id_ctx->ldap_ctx,  /* Groups   */
2fc102
-                                   state->id_ctx->ldap_ctx); /* Services */
2fc102
+                                   id_ctx->sdap_id_ctx,
2fc102
+                                   sd,
2fc102
+                                   user_conn,         /* Users    */
2fc102
+                                   id_ctx->ldap_ctx,  /* Groups   */
2fc102
+                                   id_ctx->ldap_ctx); /* Services */
2fc102
     if (subreq == NULL) {
2fc102
         /* The ptask API will reschedule the enumeration on its own on
2fc102
          * failure */
2fc102
         DEBUG(SSSDBG_OP_FAILURE,
2fc102
               ("Failed to schedule enumeration, retrying later!\n"));
2fc102
-        tevent_req_error(req, ENOMEM);
2fc102
-        return;
2fc102
+        return ENOMEM;
2fc102
     }
2fc102
     tevent_req_set_callback(subreq, ad_enumeration_done, req);
2fc102
+
2fc102
+    return EOK;
2fc102
 }
2fc102
 
2fc102
+static errno_t ad_enum_cross_dom_members(struct sdap_options *opts,
2fc102
+                                         struct sss_domain_info *dom);
2fc102
+
2fc102
 static void
2fc102
 ad_enumeration_done(struct tevent_req *subreq)
2fc102
 {
2fc102
@@ -579,6 +607,7 @@ ad_enumeration_done(struct tevent_req *subreq)
2fc102
                                                       struct tevent_req);
2fc102
     struct ad_enumeration_state *state = tevent_req_data(req,
2fc102
                                                 struct ad_enumeration_state);
2fc102
+    struct ad_id_ctx *subdom_id_ctx;
2fc102
 
2fc102
     ret = sdap_dom_enum_ex_recv(subreq);
2fc102
     talloc_zfree(subreq);
2fc102
@@ -589,9 +618,348 @@ ad_enumeration_done(struct tevent_req *subreq)
2fc102
         return;
2fc102
     }
2fc102
 
2fc102
+    state->sditer = state->sditer->next;
2fc102
+    if (state->sditer != NULL) {
2fc102
+        subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx);
2fc102
+        if (subdom_id_ctx == NULL) {
2fc102
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve subdomain ad_id_ctx!\n"));
2fc102
+            tevent_req_error(req, EFAULT);
2fc102
+            return;
2fc102
+        }
2fc102
+
2fc102
+        ret = ad_enum_sdom(req, state->sditer, state->sditer->pvt);
2fc102
+        if (ret != EOK) {
2fc102
+            DEBUG(SSSDBG_OP_FAILURE, ("Could not enumerate domain %s\n",
2fc102
+                  state->sditer->dom->name));
2fc102
+            tevent_req_error(req, ret);
2fc102
+            return;
2fc102
+        }
2fc102
+
2fc102
+        /* Execution will resume in ad_enumeration_done */
2fc102
+        return;
2fc102
+    }
2fc102
+
2fc102
+    /* No more subdomains to enumerate. Check if we need to fixup
2fc102
+     * cross-domain membership
2fc102
+     */
2fc102
+    if (state->sditer != state->sdom) {
2fc102
+        /* We did enumerate at least one subdomain. Walk the subdomains
2fc102
+         * and fixup members for each of them
2fc102
+         */
2fc102
+        for (state->sditer = state->sdom;
2fc102
+             state->sditer;
2fc102
+             state->sditer = state->sditer->next) {
2fc102
+            ret = ad_enum_cross_dom_members(state->id_ctx->ad_options->id,
2fc102
+                                            state->sditer->dom);
2fc102
+            if (ret != EOK) {
2fc102
+                DEBUG(SSSDBG_MINOR_FAILURE, ("Could not check cross-domain "
2fc102
+                      "memberships for %s, group memberships might be "
2fc102
+                      "incomplete!\n", state->sdom->dom->name));
2fc102
+                continue;
2fc102
+            }
2fc102
+        }
2fc102
+    }
2fc102
+
2fc102
     tevent_req_done(req);
2fc102
 }
2fc102
 
2fc102
+static errno_t ad_group_extra_members(TALLOC_CTX *mem_ctx,
2fc102
+                                      const struct ldb_message *group,
2fc102
+                                      struct sss_domain_info *dom,
2fc102
+                                      char ***_group_only);
2fc102
+static errno_t ad_group_add_member(struct sdap_options *opts,
2fc102
+                                   struct sss_domain_info *group_domain,
2fc102
+                                   struct ldb_dn *group_dn,
2fc102
+                                   const char *member);
2fc102
+
2fc102
+static errno_t
2fc102
+ad_enum_cross_dom_members(struct sdap_options *opts,
2fc102
+                          struct sss_domain_info *dom)
2fc102
+{
2fc102
+    errno_t ret;
2fc102
+    errno_t sret;
2fc102
+    char *filter;
2fc102
+    TALLOC_CTX *tmp_ctx;
2fc102
+    const char *attrs[] = {
2fc102
+            SYSDB_NAME,
2fc102
+            SYSDB_MEMBER,
2fc102
+            SYSDB_ORIG_MEMBER,
2fc102
+            NULL
2fc102
+    };
2fc102
+    size_t count, i, mi;
2fc102
+    struct ldb_message **msgs;
2fc102
+    bool in_transaction = false;
2fc102
+    char **group_only;
2fc102
+
2fc102
+    tmp_ctx = talloc_new(NULL);
2fc102
+    if (tmp_ctx == NULL) return ENOMEM;
2fc102
+
2fc102
+    ret = sysdb_transaction_start(dom->sysdb);
2fc102
+    if (ret != EOK) {
2fc102
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
2fc102
+        goto done;
2fc102
+    }
2fc102
+    in_transaction = true;
2fc102
+
2fc102
+    filter = talloc_asprintf(tmp_ctx, "(%s=*)", SYSDB_NAME);
2fc102
+    if (filter == NULL) {
2fc102
+        ret = ENOMEM;
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    ret = sysdb_search_groups(tmp_ctx, dom->sysdb, dom,
2fc102
+                              filter, attrs, &count, &msgs);
2fc102
+    if (ret != EOK) {
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    for (i = 0; i < count; i++) {
2fc102
+        ret = ad_group_extra_members(tmp_ctx, msgs[i], dom, &group_only);
2fc102
+        if (ret != EOK) {
2fc102
+            DEBUG(SSSDBG_OP_FAILURE, ("Failed to check extra members\n"));
2fc102
+        } else if (group_only == NULL) {
2fc102
+            DEBUG(SSSDBG_TRACE_INTERNAL, ("No extra members\n"));
2fc102
+            continue;
2fc102
+        }
2fc102
+
2fc102
+        /* Group has extra members */
2fc102
+        for (mi = 0; group_only[mi]; mi++) {
2fc102
+            ret = ad_group_add_member(opts, dom, msgs[i]->dn, group_only[mi]);
2fc102
+            if (ret != EOK) {
2fc102
+                DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add [%s]: %s\n",
2fc102
+                      group_only[mi], strerror(ret)));
2fc102
+                continue;
2fc102
+            }
2fc102
+        }
2fc102
+
2fc102
+        talloc_zfree(group_only);
2fc102
+    }
2fc102
+
2fc102
+    ret = sysdb_transaction_commit(dom->sysdb);
2fc102
+    if (ret != EOK) {
2fc102
+        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n"));
2fc102
+        goto done;
2fc102
+    }
2fc102
+    in_transaction = false;
2fc102
+
2fc102
+    ret = EOK;
2fc102
+done:
2fc102
+    if (in_transaction) {
2fc102
+        sret = sysdb_transaction_cancel(dom->sysdb);
2fc102
+        if (sret != EOK) {
2fc102
+            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n"));
2fc102
+        }
2fc102
+    }
2fc102
+    talloc_free(tmp_ctx);
2fc102
+    return ret;
2fc102
+}
2fc102
+
2fc102
+static errno_t
2fc102
+ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
2fc102
+                             struct ldb_dn *dn, char ***_odn_list);
2fc102
+
2fc102
+static errno_t
2fc102
+ad_group_extra_members(TALLOC_CTX *mem_ctx, const struct ldb_message *group,
2fc102
+                       struct sss_domain_info *dom, char ***_group_only)
2fc102
+{
2fc102
+    TALLOC_CTX *tmp_ctx;
2fc102
+    struct ldb_message_element *m, *om;
2fc102
+    const char *name;
2fc102
+    errno_t ret;
2fc102
+    char **sysdb_odn_list;
2fc102
+    const char **group_odn_list;
2fc102
+    char **group_only = NULL;
2fc102
+
2fc102
+    if (_group_only == NULL) return EINVAL;
2fc102
+    *_group_only = NULL;
2fc102
+
2fc102
+    tmp_ctx = talloc_new(NULL);
2fc102
+    if (tmp_ctx == NULL) return ENOMEM;
2fc102
+
2fc102
+    om = ldb_msg_find_element(group, SYSDB_ORIG_MEMBER);
2fc102
+    m = ldb_msg_find_element(group, SYSDB_MEMBER);
2fc102
+    name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
2fc102
+    if (name == NULL) {
2fc102
+        DEBUG(SSSDBG_OP_FAILURE, ("A group with no name!\n"));
2fc102
+        ret = EFAULT;
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    if (om == NULL || om->num_values == 0) {
2fc102
+        DEBUG(SSSDBG_TRACE_FUNC, ("Group %s has no original members\n", name));
2fc102
+        ret = EOK;
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    if (m == NULL || (m->num_values < om->num_values)) {
2fc102
+        DEBUG(SSSDBG_TRACE_FUNC,
2fc102
+              ("Group %s has %d members but %d original members\n",
2fc102
+               name, m ? m->num_values : 0, om->num_values));
2fc102
+
2fc102
+        /* Get the list of originalDN attributes that are already
2fc102
+         * linked to the group
2fc102
+         */
2fc102
+        ret = ad_group_stored_orig_members(tmp_ctx, dom, group->dn,
2fc102
+                                           &sysdb_odn_list);
2fc102
+        if (ret != EOK) {
2fc102
+            DEBUG(SSSDBG_OP_FAILURE,
2fc102
+                  ("Could not retrieve list of original members for %s\n",
2fc102
+                  name));
2fc102
+            goto done;
2fc102
+        }
2fc102
+
2fc102
+        /* Get the list of original DN attributes the group had in AD */
2fc102
+        group_odn_list = sss_ldb_el_to_string_list(tmp_ctx, om);
2fc102
+        if (group_odn_list == NULL) {
2fc102
+            ret = EFAULT;
2fc102
+            goto done;
2fc102
+        }
2fc102
+
2fc102
+        /* Compare the two lists */
2fc102
+        ret = diff_string_lists(tmp_ctx, discard_const(group_odn_list),
2fc102
+                                sysdb_odn_list, &group_only, NULL, NULL);
2fc102
+        if (ret != EOK) {
2fc102
+            DEBUG(SSSDBG_OP_FAILURE,
2fc102
+                  ("Could not compare lists of members for %s\n", name));
2fc102
+            goto done;
2fc102
+        }
2fc102
+    }
2fc102
+
2fc102
+    ret = EOK;
2fc102
+    *_group_only = talloc_steal(mem_ctx, group_only);
2fc102
+done:
2fc102
+    talloc_free(tmp_ctx);
2fc102
+    return ret;
2fc102
+}
2fc102
+
2fc102
+static errno_t
2fc102
+ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
2fc102
+                             struct ldb_dn *dn, char ***_odn_list)
2fc102
+{
2fc102
+    errno_t ret;
2fc102
+    TALLOC_CTX *tmp_ctx;
2fc102
+    size_t m_count, i;
2fc102
+    struct ldb_message **members;
2fc102
+    const char *attrs[] = {
2fc102
+            SYSDB_NAME,
2fc102
+            SYSDB_ORIG_DN,
2fc102
+            NULL
2fc102
+    };
2fc102
+    char **odn_list;
2fc102
+    const char *odn;
2fc102
+    size_t oi;
2fc102
+
2fc102
+    tmp_ctx = talloc_new(NULL);
2fc102
+    if (tmp_ctx == NULL) return ENOMEM;
2fc102
+
2fc102
+    /* Get all entries member element points to */
2fc102
+    ret = sysdb_asq_search(tmp_ctx, dom->sysdb, dn, NULL, SYSDB_MEMBER,
2fc102
+                           attrs, &m_count, &members);
2fc102
+    if (ret != EOK) {
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    odn_list = talloc_zero_array(tmp_ctx, char *, m_count + 1);
2fc102
+    if (odn_list == NULL) {
2fc102
+        ret = ENOMEM;
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    /* Get a list of their original DNs */
2fc102
+    oi = 0;
2fc102
+    for (i = 0; i < m_count; i++) {
2fc102
+        odn = ldb_msg_find_attr_as_string(members[i], SYSDB_ORIG_DN, NULL);
2fc102
+        if (odn == NULL) {
2fc102
+            continue;
2fc102
+        }
2fc102
+
2fc102
+        odn_list[oi] = talloc_strdup(odn_list, odn);
2fc102
+        if (odn_list[oi] == NULL) {
2fc102
+            ret = ENOMEM;
2fc102
+            goto done;
2fc102
+        }
2fc102
+        oi++;
2fc102
+        DEBUG(SSSDBG_TRACE_INTERNAL, ("Member %s already in sysdb\n", odn));
2fc102
+    }
2fc102
+
2fc102
+    ret = EOK;
2fc102
+    *_odn_list = talloc_steal(mem_ctx, odn_list);
2fc102
+done:
2fc102
+    talloc_free(tmp_ctx);
2fc102
+    return ret;
2fc102
+}
2fc102
+
2fc102
+static errno_t
2fc102
+ad_group_add_member(struct sdap_options *opts,
2fc102
+                    struct sss_domain_info *group_domain,
2fc102
+                    struct ldb_dn *group_dn,
2fc102
+                    const char *member)
2fc102
+{
2fc102
+    struct sdap_domain *sd;
2fc102
+    struct ldb_dn *base_dn;
2fc102
+    TALLOC_CTX *tmp_ctx;
2fc102
+    errno_t ret;
2fc102
+    const char *mem_filter;
2fc102
+    size_t msgs_count;
2fc102
+    struct ldb_message **msgs;
2fc102
+
2fc102
+    /* This member would be from a different domain */
2fc102
+    sd = sdap_domain_get_by_dn(opts, member);
2fc102
+    if (sd == NULL) {
2fc102
+        DEBUG(SSSDBG_MINOR_FAILURE, ("No matching domain for %s\n", member));
2fc102
+        return ENOENT;
2fc102
+    }
2fc102
+
2fc102
+    tmp_ctx = talloc_new(NULL);
2fc102
+    if (tmp_ctx == NULL) return ENOMEM;
2fc102
+
2fc102
+    mem_filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
2fc102
+                                 SYSDB_ORIG_DN, member);
2fc102
+    if (mem_filter == NULL) {
2fc102
+        ret = ENOMEM;
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    base_dn = sysdb_domain_dn(sd->dom->sysdb, tmp_ctx, sd->dom);
2fc102
+    if (base_dn == NULL) {
2fc102
+        ret = ENOMEM;
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    ret = sysdb_search_entry(tmp_ctx, sd->dom->sysdb, base_dn,
2fc102
+                             LDB_SCOPE_SUBTREE, mem_filter, NULL,
2fc102
+                             &msgs_count, &msgs);
2fc102
+    if (ret == ENOENT) {
2fc102
+        DEBUG(SSSDBG_TRACE_FUNC, ("No member [%s] in sysdb\n", member));
2fc102
+        ret = EOK;
2fc102
+        goto done;
2fc102
+    } else if (ret != EOK) {
2fc102
+        goto done;
2fc102
+    }
2fc102
+    DEBUG(SSSDBG_TRACE_INTERNAL, ("[%s] found in sysdb\n", member));
2fc102
+
2fc102
+    if (msgs_count != 1) {
2fc102
+        DEBUG(SSSDBG_CRIT_FAILURE,
2fc102
+               ("Search by orig DN returned %zd results!\n", msgs_count));
2fc102
+        ret = EFAULT;
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    ret = sysdb_mod_group_member(group_domain->sysdb, msgs[0]->dn,
2fc102
+                                 group_dn, SYSDB_MOD_ADD);
2fc102
+    if (ret != EOK) {
2fc102
+        DEBUG(SSSDBG_OP_FAILURE, ("Could not add [%s] as a member of [%s]\n",
2fc102
+              ldb_dn_get_linearized(msgs[0]->dn),
2fc102
+              ldb_dn_get_linearized(group_dn)));
2fc102
+        goto done;
2fc102
+    }
2fc102
+
2fc102
+    ret = EOK;
2fc102
+done:
2fc102
+    talloc_free(tmp_ctx);
2fc102
+    return ret;
2fc102
+}
2fc102
+
2fc102
 errno_t
2fc102
 ad_enumeration_recv(struct tevent_req *req)
2fc102
 {
2fc102
diff --git a/src/providers/ad/ad_subdomains.c b/src/providers/ad/ad_subdomains.c
2fc102
index e7871cc32407893948fe1b2803258d68c70889c1..0d9652b5c615add47958cfdc61eba862a332ae4d 100644
2fc102
--- a/src/providers/ad/ad_subdomains.c
2fc102
+++ b/src/providers/ad/ad_subdomains.c
2fc102
@@ -177,17 +177,6 @@ ad_subdom_ad_ctx_new(struct be_ctx *be_ctx,
2fc102
         return EFAULT;
2fc102
     }
2fc102
 
2fc102
-    ret = sdap_id_setup_tasks(be_ctx,
2fc102
-                              ad_id_ctx->sdap_id_ctx,
2fc102
-                              sdom,
2fc102
-                              ldap_enumeration_send,
2fc102
-                              ldap_enumeration_recv,
2fc102
-                              ad_id_ctx->sdap_id_ctx);
2fc102
-    if (ret != EOK) {
2fc102
-        talloc_free(ad_options);
2fc102
-        return ret;
2fc102
-    }
2fc102
-
2fc102
     /* Set up the ID mapping object */
2fc102
     ad_id_ctx->sdap_id_ctx->opts->idmap_ctx =
2fc102
         id_ctx->sdap_id_ctx->opts->idmap_ctx;
2fc102
-- 
2fc102
1.8.4.2
2fc102