[SSSD] [PATCH] Connect to GC during enumeration

Sumit Bose sbose at redhat.com
Tue Jan 28 10:17:55 UTC 2014


On Fri, Jan 24, 2014 at 08:31:00PM +0100, Jakub Hrozek wrote:
> On Wed, Jan 22, 2014 at 03:26:07PM +0100, Jakub Hrozek wrote:
> > On Wed, Jan 22, 2014 at 12:02:34AM +0100, Jakub Hrozek wrote:
> > > On Fri, Jan 10, 2014 at 02:54:46PM +0100, Sumit Bose wrote:
> > > > On Fri, Jan 10, 2014 at 02:35:12PM +0100, Jakub Hrozek wrote:
> > > > > On Fri, Jan 10, 2014 at 12:59:05PM +0100, Sumit Bose wrote:
> > > > > > On Tue, Dec 17, 2013 at 09:00:25PM +0100, Jakub Hrozek wrote:
> > > > > > > Hi,
> > > > > > > 
> > > > > > > the attached patches address ticket
> > > > > > > https://fedorahosted.org/sssd/ticket/2142
> > > > > > > 
> > > > > > > There are some things I'm still not satisfied with and one of them is
> > > > > > > refreshing subdomains. Currently the subdomain refresh happens after
> > > > > > > startup and then only if a direct lookup for a user or group happens and
> > > > > > > the timeout for subdomain refresh is over. So in theory it's possible
> > > > > > > that the user and group objects will be refreshed by the enumeration
> > > > > > > task only and there would be no lookup to trigger the subdomain refresh.
> > > > > > > 
> > > > > > > With master domain enumeration we've solved this problem by
> > > > > > > re-downloading master domain info before the enumeration request. We
> > > > > > > could do something similar with subdomains (although a little more
> > > > > > > involved becase there is always precisely one subdomain), but I didn't
> > > > > > > like doing all the changes in 1.11.3. I can code up additional patch
> > > > > > > only for master, though.
> > > > > > > 
> > > > > > > Something similar is with fallback from GC to LDAP. Although here I'm
> > > > > > > not convinced we need to perform the fallback at all, since there are
> > > > > > > already patches on the list that implement the option to disable GC
> > > > > > > lookups and there will also be a patch to autodetect POSIX attributes in
> > > > > > > GC.
> > > > > > > 
> > > > > > > These patches must be applied on top of my previous patches.
> > > > > > 
> > > > > > Can you rebase these patches and their prerequisites? They do not apply
> > > > > > to master anymore. I also cloud not apply "AD: Retry and terminate
> > > > > > sdap_id_op if possible".
> > > 
> > > Hi,
> > > 
> > > the "AD: Retry and terminate sdap_id_op if possible" patch is not
> > > strictly required, so I haven't rebased and resent it yet.
> > > 
> > > > > 
> > > > > Sure, will do.
> > > > > 
> > > > > > 
> > > > > > Based on the experience with AD group-memberships and the recent
> > > > > > changes where we switch back from GC to LDAP to determine
> > > > > > group-memberships I would suggest to use the LDAP connect for the group
> > > > > > enumeration as well.
> > > > > 
> > > > > The last word in a private mini-thread with Simo was to use LDAP for the
> > > > > parent domain by default and GC elsewhere, right? I would also like to
> > > > > check all code is consistent when changing these patches.
> > > > 
> > > > I think in the general only universal group can be retrieve correctly
> > > > form the GC. If we read LDAP for the parent domain there are still the
> > > > global groups from the other domains which might be incomplete in the
> > > > GC.
> > > 
> > > I've been testing the enumeration quite a bit and unfortunately I
> > > found a defect that is not so easily fixed with the current enumeration
> > > architecture. Because the original patches enumerated the primary domain and
> > > subdomain separately, cross-domain memberships were hard, if not impossible
> > > to maintain, at least because there was no guarantee on the order or
> > > completeness of enumeration.
> > > 
> > > So attached are rebased the original patches with the connections fixed
> > > as you liked. But cross-domain memberships don't work.
> > > 
> > > I have two additional patches, one finished and one WIP in my ad_enum branch:
> > > http://fedorapeople.org/cgit/jhrozek/public_git/sssd.git/log/?h=ad_enum
> > > 
> > > The first makes sure the original_member contains the original DN and
> > > not sysdb DN :-) The other is not finished but my intent was to
> > >     1) check if any subdomains were enumerated. If not, do nothing
> > >     2) if any of the groups saved had more original members than sysdb
> > >     members, check if members of these groups can be linked now that all
> > >     users and groups are saved.
> > > 
> > > I hope this would be acceptable, because the cost is only incurred  if
> > > subdomains are enumerated and there are cross-domain memberships at the
> > > same time.. Any other solution I could think of would require bigger
> > > changes, but I'd welcome other ideas.
> > 
> > Hi,
> > 
> > all patches are attached now. With the attached patches, even
> > cross-domain memberships are established in my testing if enumeration is
> > on.
> 
> Hi,
> 
> Sumit found a rather embarrasing bug in the code, where a tevent_req was
> terminated even if it shouldn't. I guess my testing only went fine
> because the server and client are really close to one another and thus
> the request completed quickly.
> 
> Thank you for the review. A new set of patches is attached.

