From 26878366fe40ba177de48756b8f886cf452ba2be Mon Sep 17 00:00:00 2001 From: Tomas Halman Date: Tue, 14 Nov 2023 11:07:04 +0100 Subject: [PATCH] Handle child-domain group membership In AD, a user from a domain can be a member of a group that is from a child of the domain. The old code did not account for this and created a cache object with incorrect DNs when ldap_use_tokengoups is set to False. This patch looks up the correct domain before saving group and membership attributes. Resolves: https://github.com/SSSD/sssd/issues/7084 --- Makefile.am | 9 ++- src/db/sysdb_ops.c | 13 +++- src/providers/ldap/sdap.c | 62 ++++++++++++++++--- src/providers/ldap/sdap.h | 2 + src/providers/ldap/sdap_async_groups.c | 2 + src/providers/ldap/sdap_async_initgroups.c | 23 ++++++- src/providers/ldap/sdap_async_initgroups_ad.c | 2 + 7 files changed, 98 insertions(+), 15 deletions(-) diff --git a/Makefile.am b/Makefile.am index 0d81fd8b4af..1fbe0739007 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2357,7 +2357,10 @@ ipa_ldap_opt_tests_LDADD = \ $(LDB_LIBS) \ $(SSSD_INTERNAL_LTLIBS) \ $(OPENLDAP_LIBS) \ - libsss_test_common.la + libsss_test_common.la \ + libsss_ldap_common.la \ + libdlopen_test_providers.la \ + $(NULL) ad_ldap_opt_tests_SOURCES = \ src/providers/ldap/ldap_opts.c \ @@ -2919,6 +2922,8 @@ nestedgroups_tests_LDADD = \ $(SSSD_INTERNAL_LTLIBS) \ libsss_idmap.la \ libsss_test_common.la \ + libsss_ldap_common.la \ + libdlopen_test_providers.la \ $(NULL) if BUILD_SYSTEMTAP nestedgroups_tests_LDADD += stap_generated_probes.lo @@ -3165,6 +3170,8 @@ sdap_tests_LDADD = \ $(SSSD_INTERNAL_LTLIBS) \ $(OPENLDAP_LIBS) \ libsss_test_common.la \ + libsss_ldap_common.la \ + libdlopen_test_providers.la \ $(NULL) if BUILD_IFP diff --git a/src/db/sysdb_ops.c b/src/db/sysdb_ops.c index 7a3c002130f..3331d46877f 100644 --- a/src/db/sysdb_ops.c +++ b/src/db/sysdb_ops.c @@ -2980,6 +2980,7 @@ sysdb_group_membership_mod(struct sss_domain_info *domain, struct ldb_dn *member_dn; char *member_domname; struct sss_domain_info *member_dom; + struct sss_domain_info *group_dom; int ret; TALLOC_CTX *tmp_ctx = talloc_new(NULL); if (!tmp_ctx) { @@ -3019,7 +3020,17 @@ sysdb_group_membership_mod(struct sss_domain_info *domain, } if (!is_dn) { - group_dn = sysdb_group_dn(tmp_ctx, domain, group); + /* To create a correct DN we have to check if the group belongs to */ + /* child domain */ + group_dom = find_domain_by_object_name(domain, group); + if (group_dom == NULL) { + DEBUG(SSSDBG_OP_FAILURE, + "The right (sub)domain for the group [%s] was not found\n", + group); + ret = EINVAL; + goto done; + } + group_dn = sysdb_group_dn(tmp_ctx, group_dom, group); } else { group_dn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, group); } diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c index 232cb43c98e..f5637c5fbf5 100644 --- a/src/providers/ldap/sdap.c +++ b/src/providers/ldap/sdap.c @@ -1843,7 +1843,9 @@ errno_t sdap_get_primary_name(const char *attr_name, static errno_t sdap_get_primary_fqdn(TALLOC_CTX *mem_ctx, + struct sdap_idmap_ctx *idmap_ctx, const char *attr_name, + const char *sid_attr_name, struct sysdb_attrs *attrs, struct sss_domain_info *dom, const char **_primary_fqdn) @@ -1852,6 +1854,8 @@ sdap_get_primary_fqdn(TALLOC_CTX *mem_ctx, const char *shortname = NULL; const char *primary_fqdn = NULL; TALLOC_CTX *tmp_ctx; + char *sid_str = NULL; + struct sss_domain_info *subdomain = NULL; tmp_ctx = talloc_new(NULL); if (tmp_ctx == NULL) { @@ -1863,6 +1867,25 @@ sdap_get_primary_fqdn(TALLOC_CTX *mem_ctx, goto done; } + /* In AD scenarion, the object can be from subdomain - identify it by SID */ + if (sid_attr_name != NULL) { + ret = sdap_attrs_get_sid_str(tmp_ctx, + idmap_ctx, + attrs, + sid_attr_name, + &sid_str); + + if (ret == EOK) { + DEBUG(SSSDBG_TRACE_INTERNAL, "Group has objectSID [%s]\n", sid_str); + subdomain = find_domain_by_sid(dom, sid_str); + talloc_free(sid_str); + if (subdomain != NULL) { + dom = subdomain; + } + } + DEBUG(SSSDBG_TRACE_INTERNAL, "Group has name [%s]\n", dom->name); + } + primary_fqdn = sss_create_internal_fqname(tmp_ctx, shortname, dom->name); if (primary_fqdn == NULL) { ret = ENOMEM; @@ -1883,7 +1906,9 @@ errno_t sdap_get_user_primary_name(TALLOC_CTX *memctx, const char **_user_name) { return sdap_get_primary_fqdn(memctx, + opts->idmap_ctx, opts->user_map[SDAP_AT_USER_NAME].name, + opts->group_map[SDAP_AT_USER_OBJECTSID].name, attrs, dom, _user_name); } @@ -1894,7 +1919,9 @@ errno_t sdap_get_group_primary_name(TALLOC_CTX *memctx, const char **_group_name) { return sdap_get_primary_fqdn(memctx, + opts->idmap_ctx, opts->group_map[SDAP_AT_GROUP_NAME].name, + opts->group_map[SDAP_AT_GROUP_OBJECTSID].name, attrs, dom, _group_name); } @@ -1913,6 +1940,8 @@ _sdap_get_primary_name_list(struct sss_domain_info *domain, size_t attr_count, const char *ldap_attr, bool qualify_names, + const char *sid_attr, + struct sdap_idmap_ctx *idmap_ctx, char ***name_list) { errno_t ret; @@ -1928,17 +1957,28 @@ _sdap_get_primary_name_list(struct sss_domain_info *domain, j = 0; for (i = 0; i < attr_count; i++) { - ret = sdap_get_primary_name(ldap_attr, attr_list[i], &name); - if (ret != EOK) { - DEBUG(SSSDBG_CRIT_FAILURE, "Could not determine primary name\n"); - /* Skip and continue. Don't advance 'j' */ - continue; - } - if (qualify_names == false) { + ret = sdap_get_primary_name(ldap_attr, attr_list[i], &name); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not determine primary name\n"); + /* Skip and continue. Don't advance 'j' */ + continue; + } list[j] = talloc_strdup(list, name); } else { - list[j] = sss_create_internal_fqname(list, name, domain->name); + ret = sdap_get_primary_fqdn(mem_ctx, + idmap_ctx, + ldap_attr, + sid_attr, + attr_list[i], + domain, + &name); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, "Could not determine primary fqdn name\n"); + /* Skip and continue. Don't advance 'j' */ + continue; + } + list[j] = talloc_strdup(list, name); } if (!list[j]) { ret = ENOMEM; @@ -1970,7 +2010,7 @@ errno_t sdap_get_primary_name_list(struct sss_domain_info *domain, char ***name_list) { return _sdap_get_primary_name_list(domain, mem_ctx, attr_list, attr_count, - ldap_attr, false, name_list); + ldap_attr, false, NULL, NULL, name_list); } errno_t sdap_get_primary_fqdn_list(struct sss_domain_info *domain, @@ -1978,10 +2018,12 @@ errno_t sdap_get_primary_fqdn_list(struct sss_domain_info *domain, struct sysdb_attrs **attr_list, size_t attr_count, const char *ldap_attr, + const char *sid_attr, + struct sdap_idmap_ctx *idmap_ctx, char ***name_list) { return _sdap_get_primary_name_list(domain, mem_ctx, attr_list, attr_count, - ldap_attr, true, name_list); + ldap_attr, true, sid_attr, idmap_ctx, name_list); } diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h index 678bf76701e..161bc5c269f 100644 --- a/src/providers/ldap/sdap.h +++ b/src/providers/ldap/sdap.h @@ -707,6 +707,8 @@ errno_t sdap_get_primary_fqdn_list(struct sss_domain_info *domain, struct sysdb_attrs **attr_list, size_t attr_count, const char *ldap_attr, + const char *sid_attr, + struct sdap_idmap_ctx *idmap_ctx, char ***name_list); errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, diff --git a/src/providers/ldap/sdap_async_groups.c b/src/providers/ldap/sdap_async_groups.c index 405260d1848..f36e5c5837a 100644 --- a/src/providers/ldap/sdap_async_groups.c +++ b/src/providers/ldap/sdap_async_groups.c @@ -2002,6 +2002,8 @@ static void sdap_get_groups_process(struct tevent_req *subreq) ret = sdap_get_primary_fqdn_list(state->dom, state, state->groups, state->count, state->opts->group_map[SDAP_AT_GROUP_NAME].name, + state->opts->group_map[SDAP_AT_GROUP_OBJECTSID].name, + state->opts->idmap_ctx, &sysdb_groupnamelist); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c index c4842989bd5..4c8538e8a55 100644 --- a/src/providers/ldap/sdap_async_initgroups.c +++ b/src/providers/ldap/sdap_async_initgroups.c @@ -53,6 +53,7 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb, char *sid_str = NULL; bool use_id_mapping; bool need_filter; + struct sss_domain_info *subdomain; /* There are no groups in LDAP but we should add user to groups?? */ if (ldap_groups_count == 0) return EOK; @@ -68,7 +69,11 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb, mi = 0; for (i=0; sysdb_groupnames[i]; i++) { - ret = sysdb_search_group_by_name(tmp_ctx, domain, sysdb_groupnames[i], NULL, + subdomain = find_domain_by_object_name(domain, sysdb_groupnames[i]); + if (subdomain == NULL) { + subdomain = domain; + } + ret = sysdb_search_group_by_name(tmp_ctx, subdomain, sysdb_groupnames[i], NULL, &msg); if (ret == EOK) { continue; @@ -222,7 +227,11 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb, DEBUG(SSSDBG_TRACE_INTERNAL, "Adding fake group %s to sysdb\n", groupname); - ret = sysdb_add_incomplete_group(domain, groupname, gid, + subdomain = find_domain_by_object_name(domain, groupname); + if (subdomain == NULL) { + subdomain = domain; + } + ret = sysdb_add_incomplete_group(subdomain, groupname, gid, original_dn, sid_str, uuid, posix, now); if (ret == ERR_GID_DUPLICATED) { @@ -233,7 +242,7 @@ errno_t sdap_add_incomplete_groups(struct sysdb_ctx *sysdb, * removed from the memory cache */ ret = sdap_handle_id_collision_for_incomplete_groups( - opts->dp, domain, groupname, gid, + opts->dp, subdomain, groupname, gid, original_dn, sid_str, uuid, posix, now); } @@ -667,6 +676,8 @@ sdap_nested_groups_store(struct sysdb_ctx *sysdb, if (count > 0) { ret = sdap_get_primary_fqdn_list(domain, tmp_ctx, groups, count, opts->group_map[SDAP_AT_GROUP_NAME].name, + opts->group_map[SDAP_AT_GROUP_OBJECTSID].name, + opts->idmap_ctx, &groupnamelist); if (ret != EOK) { DEBUG(SSSDBG_MINOR_FAILURE, @@ -1447,6 +1458,8 @@ sdap_initgr_nested_get_membership_diff(TALLOC_CTX *mem_ctx, ret = sdap_get_primary_fqdn_list(dom, tmp_ctx, ldap_parentlist, parents_count, opts->group_map[SDAP_AT_GROUP_NAME].name, + opts->group_map[SDAP_AT_GROUP_OBJECTSID].name, + opts->idmap_ctx, &ldap_parent_names_list); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, @@ -2105,6 +2118,8 @@ rfc2307bis_group_memberships_build(hash_entry_t *item, void *user_data) ret = sdap_get_primary_fqdn_list(mstate->dom, tmp_ctx, group->ldap_parents, group->parents_count, mstate->opts->group_map[SDAP_AT_GROUP_NAME].name, + mstate->opts->group_map[SDAP_AT_GROUP_OBJECTSID].name, + mstate->opts->idmap_ctx, &ldap_parents_names_list); if (ret != EOK) { goto done; @@ -2169,6 +2184,8 @@ errno_t save_rfc2307bis_user_memberships( ret = sdap_get_primary_fqdn_list(state->dom, tmp_ctx, state->direct_groups, state->num_direct_parents, state->opts->group_map[SDAP_AT_GROUP_NAME].name, + state->opts->group_map[SDAP_AT_GROUP_OBJECTSID].name, + state->opts->idmap_ctx, &ldap_grouplist); if (ret != EOK) { goto error; diff --git a/src/providers/ldap/sdap_async_initgroups_ad.c b/src/providers/ldap/sdap_async_initgroups_ad.c index efd83d2dac8..bb18f35dc3f 100644 --- a/src/providers/ldap/sdap_async_initgroups_ad.c +++ b/src/providers/ldap/sdap_async_initgroups_ad.c @@ -1333,6 +1333,8 @@ sdap_ad_get_domain_local_groups_parse_parents(TALLOC_CTX *mem_ctx, ret = sdap_get_primary_fqdn_list(dom, tmp_ctx, gr->ldap_parents, gr->parents_count, opts->group_map[SDAP_AT_GROUP_NAME].name, + opts->group_map[SDAP_AT_GROUP_OBJECTSID].name, + opts->idmap_ctx, &groupnamelist); if (ret != EOK) { DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_primary_fqdn_list failed.\n");