diff --git a/.gitignore b/.gitignore index cc024b9..bd547a2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -sssd-2.11.1.tar.gz +sssd-2.12.0.tar.gz diff --git a/0001-Revert-ipa-improve-handling-of-external-group-member.patch b/0001-Revert-ipa-improve-handling-of-external-group-member.patch deleted file mode 100644 index c2360c1..0000000 --- a/0001-Revert-ipa-improve-handling-of-external-group-member.patch +++ /dev/null @@ -1,222 +0,0 @@ -From 98a91d170f7a6074ed1bd3b8ed9161c4a11b4074 Mon Sep 17 00:00:00 2001 -From: Alexey Tikhonov -Date: Thu, 14 Aug 2025 16:21:00 +0200 -Subject: [PATCH] Revert "ipa: improve handling of external group memberships" - -This reverts commit 63a6f51069a86765417f044a62705fe20572e0da. ---- - src/providers/ipa/ipa_subdomains_ext_groups.c | 152 +++--------------- - 1 file changed, 22 insertions(+), 130 deletions(-) - -diff --git a/src/providers/ipa/ipa_subdomains_ext_groups.c b/src/providers/ipa/ipa_subdomains_ext_groups.c -index f86130d89..ba3fb3953 100644 ---- a/src/providers/ipa/ipa_subdomains_ext_groups.c -+++ b/src/providers/ipa/ipa_subdomains_ext_groups.c -@@ -312,19 +312,11 @@ static errno_t add_ad_user_to_cached_groups(struct ldb_dn *user_dn, - bool *missing_groups) - { - size_t c; -- size_t d = 0; - struct sysdb_attrs *user_attrs; - size_t msgs_count; - struct ldb_message **msgs; - TALLOC_CTX *tmp_ctx; - int ret; -- const struct ldb_val *val; -- char *user_name; -- char **sysdb_ipa_group_memberships; -- char **add_groups; -- char **del_groups; -- errno_t sret; -- bool in_transaction = false; - - *missing_groups = false; - -@@ -334,96 +326,18 @@ static errno_t add_ad_user_to_cached_groups(struct ldb_dn *user_dn, - return ENOMEM; - } - -- val = ldb_dn_get_rdn_val(user_dn); -- if (val == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "user_dn has no RDN.\n"); -- ret = EINVAL; -- goto done; -- } -- user_name = talloc_strndup(tmp_ctx, (char *) val->data, val->length); -- if (user_name == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "Failed to copy user name.\n"); -- ret = ENOMEM; -- goto done; -- } -- -- ret = sysdb_transaction_start(user_dom->sysdb); -- if (ret != EOK) { -- DEBUG(SSSDBG_FATAL_FAILURE, "Failed to start update transaction\n"); -- goto done; -- } -- -- in_transaction = true; -- -- ret = sysdb_get_direct_parents_ex(tmp_ctx, user_dom, group_dom, -- SYSDB_MEMBER_USER, user_name, -- SYSDB_ORIG_DN, -- &sysdb_ipa_group_memberships); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "Failed to get current IPA group memberships " -- "of user [%s].\n", user_name); -- goto done; -- } -- -- ret = diff_string_lists(tmp_ctx, groups, sysdb_ipa_group_memberships, -- &add_groups, &del_groups, NULL); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "Failed to get difference in group lists.\n"); -- goto done; -- } -- -- user_attrs = sysdb_new_attrs(tmp_ctx); -- if (user_attrs == NULL) { -- DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); -- ret = ENOMEM; -- goto done; -- } -- -- /* Add all new IPA groups to SYSDB_ORIG_MEMBEROF because they are most -- * probably removed by the previous user update and mark all new groups as -- * processed. */ - for (c = 0; groups[c] != NULL; c++) { -- ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF, -- groups[c]); -- if (ret != EOK) { -- DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n"); -- goto done; -+ if (groups[c][0] == '\0') { -+ continue; - } - -- groups[c][0] = '\0'; -- } -- -- if (DEBUG_IS_SET(SSSDBG_TRACE_ALL)) { -- DEBUG(SSSDBG_TRACE_ALL, "New IPA groups [%zu].\n", c); -- -- for (c = 0; sysdb_ipa_group_memberships[c] != NULL; c++); -- DEBUG(SSSDBG_TRACE_ALL, "Cached IPA groups [%zu].\n", c); -- -- for (c = 0; add_groups[c] != NULL; c++); -- DEBUG(SSSDBG_TRACE_ALL, "Groups to add [%zu].\n", c); -- -- for (c = 0; del_groups[c] != NULL; c++); -- DEBUG(SSSDBG_TRACE_ALL, "Groups to delete [%zu].\n", c); -- } -- -- /* TODO: there is a similar functionality (adding and removing group -- * memberships in sysdb_update_members_ex(), but the missing group feature -- * is missing. It might be worth to evaluate if either the missing group -- * feature can be added there or if group which are missing in the cache -- * can bew handled differently here. */ -- -- for (c = 0; add_groups[c] != NULL; c++) { -- -- ret = sysdb_search_groups_by_orig_dn(tmp_ctx, group_dom, add_groups[c], -+ ret = sysdb_search_groups_by_orig_dn(tmp_ctx, group_dom, groups[c], - NULL, &msgs_count, &msgs); - if (ret != EOK) { - if (ret == ENOENT) { - DEBUG(SSSDBG_TRACE_ALL, "Group [%s] not in the cache.\n", -- add_groups[c]); -+ groups[c]); - *missing_groups = true; -- talloc_free(groups[d]); -- /* add missing group back to the list */ -- groups[d++] = talloc_steal(groups, add_groups[c]); - continue; - } else { - DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n"); -@@ -431,6 +345,9 @@ static errno_t add_ad_user_to_cached_groups(struct ldb_dn *user_dn, - } - } - -+/* TODO? Do we have to remove members as well? I think not because the AD -+ * query before removes all memberships. */ -+ - ret = sysdb_mod_group_member(group_dom, user_dn, msgs[0]->dn, - LDB_FLAG_MOD_ADD); - if (ret != EOK && ret != EEXIST) { -@@ -438,58 +355,33 @@ static errno_t add_ad_user_to_cached_groups(struct ldb_dn *user_dn, - goto done; - } - -- } -- talloc_free(groups[d]); -- groups[d] = NULL; -+ user_attrs = sysdb_new_attrs(tmp_ctx); -+ if (user_attrs == NULL) { -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_new_attrs failed.\n"); -+ ret = ENOMEM; -+ goto done; -+ } - -- for (c = 0; del_groups[c] != NULL; c++) { -- ret = sysdb_search_groups_by_orig_dn(tmp_ctx, group_dom, del_groups[c], -- NULL, &msgs_count, &msgs); -+ ret = sysdb_attrs_add_string(user_attrs, SYSDB_ORIG_MEMBEROF, -+ groups[c]); - if (ret != EOK) { -- if (ret == ENOENT) { -- DEBUG(SSSDBG_TRACE_ALL, -- "Group [%s] not in the cache, skipping.\n", -- del_groups[c]); -- continue; -- } else { -- DEBUG(SSSDBG_OP_FAILURE, "sysdb_search_entry failed.\n"); -- goto done; -- } -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_attrs_add_string failed.\n"); -+ goto done; - } - -- ret = sysdb_mod_group_member(group_dom, user_dn, msgs[0]->dn, -- LDB_FLAG_MOD_DELETE); -+ ret = sysdb_set_entry_attr(user_dom->sysdb, user_dn, user_attrs, -+ LDB_FLAG_MOD_ADD); - if (ret != EOK && ret != EEXIST) { -- DEBUG(SSSDBG_OP_FAILURE, -- "sysdb_mod_group_member failed to delete member.\n"); -+ DEBUG(SSSDBG_OP_FAILURE, "sysdb_set_entry_attr failed.\n"); - goto done; - } -- } - -- /* Update SYSDB_ORIG_MEMBEROF with the IPA groups. */ -- ret = sysdb_set_entry_attr(user_dom->sysdb, user_dn, user_attrs, -- LDB_FLAG_MOD_ADD); -- if (ret != EOK && ret != EEXIST) { -- DEBUG(SSSDBG_OP_FAILURE, "Failed to add original IPA group DNs, ignored.\n"); -- } -- -- ret = sysdb_transaction_commit(user_dom->sysdb); -- if (ret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Failed to commit transaction\n"); -- goto done; -+ /* mark group as already processed */ -+ groups[c][0] = '\0'; - } - -- in_transaction = false; -- - ret = EOK; - done: -- if (in_transaction) { -- sret = sysdb_transaction_cancel(user_dom->sysdb); -- if (sret != EOK) { -- DEBUG(SSSDBG_CRIT_FAILURE, "Could not cancel transaction\n"); -- } -- } -- - talloc_free(tmp_ctx); - - return ret; --- -2.50.0 - diff --git a/0001-do-not-require-GID-for-non-POSIX-group.patch b/0001-do-not-require-GID-for-non-POSIX-group.patch new file mode 100644 index 0000000..db6d370 --- /dev/null +++ b/0001-do-not-require-GID-for-non-POSIX-group.patch @@ -0,0 +1,79 @@ +Based on 7aa7344a20b3b31ae53ea790801254af42d525ed +From: Sumit Bose +Date: Mon, 9 Feb 2026 14:10:29 +0100 +Subject: [PATCH] sdap: do not require GID for non-POSIX group + +diff -up sssd-2.12.0/src/providers/ldap/sdap_async_groups.c.orig sssd-2.12.0/src/providers/ldap/sdap_async_groups.c +--- sssd-2.12.0/src/providers/ldap/sdap_async_groups.c.orig 2026-01-14 15:59:45.560996918 +0100 ++++ sssd-2.12.0/src/providers/ldap/sdap_async_groups.c 2026-04-02 10:34:30.367027491 +0200 +@@ -620,15 +620,17 @@ static int sdap_save_group(TALLOC_CTX *m + goto done; + } + +- ret = sysdb_attrs_get_uint32_t(attrs, +- opts->group_map[SDAP_AT_GROUP_GID].sys_name, +- &gid); +- if (ret != EOK) { +- DEBUG(SSSDBG_CRIT_FAILURE, +- "no gid provided for [%s] in domain [%s].\n", +- group_name, dom->name); +- ret = EINVAL; +- goto done; ++ if (posix_group) { ++ ret = sysdb_attrs_get_uint32_t(attrs, ++ opts->group_map[SDAP_AT_GROUP_GID].sys_name, ++ &gid); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_CRIT_FAILURE, ++ "no gid provided for [%s] in domain [%s].\n", ++ group_name, dom->name); ++ ret = EINVAL; ++ goto done; ++ } + } + } + } +diff -up sssd-2.12.0/src/tests/tests/system/tests/test_identity.py.orig sssd-2.12.0/src/tests/tests/system/tests/test_identity.py +--- sssd-2.12.0/src/tests/tests/system/tests/test_identity.py.orig 2026-01-14 15:59:45.611996896 +0100 ++++ sssd-2.12.0/src/tests/tests/system/tests/test_identity.py 2026-04-02 10:34:30.368219151 +0200 +@@ -761,3 +761,40 @@ def test_identity__filter_groups_by_name + + result = client.tools.getent.group(20001) + assert result is None, "Filtered group was found" ++ ++ ++@pytest.mark.importance("critical") ++@pytest.mark.topology(KnownTopologyGroup.AnyAD) ++def test_identity__nested_non_posix_group(client: Client, provider: GenericADProvider): ++ """ ++ :title: Lookup indirect group-members of a nested non-POSIX group ++ :setup: ++ 1. Add a new POSIX user and two new groups, one POSIX the other non-POSIX ++ 2. Add the user to the non-POSIX group and the non-POSIX group to the POSIX group ++ 3. Set 'ldap_id_mapping = false' to allow non-POSIX groups, because ++ with POSIX id-mapping enabled all groups will get POSIX ID and hence ++ there are no non-POSIX groups, and start SSSD ++ :steps: ++ 1. Lookup the POSIX group with getent ++ :expectedresults: ++ 1. Group is present and the new user is a member ++ :customerscenario: False ++ """ ++ user = provider.user("nesteduser").add( ++ uid=10001, gid=20001, password="Secret123", gecos="User for tests", shell="/bin/bash" ++ ) ++ nested_group = provider.group("nested_nonposix_group").add().add_member(user) ++ base_group = provider.group("posix_group").add(gid=30001).add_member(nested_group) ++ ++ client.sssd.domain["ldap_id_mapping"] = "false" ++ client.sssd.start() ++ ++ result = client.tools.getent.group(base_group.name) ++ assert result is not None, f"Group '{base_group.name}' not found!" ++ assert ( ++ len(result.members) == 1 ++ ), f"Group '{base_group.name}' has unexpected number of members [{len(result.members)}]!" ++ assert f"{user.name}" in result.members, f"Member '{user.name}' of group '{base_group.name}' not found!" ++ ++ result = client.tools.getent.group(nested_group.name) ++ assert result is None, f"Non-POSIX Group '{nested_group.name}' was found with 'getent group'!" diff --git a/0002-fix-use-after-free-in-kcm_read_options.patch b/0002-fix-use-after-free-in-kcm_read_options.patch new file mode 100644 index 0000000..ba11482 --- /dev/null +++ b/0002-fix-use-after-free-in-kcm_read_options.patch @@ -0,0 +1,16 @@ +KCM: fix use-after-free in `kcm_read_options()` +Based on commit c5a2b48f13af893ae6c7c9fe63e41f64eb77cade + +diff --git a/src/responder/kcm/kcm_renew.c b/src/responder/kcm/kcm_renew.c +index 39e9470fa22..32eccf4b48a 100644 +--- a/src/responder/kcm/kcm_renew.c ++++ b/src/responder/kcm/kcm_renew.c +@@ -228,7 +228,7 @@ static errno_t kcm_read_options(TALLOC_CTX *mem_ctx, + *_validate = validate; + *_canonicalize = canonicalize; + *_timeout = timeout; +- *_renew_intv = renew_intv; ++ *_renew_intv = talloc_steal(mem_ctx, renew_intv); + + ret = EOK; + diff --git a/0002-krb5-disable-Kerberos-localauth-an2ln-plugin-for-AD-.patch b/0002-krb5-disable-Kerberos-localauth-an2ln-plugin-for-AD-.patch deleted file mode 100644 index 3c3755a..0000000 --- a/0002-krb5-disable-Kerberos-localauth-an2ln-plugin-for-AD-.patch +++ /dev/null @@ -1,49 +0,0 @@ -From a08e5862693ed1191ba464351ae43c779b509096 Mon Sep 17 00:00:00 2001 -From: Sumit Bose -Date: Fri, 10 Oct 2025 12:57:40 +0200 -Subject: [PATCH] krb5: disable Kerberos localauth an2ln plugin for AD/IPA -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -If a client is joined to AD or IPA SSSD's localauth plugin can handle -the mapping of Kerberos principals to local accounts. In case it cannot -map the Kerberos principals libkrb5 is currently configured to fall back -to the default localauth plugins 'default', 'rule', 'names', -'auth_to_local', 'k5login' and 'an2ln' (see man krb5.conf for details). -All plugins except 'an2ln' require some explicit configuration by either -the administrator or the local user. To avoid some unexpected mapping is -done by the 'an2ln' plugin this patch disables it in the configuration -snippets for SSSD's localauth plugin. - -Resolves: https://github.com/SSSD/sssd/issues/8021 - -:relnote: After startup SSSD already creates a Kerberos configuration - snippet typically in /var/lib/sss/pubconf/krb5.include.d/localauth_plugin - if the AD or IPA providers are used. This enables SSSD's localauth plugin. - Starting with this release the an2ln plugin is disabled in the - configuration snippet as well. If this file or its content are included in - the Kerberos configuration it will fix CVE-2025-11561. - -Reviewed-by: Alexey Tikhonov -Reviewed-by: Pavel Březina -(cherry picked from commit 9939c39d1949fad48af2f0b43c788bad0809e310) ---- - src/util/domain_info_utils.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/src/util/domain_info_utils.c b/src/util/domain_info_utils.c -index 677b76ff352198b8b6049213ae32c80f2f59026e..00f22b19d29fb24a8c49219e857a02cc24886a7d 100644 ---- a/src/util/domain_info_utils.c -+++ b/src/util/domain_info_utils.c -@@ -747,6 +747,7 @@ done: - #define LOCALAUTH_PLUGIN_CONFIG \ - "[plugins]\n" \ - " localauth = {\n" \ -+" disable = an2ln\n" \ - " module = sssd:"APP_MODULES_PATH"/sssd_krb5_localauth_plugin.so\n" \ - " }\n" - --- -2.51.0 - diff --git a/0003-do-not-update-cache-timeout-if-member-is-added.patch b/0003-do-not-update-cache-timeout-if-member-is-added.patch new file mode 100644 index 0000000..091285d --- /dev/null +++ b/0003-do-not-update-cache-timeout-if-member-is-added.patch @@ -0,0 +1,385 @@ +Based on https://github.com/SSSD/sssd/pull/8595 +idp: do not update cache timeout if member is added + +diff -up sssd-2.12.0/src/confdb/confdb.c.orig sssd-2.12.0/src/confdb/confdb.c +--- sssd-2.12.0/src/confdb/confdb.c.orig 2026-01-14 15:59:45.496996946 +0100 ++++ sssd-2.12.0/src/confdb/confdb.c 2026-04-14 11:31:11.752143448 +0200 +@@ -1091,6 +1091,7 @@ static errno_t confdb_init_domain(struct + { + errno_t ret; + const char *tmp; ++ bool default_avoid_by_id_lookups = false; + + tmp = ldb_msg_find_attr_as_string(res->msgs[0], "cn", NULL); + if (!tmp) { +@@ -1214,6 +1215,19 @@ static errno_t confdb_init_domain(struct + } + } + ++ if (strcasecmp(domain->provider, "idp") == 0) { ++ default_avoid_by_id_lookups = true; ++ } ++ ret = get_entry_as_bool(res->msgs[0], &domain->avoid_by_id_lookups, ++ CONFDB_DOMAIN_AVOID_BY_ID_LOOKUPS, ++ default_avoid_by_id_lookups); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_FATAL_FAILURE, ++ "Invalid value for %s\n", ++ CONFDB_DOMAIN_AVOID_BY_ID_LOOKUPS); ++ goto done; ++ } ++ + domain->has_views = false; + domain->view_name = NULL; + +diff -up sssd-2.12.0/src/confdb/confdb.h.orig sssd-2.12.0/src/confdb/confdb.h +--- sssd-2.12.0/src/confdb/confdb.h.orig 2026-01-14 15:59:45.496996946 +0100 ++++ sssd-2.12.0/src/confdb/confdb.h 2026-04-14 11:31:11.752647894 +0200 +@@ -226,6 +226,7 @@ + #define CONFDB_DOMAIN_ACCOUNT_CACHE_EXPIRATION "account_cache_expiration" + #define CONFDB_DOMAIN_OVERRIDE_GID "override_gid" + #define CONFDB_DOMAIN_CASE_SENSITIVE "case_sensitive" ++#define CONFDB_DOMAIN_AVOID_BY_ID_LOOKUPS "avoid_by_id_lookups" + #define CONFDB_DOMAIN_SUBDOMAIN_HOMEDIR "subdomain_homedir" + #define CONFDB_DOMAIN_DEFAULT_SUBDOMAIN_HOMEDIR "/home/%d/%u" + #define CONFDB_DOMAIN_IGNORE_GROUP_MEMBERS "ignore_group_members" +@@ -366,6 +367,7 @@ struct sss_domain_info { + uint32_t cache_credentials_min_ff_length; + bool case_sensitive; + bool case_preserve; ++ bool avoid_by_id_lookups; + + gid_t override_gid; + const char *override_homedir; +diff -up sssd-2.12.0/src/config/cfg_rules.ini.orig sssd-2.12.0/src/config/cfg_rules.ini +--- sssd-2.12.0/src/config/cfg_rules.ini.orig 2026-01-14 15:59:45.496996946 +0100 ++++ sssd-2.12.0/src/config/cfg_rules.ini 2026-04-14 11:31:11.753537516 +0200 +@@ -393,6 +393,7 @@ option = dns_discovery_domain + option = failover_primary_timeout + option = override_gid + option = case_sensitive ++option = avoid_by_id_lookups + option = override_homedir + option = fallback_homedir + option = homedir_substring +diff -up sssd-2.12.0/src/config/etc/sssd.api.conf.orig sssd-2.12.0/src/config/etc/sssd.api.conf +--- sssd-2.12.0/src/config/etc/sssd.api.conf.orig 2026-01-14 15:59:45.497996946 +0100 ++++ sssd-2.12.0/src/config/etc/sssd.api.conf 2026-04-14 11:31:11.753715790 +0200 +@@ -172,6 +172,7 @@ dns_discovery_domain = str, None, false + failover_primary_timeout = int, None, false + override_gid = int, None, false + case_sensitive = str, None, false ++avoid_by_id_lookups = bool, None, false + override_homedir = str, None, false + fallback_homedir = str, None, false + homedir_substring = str, None, false +diff -up sssd-2.12.0/src/config/SSSDConfig/sssdoptions.py.orig sssd-2.12.0/src/config/SSSDConfig/sssdoptions.py +--- sssd-2.12.0/src/config/SSSDConfig/sssdoptions.py.orig 2026-01-14 15:59:45.496996946 +0100 ++++ sssd-2.12.0/src/config/SSSDConfig/sssdoptions.py 2026-04-14 11:31:11.752888576 +0200 +@@ -187,6 +187,7 @@ class SSSDOptions(object): + 'server after a successful connection to the backup server'), + 'override_gid': _('Override GID value from the identity provider with this value'), + 'case_sensitive': _('Treat usernames as case sensitive'), ++ 'avoid_by_id_lookups': _('Lookups by ID are expensive or do not work at all'), + 'entry_cache_user_timeout': _('Entry cache timeout length (seconds)'), + 'entry_cache_group_timeout': _('Entry cache timeout length (seconds)'), + 'entry_cache_netgroup_timeout': _('Entry cache timeout length (seconds)'), +diff -up sssd-2.12.0/src/config/SSSDConfigTest.py.orig sssd-2.12.0/src/config/SSSDConfigTest.py +--- sssd-2.12.0/src/config/SSSDConfigTest.py.orig 2026-01-14 15:59:45.496996946 +0100 ++++ sssd-2.12.0/src/config/SSSDConfigTest.py 2026-04-14 11:31:11.753215468 +0200 +@@ -573,6 +573,7 @@ class SSSDConfigTestSSSDDomain(unittest. + 'dyndns_dot_key', + 'override_gid', + 'case_sensitive', ++ 'avoid_by_id_lookups', + 'override_homedir', + 'fallback_homedir', + 'homedir_substring', +@@ -937,6 +938,7 @@ class SSSDConfigTestSSSDDomain(unittest. + 'dyndns_dot_key', + 'override_gid', + 'case_sensitive', ++ 'avoid_by_id_lookups', + 'override_homedir', + 'fallback_homedir', + 'homedir_substring', +diff -up sssd-2.12.0/src/db/sysdb_subdomains.c.orig sssd-2.12.0/src/db/sysdb_subdomains.c +--- sssd-2.12.0/src/db/sysdb_subdomains.c.orig 2026-01-14 15:59:45.499996945 +0100 ++++ sssd-2.12.0/src/db/sysdb_subdomains.c 2026-04-14 11:31:11.753963557 +0200 +@@ -199,6 +199,7 @@ struct sss_domain_info *new_subdomain(TA + dom->default_shell = parent->default_shell; + dom->homedir_substr = parent->homedir_substr; + dom->override_gid = parent->override_gid; ++ dom->avoid_by_id_lookups = parent->avoid_by_id_lookups; + + dom->gssapi_services = parent->gssapi_services; + dom->gssapi_indicators_map = parent->gssapi_indicators_map; +diff -up sssd-2.12.0/src/man/sssd.conf.5.xml.orig sssd-2.12.0/src/man/sssd.conf.5.xml +--- sssd-2.12.0/src/man/sssd.conf.5.xml.orig 2026-01-14 15:59:45.543996926 +0100 ++++ sssd-2.12.0/src/man/sssd.conf.5.xml 2026-04-14 11:31:11.754747046 +0200 +@@ -3775,6 +3775,28 @@ pam_json_services = gdm-switchable-auth + + + ++ avoid_by_id_lookups (boolean) ++ ++ ++ If this option is set to 'true' SSSD will try to ++ avoid sending lookups by ID to the backend and ++ will switch to a lookup by name if a cached ++ object with a matching ID can be found. ++ ++ ++ This option can e.g. be used in cases where ++ searches by ID are expensive on the server side ++ because of missing indexes or are not even ++ possible, e.g. due to non-reversible POSIX ++ id-mapping. ++ ++ ++ Default: False (True for IdP provider) ++ ++ ++ ++ ++ + subdomain_inherit (string) + + +diff -up sssd-2.12.0/src/providers/idp/idp_id_eval.c.orig sssd-2.12.0/src/providers/idp/idp_id_eval.c +--- sssd-2.12.0/src/providers/idp/idp_id_eval.c.orig 2026-01-14 15:59:45.551996922 +0100 ++++ sssd-2.12.0/src/providers/idp/idp_id_eval.c 2026-04-14 11:31:11.756401469 +0200 +@@ -137,7 +137,6 @@ static errno_t store_json_group(struct i + errno_t ret; + json_t *group_name = NULL; + json_t *uuid = NULL; +- int cache_timeout; + struct sss_domain_info *dom; + gid_t gid; + char *fqdn = NULL; +@@ -195,18 +194,35 @@ static errno_t store_json_group(struct i + goto done; + } + +- cache_timeout = dom->group_timeout; +- ret = sysdb_store_group(dom, fqdn, gid, attrs, cache_timeout, 0); ++ /* If we just add a single member to a group (user_name != NULL) we do not ++ * want to change the cache timeout. Calling `sysdb_add_incomplete_group() ++ * will check if the group already exists (ret == ERR_GID_DUPLICATED) or ++ * create an expired group object (ret == EOK). In both cases there will ++ * be a cached group object where the user can be added as a member. */ ++ if (user_name == NULL) { ++ ret = sysdb_store_group(dom, fqdn, gid, attrs, dom->group_timeout, 0); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, "Failed to store group [%s].\n", fqdn); ++ goto done; ++ } ++ } else { ++ ret = sysdb_add_incomplete_group(dom, fqdn, gid, NULL, NULL, ++ json_string_value(uuid), ++ gid != 0, 0); ++ if (ret != EOK && ret != ERR_GID_DUPLICATED) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to create incomplete group [%s].\n", fqdn); ++ goto done; ++ } + +- if (user_name != NULL) { + ret = sysdb_add_group_member(dom, fqdn, user_name, SYSDB_MEMBER_USER, + false); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, +- "Failed to store user [%s] as member of group [%s].\n", +- user_name, fqdn); +- goto done; +- } ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to store user [%s] as member of group [%s].\n", ++ user_name, fqdn); ++ goto done; ++ } + } + + done: +diff -up sssd-2.12.0/src/responder/common/cache_req/cache_req.c.orig sssd-2.12.0/src/responder/common/cache_req/cache_req.c +--- sssd-2.12.0/src/responder/common/cache_req/cache_req.c.orig 2026-01-14 15:59:45.565996916 +0100 ++++ sssd-2.12.0/src/responder/common/cache_req/cache_req.c 2026-04-14 11:31:11.755687660 +0200 +@@ -23,6 +23,7 @@ + #include + #include + ++#include "db/sysdb.h" + #include "util/util.h" + #include "util/sss_chain_id.h" + #include "responder/common/responder.h" +@@ -1613,3 +1614,56 @@ cache_req_steal_data_and_send(TALLOC_CTX + + return req; + } ++ ++errno_t cache_req_fallback_to_name_search(struct cache_req *cr, ++ enum cache_req_type fallback_type, ++ struct ldb_result *result) ++{ ++ int ret; ++ const char *name = NULL; ++ char *shortname = NULL; ++ ++ name = ldb_msg_find_attr_as_string(result->msgs[0], SYSDB_NAME, NULL); ++ if (name != NULL) { ++ ret = cache_req_set_plugin(cr, fallback_type); ++ if (ret != EOK) { ++ CACHE_REQ_DEBUG(SSSDBG_OP_FAILURE, cr, "cache_req_set_plugin failed.\n"); ++ goto done; ++ } ++ ++ ret = sss_parse_internal_fqname(cr, name, &shortname, NULL); ++ if (ret != EOK) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, "sss_parse_internal_fqname() failed\n"); ++ goto done; ++ } ++ ++ ret = cache_req_set_name(cr, shortname); ++ if (ret != EOK) { ++ CACHE_REQ_DEBUG(SSSDBG_CRIT_FAILURE, cr, "cache_req_set_name() failed\n"); ++ goto done; ++ } ++ ++ ret = cr->plugin->prepare_domain_data_fn(cr, cr->data, cr->domain); ++ if (ret != EOK) { ++ CACHE_REQ_DEBUG(SSSDBG_OP_FAILURE, cr, "prepare_domain_data_fn() failed.\n"); ++ goto done; ++ } ++ ++ ret = cache_req_create_debug_name(cr, cr->domain); ++ if (ret != EOK) { ++ CACHE_REQ_DEBUG(SSSDBG_OP_FAILURE, cr, "cache_req_create_debug_name() failed.\n"); ++ goto done; ++ } ++ ++ CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, "Switching to name [%s]\n", ++ name); ++ } else { ++ CACHE_REQ_DEBUG(SSSDBG_OP_FAILURE, cr, "Name not available, switching not possible.\n"); ++ } ++ ++ ret = EOK; ++ ++done: ++ ++ return ret; ++} +diff -up sssd-2.12.0/src/responder/common/cache_req/cache_req_private.h.orig sssd-2.12.0/src/responder/common/cache_req/cache_req_private.h +--- sssd-2.12.0/src/responder/common/cache_req/cache_req_private.h.orig 2026-01-14 15:59:45.565996916 +0100 ++++ sssd-2.12.0/src/responder/common/cache_req/cache_req_private.h 2026-04-14 11:31:11.755989311 +0200 +@@ -224,4 +224,8 @@ cache_req_common_get_acct_domain_recv(TA + + errno_t cache_req_idminmax_check(struct cache_req_data *data, + struct sss_domain_info *domain); ++ ++errno_t cache_req_fallback_to_name_search(struct cache_req *cr, ++ enum cache_req_type fallback_type, ++ struct ldb_result *result); + #endif /* _CACHE_REQ_PRIVATE_H_ */ +diff -up sssd-2.12.0/src/responder/common/cache_req/cache_req_search.c.orig sssd-2.12.0/src/responder/common/cache_req/cache_req_search.c +--- sssd-2.12.0/src/responder/common/cache_req/cache_req_search.c.orig 2026-01-14 15:59:45.566996916 +0100 ++++ sssd-2.12.0/src/responder/common/cache_req/cache_req_search.c 2026-04-14 11:31:11.756157616 +0200 +@@ -311,6 +311,7 @@ cache_req_search_send(TALLOC_CTX *mem_ct + bool bypass_dp = false; + bool skip_refresh = false; + errno_t ret; ++ enum cache_req_type fallback_type = CACHE_REQ_SENTINEL; + + req = tevent_req_create(mem_ctx, &state, struct cache_req_search_state); + if (req == NULL) { +@@ -381,6 +382,26 @@ cache_req_search_send(TALLOC_CTX *mem_ct + CACHE_REQ_DEBUG(SSSDBG_TRACE_FUNC, cr, + "Object found, but needs to be refreshed.\n"); + bypass_dp = false; ++ ++ if (cr->domain->avoid_by_id_lookups) { ++ if (cache_req_data_get_type(cr->data) ++ == CACHE_REQ_GROUP_BY_ID) { ++ fallback_type = CACHE_REQ_GROUP_BY_NAME; ++ } else if (cache_req_data_get_type(cr->data) ++ == CACHE_REQ_USER_BY_ID) { ++ fallback_type = CACHE_REQ_USER_BY_NAME; ++ } ++ ++ if (fallback_type != CACHE_REQ_SENTINEL) { ++ ret = cache_req_fallback_to_name_search(cr, fallback_type, ++ state->result); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to switch to name search.\n"); ++ goto done; ++ } ++ } ++ } + } else { + ret = ENOENT; + } +diff -up sssd-2.12.0/src/tests/tests/system/tests/test_idp.py.orig sssd-2.12.0/src/tests/tests/system/tests/test_idp.py +--- sssd-2.12.0/src/tests/tests/system/tests/test_idp.py.orig 2026-01-14 15:59:45.611996896 +0100 ++++ sssd-2.12.0/src/tests/tests/system/tests/test_idp.py 2026-04-14 11:31:49.961013653 +0200 +@@ -159,3 +159,59 @@ def test_idp__group_ignore_group_members + out = client.host.conn.run(f"getent group group1{domain}") + assert out.stdout.startswith(f"group1{domain}:*:") + assert out.stdout.endswith(":") ++ ++ ++@pytest.mark.parametrize("use_fully_qualified_names", ["true", "false"]) ++@pytest.mark.topology(KnownTopology.Keycloak) ++@pytest.mark.builtwith(client="idp-provider") ++def test_idp__id_before_group(client: Client, keycloak: Keycloak, use_fully_qualified_names: str): ++ """ ++ :title: Call id before getent group ++ :setup: ++ 1. Create two user ++ 2. Create group with both users as members ++ :steps: ++ 1. Lookup one user with 'id' ++ 2. Lookup group with 'getent group' ++ :expectedresults: ++ 1. User is member of added group and the auto-private group ++ 2. Both users are members of the group ++ :customerscenario: False ++ """ ++ ++ user1 = keycloak.user("user1").add(password="Secret123") ++ user2 = keycloak.user("user2").add(password="Secret123") ++ group1 = keycloak.group("group1").add().add_members([user1, user2]) ++ ++ client.sssd.dom("test")["use_fully_qualified_names"] = use_fully_qualified_names ++ ++ domain = f"@{client.sssd.default_domain}" if use_fully_qualified_names == "true" else "" ++ ++ client.sssd.start(check_config=False) ++ ++ user_out = client.tools.id(user1.name + domain) ++ assert user_out is not None, f"User {user1.name} was not found using getent!" ++ assert ( ++ user_out.user.name == user1.name + domain ++ ), f"Username {user_out.user.name} is incorrect, {user1.name}{domain} expected!" ++ assert user_out.memberof( ++ group1.name + domain ++ ), f"User {user_out.user.name} is not a member of group {group1.name}{domain}!" ++ assert user_out.memberof( ++ user1.name + domain ++ ), f"User {user_out.user.name} is not a member of group {user1.name}{domain}!" ++ ++ group_out = client.tools.getent.group(f"{group1.name}{domain}") ++ assert group_out is not None, f"Group {group1.name}{domain} was not found using getent!" ++ assert ( ++ group_out.name == group1.name + domain ++ ), f"Groupname {group_out.name} is incorrect, {group1.name}{domain} expected!" ++ assert ( ++ len(group_out.members) == 2 ++ ), f"Group {group_out.name} has unexpected number of members [{len(group_out.members)}]!" ++ assert ( ++ user1.name + domain in group_out.members ++ ), f"Member {user1.name}{domain} of group {group_out.name} not found!" ++ assert ( ++ user2.name + domain in group_out.members ++ ), f"Member {user2.name}{domain} of group {group_out.name} not found!" diff --git a/sources b/sources index f12bd80..e4fb5a4 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (sssd-2.11.1.tar.gz) = e65897bcb9ddd64f6c01787ad7b7eab3c9916e10f9ead02a6e92de503a4ea71c091e998ccf0344576b520bea75abfe5fd2880e8401237a26274d764d291f6fa4 +SHA512 (sssd-2.12.0.tar.gz) = 3bd90a88a43019b00d3f0a674ef4d2473bf6895e749a54bec8ac1661e7d289083e0cbd64846dacc8bdd4b2447f171dddb2d0ba108962dbd862bce86c2247b038 diff --git a/sssd.spec b/sssd.spec index 1ad425c..9369315 100644 --- a/sssd.spec +++ b/sssd.spec @@ -7,7 +7,6 @@ %global build_kcm_renewals 1 %global krb5_version 1.18.2 %global build_passkey 1 -%global build_idp 0 %global build_ssh_known_hosts_proxy 0 # we don't want to provide private python extension libs @@ -17,22 +16,22 @@ # Determine the location of the LDB modules directory %global ldb_modulesdir %(pkg-config --variable=modulesdir ldb) -%global ldb_version 1.2.0 %global samba_package_version %(rpm -q samba-devel --queryformat %{version}) Name: sssd -Version: 2.11.1 -Release: 2%{?dist}.1 +Version: 2.12.0 +Release: 3%{?dist} Summary: System Security Services Daemon License: GPL-3.0-or-later URL: https://github.com/SSSD/sssd/ -Source0: https://github.com/SSSD/sssd/releases/download/2.11.1/sssd-2.11.1.tar.gz +Source0: https://github.com/SSSD/sssd/releases/download/2.12.0/sssd-2.12.0.tar.gz Source1: sssd.sysusers ### Patches ### -Patch0001: 0001-Revert-ipa-improve-handling-of-external-group-member.patch -Patch0002: 0002-krb5-disable-Kerberos-localauth-an2ln-plugin-for-AD-.patch +Patch1: 0001-do-not-require-GID-for-non-POSIX-group.patch +Patch2: 0002-fix-use-after-free-in-kcm_read_options.patch +Patch3: 0003-do-not-update-cache-timeout-if-member-is-added.patch ### Dependencies ### @@ -87,7 +86,7 @@ BuildRequires: libdhash-devel >= 0.4.2 BuildRequires: libfido2-devel %endif BuildRequires: libini_config-devel >= 1.3 -BuildRequires: libldb-devel >= %{ldb_version} +BuildRequires: libldb-devel BuildRequires: libnfsidmap-devel BuildRequires: libnl3-devel BuildRequires: libselinux-devel @@ -163,7 +162,7 @@ Obsoletes: libsss_simpleifp-debuginfo < 2.9.2 Obsoletes: sssd-polkit-rules < 2.10.0 # Requires # due to ABI changes in 1.1.30/1.2.0 -Requires: libldb >= %{ldb_version} +Requires: libldb >= %{samba_package_version} Requires: libtevent >= 0.11.0 Requires: sssd-client%{?_isa} = %{version}-%{release} Requires: (libsss_sudo = %{version}-%{release} if sudo) @@ -474,14 +473,17 @@ An implementation of a Kerberos KCM server. Use this package if you want to use the KCM: Kerberos credentials cache. %package idp -Summary: Kerberos plugins and OIDC helper for external identity providers. +Summary: The IdP back end of the SSSD, Kerberos plugins and OIDC helper License: GPL-3.0-or-later Requires: sssd-common = %{version}-%{release} +Requires: libsss_idmap = %{version}-%{release} %description idp -This package provides Kerberos plugins that are required to enable -authentication against external identity providers. Additionally a helper -program to handle the OAuth 2.0 Device Authorization Grant is provided. +Provides the Identity Provider (IdP) back end that the SSSD can utilize to fetch +identity data from and authenticate against an IdP like Keycloak or Entra ID +server. Additionally this package provides Kerberos plugins that are required to +enable authentication against external identity providers, if the KDC supports +it, and a helper program to handle the OAuth 2.0 Device Authorization Grant. %if %{build_passkey} %package passkey @@ -499,7 +501,7 @@ enable authentication with passkey token. %endif %prep -%autosetup -n sssd-2.11.1 -p1 +%autosetup -n %{name}-%{version_no_tilde} -p1 %build @@ -534,9 +536,6 @@ autoreconf -ivf %endif %if %{build_ssh_known_hosts_proxy} --with-ssh-known-hosts-proxy \ -%endif -%if ! %{build_idp} - --with-id-provider-idp=no %endif %{nil} @@ -982,10 +981,8 @@ install -D -p -m 0644 %{SOURCE1} %{buildroot}%{_sysusersdir}/sssd.conf %{_mandir}/man8/sssd-kcm.8* %files idp -%if %{build_idp} %{_libdir}/%{name}/libsss_idp.so %{_mandir}/man5/sssd-idp.5* -%endif %{_libexecdir}/%{servicename}/oidc_child %{_libdir}/%{name}/modules/sssd_krb5_idp_plugin.so %{_datadir}/sssd/krb5-snippets/sssd_enable_idp @@ -1093,9 +1090,34 @@ fi %systemd_postun_with_restart sssd.service %changelog -* Tue Oct 21 2025 Sumit Bose - 2.11.1-2.1 -- Resovles: RHEL-120288 - CVE-2025-11561 sssd: SSSD default Kerberos configuration allows - privilege escalation on AD-joined Linux systems [rhel-10.1.z] +* Tue Apr 14 2026 Tomas Halman - 2.12.0-3 +- Resolves: RHEL-167749 - SSSD IdP (Entra ID): listing group members does not work +- Resolves: RHEL-167757 - sssd-kcm fails to start if krb5_renew_interval is specified + +* Thu Apr 2 2026 Tomas Halman - 2.12.0-2 +- Resolves: RHEL-148232 - Failed to resolve indirect group-members of nested non-POSIX group + +* Thu Jan 15 2026 Sumit Bose - 2.12.0-1 +- Resolves: RHEL-139110 - Rebase SSSD for RHEL 10.2 +- Resolves: RHEL-132552 - sssd_be: segfault at 8 ip 00007f6fd25b2b90 sp 00007ffc02dfbae0 error 4 in libsss_ipa.so[7f6fd25ae000+4d000] +- Resolves: RHEL-132505 - RFE: package LDAP provider support for subid ranges +- Resolves: RHEL-130571 - SSSD: change a default value of 'session_provider' sssd.conf option to 'none' +- Resolves: RHEL-129636 - sssd service fails to start after updating to 2.9.6-4 or 2.9.7-4 +- Resolves: RHEL-128594 - 'sssd_nss' hangs when looking up an object by ID that has expired cache entry and filtered out by name +- Resolves: RHEL-127792 - Remove SSSD option ipa_enable_dns_sites +- Resolves: RHEL-120501 - Crash in 'sss_client/autofs/sss_autofs.c' +- Resolves: RHEL-120287 - CVE-2025-11561 sssd: SSSD default Kerberos configuration allows privilege escalation on AD-joined Linux systems [rhel-10.2] +- Resolves: RHEL-114468 - Spam in 'sssd_kcm.log' during normal operations +- Resolves: RHEL-113111 - Including innapropriate IPv6 addresses in dyndns_update +- Resolves: RHEL-104221 - The SSSD cache is filled with groups having GID=0, causing the cache index to grow excessively large. This, in turn, leads to timeouts +- Resolves: RHEL-94545 - When the user name of an AD user in an IPA-AD trust environment overwritten, the user private group, the users primary group, cannot be lookup up by the overwritten name. +- Resolves: RHEL-77184 - AD user in external group is not cleared when expiring the cache +- Resolves: RHEL-72935 - sss_override does not work on AD UPN +- Resolves: RHEL-11913 - GDM Support for IdM IdP feature and MFA [SSSD] +- Resolves: RHEL-4990 - [RFE] SSSD support for Azure AD / Microsoft Entra ID (or general direct support of OIDC authentication) + +* Mon Sep 22 2025 Pavel Filipenský - 2.11.1-3 +- Related: RHEL-114545 - Rebase Samba to the latest 4.23.x release * Thu Aug 14 2025 Alexey Tikhonov - 2.11.1-2 - Related: RHEL-77184 - AD user in external group is not cleared when expiring the cache