Patches 1, 2, 3 and 5 are looking good.

In patch 4 you add ad_enum_subdom_send() and ad_enum_subdom_done()
(without calling them) and in patch 6 you remove them again.

Other comments for patch 6 are inline.

bye,
Sumit


> From 066ce9945b6af3748f0ead06213f0180a742c542 Mon Sep 17 00:00:00 2001
> From: Jakub Hrozek <jhrozek at redhat.com>
> Date: Wed, 22 Jan 2014 15:21:24 +0100
> Subject: [PATCH 6/6] AD: Establish cross-domain memberships after enumeration
>  finishes
> 
> Because domain enumeration currently works for each domain separately,
> the code has to establish cross-domain memberships after all domains are
> enumerated. The code works as follows:
> 
>     1) check if any *sub*domains were enumerated. If not, do nothing
>     2) if any of the groups saved had more original members than
>        sysdb members, check if members of these groups can be linked now
>        that all users and groups are saved using the orig_member
>        attribute of the group matched against originalDN member of the
>        user.
> 
> Related:
> https://fedorahosted.org/sssd/ticket/2142
> ---
>  src/providers/ad/ad_id.c | 515 +++++++++++++++++++++++++++++++++++------------
>  1 file changed, 390 insertions(+), 125 deletions(-)
> 
> diff --git a/src/providers/ad/ad_id.c b/src/providers/ad/ad_id.c
> index 1bdacf74f0e6de2120603401bcf115549a03ac4f..8818869f73be4afa8b36c0da0341391b569aafd2 100644
> --- a/src/providers/ad/ad_id.c
> +++ b/src/providers/ad/ad_id.c
> @@ -420,10 +420,13 @@ struct ad_enumeration_state {
>      struct tevent_context *ev;
>  
>      struct sdap_domain *sdom;
> +    struct sdap_domain *sditer;
>  };
>  
>  static void ad_enumeration_conn_done(struct tevent_req *subreq);
>  static void ad_enumeration_master_done(struct tevent_req *subreq);
> +static errno_t ad_enum_sdom(struct tevent_req *req, struct sdap_domain *sd,
> +                            struct ad_id_ctx *id_ctx);
>  static void ad_enumeration_done(struct tevent_req *subreq);
>  
>  struct tevent_req *
> @@ -452,6 +455,7 @@ ad_enumeration_send(TALLOC_CTX *mem_ctx,
>      state->ectx = ectx;
>      state->ev = ev;
>      state->sdom = ectx->sdom;
> +    state->sditer = state->sdom;
>      state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
>  
>      state->sdap_op = sdap_id_op_create(state,
> @@ -526,7 +530,6 @@ ad_enumeration_master_done(struct tevent_req *subreq)
>      char *flat_name;
>      char *master_sid;
>      char *forest;
> -    struct sdap_id_conn_ctx *user_conn;
>  
>      ret = ad_master_domain_recv(subreq, state,
>                                  &flat_name, &master_sid, &forest);
> @@ -545,32 +548,57 @@ ad_enumeration_master_done(struct tevent_req *subreq)
>          return;
>      }
>  
> -    if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) {
> -        user_conn = state->id_ctx->gc_ctx;
> +    ret = ad_enum_sdom(req, state->sdom, state->id_ctx);
> +    if (ret != EOK) {
> +        DEBUG(SSSDBG_OP_FAILURE,
> +                ("Could not enumerate domain %s\n", state->sdom->dom->name));
> +        tevent_req_error(req, ret);
> +        return;
> +    }
> +
> +    /* Execution will resume in ad_enumeration_done */
> +}
> +
> +static errno_t
> +ad_enum_sdom(struct tevent_req *req,
> +             struct sdap_domain *sd,
> +             struct ad_id_ctx *id_ctx)
> +{
> +    struct sdap_id_conn_ctx *user_conn;
> +    struct tevent_req *subreq;
> +    struct ad_enumeration_state *state = tevent_req_data(req,
> +                                                struct ad_enumeration_state);
> +
> +    if (dp_opt_get_bool(id_ctx->ad_options->basic, AD_ENABLE_GC)) {
> +        user_conn = id_ctx->gc_ctx;
>      } else {
> -        user_conn = state->id_ctx->ldap_ctx;
> +        user_conn = id_ctx->ldap_ctx;
>      }
>  
>      /* Groups are searched for in LDAP, users in GC. Services (if present,
>       * which is unlikely in AD) from LDAP as well
>       */
>      subreq = sdap_dom_enum_ex_send(state, state->ev,
> -                                   state->id_ctx->sdap_id_ctx,
> -                                   state->sdom,
> -                                   user_conn,                /* Users    */
> -                                   state->id_ctx->ldap_ctx,  /* Groups   */
> -                                   state->id_ctx->ldap_ctx); /* Services */
> +                                   id_ctx->sdap_id_ctx,
> +                                   sd,
> +                                   user_conn,         /* Users    */
> +                                   id_ctx->ldap_ctx,  /* Groups   */
> +                                   id_ctx->ldap_ctx); /* Services */
>      if (subreq == NULL) {
>          /* The ptask API will reschedule the enumeration on its own on
>           * failure */
>          DEBUG(SSSDBG_OP_FAILURE,
>                ("Failed to schedule enumeration, retrying later!\n"));
> -        tevent_req_error(req, ENOMEM);
> -        return;
> +        return ENOMEM;
>      }
>      tevent_req_set_callback(subreq, ad_enumeration_done, req);
> +
> +    return EOK;
>  }
>  
> +static errno_t ad_enum_cross_dom_members(struct sdap_options *opts,
> +                                         struct sss_domain_info *dom);
> +
>  static void
>  ad_enumeration_done(struct tevent_req *subreq)
>  {
> @@ -579,121 +607,8 @@ ad_enumeration_done(struct tevent_req *subreq)
>                                                        struct tevent_req);
>      struct ad_enumeration_state *state = tevent_req_data(req,
>                                                  struct ad_enumeration_state);
> -
> -    ret = sdap_dom_enum_ex_recv(subreq);
> -    talloc_zfree(subreq);
> -    if (ret != EOK) {
> -        DEBUG(SSSDBG_OP_FAILURE,
> -              ("Could not enumerate domain %s\n", state->sdom->dom->name));
> -        tevent_req_error(req, ret);
> -        return;
> -    }
> -
> -    tevent_req_done(req);
> -}
> -
> -errno_t
> -ad_enumeration_recv(struct tevent_req *req)
> -{
> -    TEVENT_REQ_RETURN_ON_ERROR(req);
> -    return EOK;
> -}
> -
> -/* Enumerate a subdomain */
> -struct ad_enum_subdom_state {
> -    struct ad_id_ctx *id_ctx;
>      struct ad_id_ctx *subdom_id_ctx;
>  
> -    struct ldap_enum_ctx *ectx;
> -    struct tevent_context *ev;
> -
> -    struct sdap_domain *sdom;
> -};
> -
> -static void ad_enum_subdom_done(struct tevent_req *subreq);
> -
> -struct tevent_req *
> -ad_enum_subdom_send(TALLOC_CTX *mem_ctx,
> -                    struct tevent_context *ev,
> -                    struct be_ctx *be_ctx,
> -                    struct be_ptask *be_ptask,
> -                    void *pvt)
> -{

see above.

> -    struct tevent_req *req;
> -    struct tevent_req *subreq;
> -    struct ad_enum_subdom_state *state;
> -    struct ldap_enum_ctx *ectx;
> -    errno_t ret;
> -    struct sdap_id_conn_ctx *user_conn;
> -
> -    req = tevent_req_create(mem_ctx, &state, struct ad_enum_subdom_state);
> -    if (req == NULL) return NULL;
> -
> -    ectx = talloc_get_type(pvt, struct ldap_enum_ctx);
> -    if (ectx == NULL) {
> -        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ldap_enum_ctx!\n"));
> -        ret = EFAULT;
> -        goto fail;
> -    }
> -
> -    state->ectx = ectx;
> -    state->ev = ev;
> -    state->sdom = ectx->sdom;
> -    state->id_ctx = talloc_get_type(ectx->pvt, struct ad_id_ctx);
> -    if (state->id_ctx == NULL) {
> -        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve ad_id_ctx!\n"));
> -        ret = EFAULT;
> -        goto fail;
> -    }
> -
> -    state->subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx);
> -    if (state->subdom_id_ctx == NULL) {
> -        DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve subdomain ad_id_ctx!\n"));
> -        ret = EFAULT;
> -        goto fail;
> -    }
> -
> -    if (dp_opt_get_bool(state->id_ctx->ad_options->basic, AD_ENABLE_GC)) {
> -        user_conn = state->id_ctx->gc_ctx;
> -    } else {
> -        user_conn = state->subdom_id_ctx->ldap_ctx;
> -    }
> -
> -    /* Groups are searched for in LDAP, users in GC. Services (if present,
> -     * which is unlikely in AD) from LDAP as well
> -     */
> -    subreq = sdap_dom_enum_ex_send(state, state->ev, state->id_ctx->sdap_id_ctx,
> -                                   state->sdom,
> -                                   user_conn,                      /* Users  */
> -                                   state->subdom_id_ctx->ldap_ctx, /* Groups */
> -                                   state->subdom_id_ctx->ldap_ctx);/* svcs */
> -    if (subreq == NULL) {
> -        /* The ptask API will reschedule the enumeration on its own on
> -         * failure */
> -        DEBUG(SSSDBG_OP_FAILURE,
> -              ("Failed to schedule enumeration, retrying later!\n"));
> -        ret = ENOMEM;
> -        goto fail;
> -    }
> -    tevent_req_set_callback(subreq, ad_enum_subdom_done, req);
> -
> -    return req;
> -
> -fail:
> -    tevent_req_error(req, ret);
> -    tevent_req_post(req, ev);
> -    return req;
> -}
> -
> -static void
> -ad_enum_subdom_done(struct tevent_req *subreq)
> -{
> -    errno_t ret;
> -    struct tevent_req *req = tevent_req_callback_data(subreq,
> -                                                      struct tevent_req);
> -    struct ad_enum_subdom_state *state = tevent_req_data(req,
> -                                                struct ad_enum_subdom_state);
> -
>      ret = sdap_dom_enum_ex_recv(subreq);
>      talloc_zfree(subreq);
>      if (ret != EOK) {
> @@ -703,11 +618,361 @@ ad_enum_subdom_done(struct tevent_req *subreq)
>          return;
>      }
>  
> +    state->sditer = state->sditer->next;
> +    if (state->sditer != NULL) {
> +        subdom_id_ctx = talloc_get_type(state->sdom->pvt, struct ad_id_ctx);
> +        if (subdom_id_ctx == NULL) {
> +            DEBUG(SSSDBG_CRIT_FAILURE, ("Cannot retrieve subdomain ad_id_ctx!\n"));
> +            tevent_req_error(req, EFAULT);
> +            return;
> +        }
> +
> +        ret = ad_enum_sdom(req, state->sditer, state->sditer->pvt);

ret is not checked here as well.

> +        DEBUG(SSSDBG_OP_FAILURE,
> +              ("Could not enumerate domain %s\n", state->sditer->dom->name));
> +        tevent_req_error(req, ret);
> +        return;
> +    }
> +
> +    /* No more subdomains to enumerate. Check if we need to fixup
> +     * cross-domain membership
> +     */
> +    if (state->sditer != state->sdom) {
> +        /* We did enumerate at least one subdomain. Walk the subdomains
> +         * and fixup members for each of them
> +         */
> +        for (state->sditer = state->sdom;
> +             state->sditer;
> +             state->sditer = state->sditer->next) {
> +            ret = ad_enum_cross_dom_members(state->id_ctx->ad_options->id,
> +                                            state->sditer->dom);
> +            if (ret != EOK) {
> +                DEBUG(SSSDBG_MINOR_FAILURE, ("Could not check cross-domain "
> +                      "memberships for %s, group memberships might be "
> +                      "incomplete!\n", state->sdom->dom->name));
> +                continue;
> +            }
> +        }
> +    }
> +
>      tevent_req_done(req);
>  }
>  
> +static errno_t ad_group_extra_members(TALLOC_CTX *mem_ctx,
> +                                      const struct ldb_message *group,
> +                                      struct sss_domain_info *dom,
> +                                      char ***_group_only);
> +static errno_t ad_group_add_member(struct sdap_options *opts,
> +                                   struct sss_domain_info *group_domain,
> +                                   struct ldb_dn *group_dn,
> +                                   const char *member);
> +
> +static errno_t
> +ad_enum_cross_dom_members(struct sdap_options *opts,
> +                          struct sss_domain_info *dom)
> +{
> +    errno_t ret;
> +    errno_t sret;
> +    char *filter;
> +    TALLOC_CTX *tmp_ctx;
> +    const char *attrs[] = {
> +            SYSDB_NAME,
> +            SYSDB_MEMBER,
> +            SYSDB_ORIG_MEMBER,
> +            NULL
> +    };
> +    size_t count, i, mi;
> +    struct ldb_message **msgs;
> +    bool in_transaction = false;
> +    char **group_only;
> +
> +    tmp_ctx = talloc_new(NULL);
> +    if (tmp_ctx == NULL) return ENOMEM;
> +
> +    ret = sysdb_transaction_start(dom->sysdb);
> +    if (ret != EOK) {
> +        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to start transaction\n"));
> +        goto done;
> +    }
> +    in_transaction = true;
> +
> +    filter = talloc_asprintf(tmp_ctx, "(%s=*)", SYSDB_NAME);
> +    if (filter == NULL) {
> +        ret = ENOMEM;
> +        goto done;
> +    }
> +
> +    ret = sysdb_search_groups(tmp_ctx, dom, filter, attrs, &count, &msgs);
> +    if (ret != EOK) {
> +        goto done;
> +    }

You try to process all groups in a domain in a single batch. We might
run into performance/memory issues if there are a lot of groups. But I
think we can keep it as it is for the time being since the easy
workaround is to disable enumeration :-)

