[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