> +
> +    for (i = 0; i < count; i++) {
> +        ret = ad_group_extra_members(tmp_ctx, msgs[i], dom, &group_only);
> +        if (ret != EOK) {
> +            DEBUG(SSSDBG_OP_FAILURE, ("Failed to check extra members\n"));
> +        } else if (group_only == NULL) {
> +            DEBUG(SSSDBG_TRACE_INTERNAL, ("No extra members\n"));
> +            continue;
> +        }
> +
> +        /* Group has extra members */
> +        for (mi = 0; group_only[mi]; mi++) {
> +            ret = ad_group_add_member(opts, dom, msgs[i]->dn, group_only[mi]);
> +            if (ret != EOK) {
> +                DEBUG(SSSDBG_MINOR_FAILURE, ("Failed to add [%s]: %s\n",
> +                      group_only[mi], strerror(ret)));
> +                continue;
> +            }
> +        }
> +    }
> +
> +    ret = sysdb_transaction_commit(dom->sysdb);
> +    if (ret != EOK) {
> +        DEBUG(SSSDBG_CRIT_FAILURE, ("Failed to commit transaction\n"));
> +        goto done;
> +    }
> +    in_transaction = false;
> +
> +    ret = EOK;
> +done:
> +    if (in_transaction) {
> +        sret = sysdb_transaction_cancel(dom->sysdb);
> +        if (sret != EOK) {
> +            DEBUG(SSSDBG_CRIT_FAILURE, ("Could not cancel transaction\n"));
> +        }
> +    }
> +    talloc_free(tmp_ctx);
> +    return ret;
> +}
> +
> +static char **
> +ad_group_orig_members(TALLOC_CTX *mem_ctx, struct ldb_message_element *om);
> +static errno_t
> +ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
> +                             struct ldb_dn *dn, char ***_odn_list);
> +
> +static errno_t
> +ad_group_extra_members(TALLOC_CTX *mem_ctx, const struct ldb_message *group,
> +                       struct sss_domain_info *dom, char ***_group_only)
> +{
> +    TALLOC_CTX *tmp_ctx;
> +    struct ldb_message_element *m, *om;
> +    const char *name;
> +    errno_t ret;
> +    char **sysdb_odn_list;
> +    char **group_odn_list;
> +    char **group_only = NULL;
> +
> +    if (_group_only == NULL) return EINVAL;
> +    *_group_only = NULL;
> +
> +    tmp_ctx = talloc_new(NULL);
> +    if (tmp_ctx == NULL) return ENOMEM;
> +
> +    om = ldb_msg_find_element(group, SYSDB_ORIG_MEMBER);
> +    m = ldb_msg_find_element(group, SYSDB_MEMBER);
> +    name = ldb_msg_find_attr_as_string(group, SYSDB_NAME, NULL);
> +    if (name == NULL) {
> +        DEBUG(SSSDBG_OP_FAILURE, ("A group with no name!\n"));
> +        ret = EFAULT;
> +        goto done;
> +    }
> +
> +    if (om == NULL || om->num_values == 0) {
> +        DEBUG(SSSDBG_TRACE_FUNC, ("Group %s has no original members\n", name));
> +        ret = EOK;
> +        goto done;
> +    }
> +
> +    if (m == NULL || (m->num_values < om->num_values)) {
> +        DEBUG(SSSDBG_TRACE_FUNC,
> +              ("Group %s has %d members but %d original members\n",
> +               name, m ? m->num_values : 0, om->num_values));
> +
> +        /* Get the list of originalDN attributes that are already
> +         * linked to the group
> +         */
> +        ret = ad_group_stored_orig_members(tmp_ctx, dom, group->dn,
> +                                           &sysdb_odn_list);
> +        if (ret != EOK) {
> +            DEBUG(SSSDBG_OP_FAILURE,
> +                  ("Could not retrieve list of original members for %s\n",
> +                  name));
> +            goto done;
> +        }
> +
> +        /* Get the list of original DN attributes the group had in AD */
> +        group_odn_list = ad_group_orig_members(tmp_ctx, om);
> +        if (group_odn_list == NULL) {
> +            ret = EFAULT;
> +            goto done;
> +        }
> +
> +        /* Compare the two lists */
> +        ret = diff_string_lists(tmp_ctx, group_odn_list, sysdb_odn_list,
> +                                &group_only, NULL, NULL);
> +        if (ret != EOK) {
> +            DEBUG(SSSDBG_OP_FAILURE,
> +                  ("Could not compare lists of members for %s\n", name));
> +            goto done;
> +        }
> +    }
> +
> +    ret = EOK;
> +    *_group_only = talloc_steal(mem_ctx, group_only);
> +done:
> +    talloc_free(tmp_ctx);
> +    return ret;
> +}
> +
> +static char **
> +ad_group_orig_members(TALLOC_CTX *mem_ctx, struct ldb_message_element *om)

this looks like a generic ldb_message_element_to_string_list call. I
would recommend to rename it and maybe move it to utils/ or db/ ebcause
it might be useful for others as well?

> +{
> +    char **odn_list;
> +    size_t i;
> +
> +    /* Get the list of original DN attributes the group had in AD */
> +    odn_list = talloc_zero_array(mem_ctx, char *, om->num_values + 1);
> +    if (odn_list == NULL) {
> +        return NULL;
> +    }
> +
> +    for (i=0; i < om->num_values; i++) {
> +        odn_list[i] = (char *) om->values[i].data;
> +    }
> +
> +    return odn_list;
> +}
> +
> +static errno_t
> +ad_group_stored_orig_members(TALLOC_CTX *mem_ctx, struct sss_domain_info *dom,
> +                             struct ldb_dn *dn, char ***_odn_list)
> +{
> +    errno_t ret;
> +    TALLOC_CTX *tmp_ctx;
> +    size_t m_count, i;
> +    struct ldb_message **members;
> +    const char *attrs[] = {
> +            SYSDB_NAME,
> +            SYSDB_ORIG_DN,
> +            NULL
> +    };
> +    char **odn_list;
> +    const char *odn;
> +    size_t oi;
> +
> +    tmp_ctx = talloc_new(NULL);
> +    if (tmp_ctx == NULL) return ENOMEM;
> +
> +    /* Get all entries member element points to */
> +    ret = sysdb_asq_search(tmp_ctx, dom, dn, NULL, SYSDB_MEMBER,
> +                           attrs, &m_count, &members);
> +    if (ret != EOK) {
> +        goto done;
> +    }
> +
> +    odn_list = talloc_zero_array(tmp_ctx, char *, m_count + 1);
> +    if (odn_list == NULL) {
> +        ret = ENOMEM;
> +        goto done;
> +    }
> +
> +    /* Get a list of their original DNs */
> +    oi = 0;
> +    for (i = 0; i < m_count; i++) {
> +        odn = ldb_msg_find_attr_as_string(members[i], SYSDB_ORIG_DN, NULL);
> +        if (odn == NULL) {
> +            continue;
> +        }
> +
> +        odn_list[oi] = talloc_strdup(odn_list, odn);
> +        if (odn_list[oi] == NULL) {
> +            continue;

do you really want to continue if talloc_strdup() fails?

> +        }
> +        oi++;
> +        DEBUG(SSSDBG_TRACE_INTERNAL, ("Member %s already in sysdb\n", odn));
> +    }
> +
> +    ret = EOK;
> +    *_odn_list = talloc_steal(mem_ctx, odn_list);
> +done:
> +    talloc_free(tmp_ctx);
> +    return ret;
> +}
> +
> +static errno_t
> +ad_group_add_member(struct sdap_options *opts,
> +                    struct sss_domain_info *group_domain,
> +                    struct ldb_dn *group_dn,
> +                    const char *member)
> +{
> +    struct sdap_domain *sd;
> +    struct ldb_dn *base_dn;
> +    TALLOC_CTX *tmp_ctx;
> +    errno_t ret;
> +    const char *mem_filter;
> +    size_t msgs_count;
> +    struct ldb_message **msgs;
> +
> +    /* This member would be from a different domain */
> +    sd = sdap_domain_get_by_dn(opts, member);
> +    if (sd == NULL) {
> +        DEBUG(SSSDBG_MINOR_FAILURE, ("No matching domain for %s\n", member));
> +        return ENOENT;
> +    }
> +
> +    tmp_ctx = talloc_new(NULL);
> +    if (tmp_ctx == NULL) return ENOMEM;
> +
> +    mem_filter = talloc_asprintf(tmp_ctx, "(%s=%s)",
> +                                 SYSDB_ORIG_DN, member);
> +    if (mem_filter == NULL) {
> +        ret = ENOMEM;
> +        goto done;
> +    }
> +
> +    base_dn = sysdb_domain_dn(tmp_ctx, sd->dom);
> +    if (base_dn == NULL) {
> +        ret = ENOMEM;
> +        goto done;
> +    }
> +
> +    ret = sysdb_search_entry(tmp_ctx, sd->dom->sysdb, base_dn,
> +                             LDB_SCOPE_SUBTREE, mem_filter, NULL,
> +                             &msgs_count, &msgs);
> +    if (ret == ENOENT) {
> +        DEBUG(SSSDBG_TRACE_FUNC, ("No member [%s] in sysdb\n", member));
> +        ret = EOK;
> +        goto done;
> +    } else if (ret != EOK) {
> +        goto done;
> +    }
> +    DEBUG(SSSDBG_TRACE_INTERNAL, ("[%s] found in sysdb\n", member));
> +
> +    if (msgs_count != 1) {
> +        DEBUG(SSSDBG_CRIT_FAILURE,
> +               ("Search by orig DN returned %zd results!\n", msgs_count));
> +        ret = EFAULT;
> +        goto done;
> +    }
> +
> +    ret = sysdb_mod_group_member(group_domain, msgs[0]->dn, group_dn, SYSDB_MOD_ADD);
> +    if (ret != EOK) {
> +        DEBUG(SSSDBG_OP_FAILURE, ("Could not add [%s] as a member of [%s]\n",
> +              ldb_dn_get_linearized(msgs[0]->dn),
> +              ldb_dn_get_linearized(group_dn)));
> +        goto done;
> +    }
> +
> +    ret = EOK;
> +done:
> +    talloc_free(tmp_ctx);
> +    return ret;
> +}
> +
>  errno_t
> -ad_enum_subdom_recv(struct tevent_req *req)
> +ad_enumeration_recv(struct tevent_req *req)
>  {
>      TEVENT_REQ_RETURN_ON_ERROR(req);
>      return EOK;
> -- 
> 1.8.4.2
> 

> _______________________________________________
> sssd-devel mailing list
> sssd-devel at lists.fedorahosted.org
> https://lists.fedorahosted.org/mailman/listinfo/sssd-devel




More information about the sssd-devel mailing list