From 9e669db91976d38b17164ffcb4ee9205d14571e5 Mon Sep 17 00:00:00 2001 From: Alexey Tikhonov Date: Mon, 12 Feb 2024 10:25:10 +0100 Subject: [PATCH] Resolves: RHEL-12503 - AD users are unable to log in due to case sensitivity of user because the domain is found as an alias to the email address. Resolves: RHEL-22288 - ssh pubkey stored in ldap/AD no longer works to authenticate via sssd Resolves: RHEL-22194 - gdm smartcard login fails with sssd-2.9.3 in case of multiple identities --- ...sssd-adding-mail-as-case-insensitive.patch | 144 +++++++++++ ..._bases-option-to-groups_by_user_send.patch | 154 ++++++++++++ ...context-as-new-member-of-struct-sdap.patch | 194 +++++++++++++++ ...with-multiple-certs-and-missing-logi.patch | 233 ++++++++++++++++++ sssd.spec | 12 +- 5 files changed, 735 insertions(+), 2 deletions(-) create mode 100644 0001-sssd-adding-mail-as-case-insensitive.patch create mode 100644 0002-sdap-add-search_bases-option-to-groups_by_user_send.patch create mode 100644 0003-sdap-add-naming_context-as-new-member-of-struct-sdap.patch create mode 100644 0004-pam-fix-SC-auth-with-multiple-certs-and-missing-logi.patch diff --git a/0001-sssd-adding-mail-as-case-insensitive.patch b/0001-sssd-adding-mail-as-case-insensitive.patch new file mode 100644 index 0000000..1e12d0b --- /dev/null +++ b/0001-sssd-adding-mail-as-case-insensitive.patch @@ -0,0 +1,144 @@ +From dd0f63246aa75d5f53b44cbc185e88833e79976e Mon Sep 17 00:00:00 2001 +From: Andre Boscatto +Date: Wed, 7 Feb 2024 12:28:28 +0100 +Subject: [PATCH] sssd: adding mail as case insensitive +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Resolves: https://github.com/SSSD/sssd/issues/7173 + +Reviewed-by: Iker Pedrosa +Reviewed-by: Tomáš Halman +(cherry picked from commit 945cebcf72ef53ea0368f19c09e710f7fff11b51) +--- + src/db/sysdb_init.c | 7 ++++++ + src/db/sysdb_private.h | 5 +++- + src/db/sysdb_upgrade.c | 56 ++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 67 insertions(+), 1 deletion(-) + +diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c +index c2ea6c369..38a9cd64a 100644 +--- a/src/db/sysdb_init.c ++++ b/src/db/sysdb_init.c +@@ -603,6 +603,13 @@ static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx, + } + } + ++ if (strcmp(version, SYSDB_VERSION_0_23) == 0) { ++ ret = sysdb_upgrade_23(sysdb, &version); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ + ret = EOK; + done: + sysdb->ldb = save_ldb; +diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h +index 1f55007bc..63f7b5601 100644 +--- a/src/db/sysdb_private.h ++++ b/src/db/sysdb_private.h +@@ -23,6 +23,7 @@ + #ifndef __INT_SYS_DB_H__ + #define __INT_SYS_DB_H__ + ++#define SYSDB_VERSION_0_24 "0.24" + #define SYSDB_VERSION_0_23 "0.23" + #define SYSDB_VERSION_0_22 "0.22" + #define SYSDB_VERSION_0_21 "0.21" +@@ -47,7 +48,7 @@ + #define SYSDB_VERSION_0_2 "0.2" + #define SYSDB_VERSION_0_1 "0.1" + +-#define SYSDB_VERSION SYSDB_VERSION_0_23 ++#define SYSDB_VERSION SYSDB_VERSION_0_24 + + #define SYSDB_BASE_LDIF \ + "dn: @ATTRIBUTES\n" \ +@@ -60,6 +61,7 @@ + "objectclass: CASE_INSENSITIVE\n" \ + "ipHostNumber: CASE_INSENSITIVE\n" \ + "ipNetworkNumber: CASE_INSENSITIVE\n" \ ++ "mail: CASE_INSENSITIVE\n" \ + "\n" \ + "dn: @INDEXLIST\n" \ + "@IDXATTR: cn\n" \ +@@ -191,6 +193,7 @@ int sysdb_upgrade_19(struct sysdb_ctx *sysdb, const char **ver); + int sysdb_upgrade_20(struct sysdb_ctx *sysdb, const char **ver); + int sysdb_upgrade_21(struct sysdb_ctx *sysdb, const char **ver); + int sysdb_upgrade_22(struct sysdb_ctx *sysdb, const char **ver); ++int sysdb_upgrade_23(struct sysdb_ctx *sysdb, const char **ver); + + int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver); + +diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c +index 346a1cb0b..56083e6be 100644 +--- a/src/db/sysdb_upgrade.c ++++ b/src/db/sysdb_upgrade.c +@@ -2718,6 +2718,62 @@ done: + return ret; + } + ++int sysdb_upgrade_23(struct sysdb_ctx *sysdb, const char **ver) ++{ ++ TALLOC_CTX *tmp_ctx; ++ int ret; ++ struct ldb_message *msg; ++ struct upgrade_ctx *ctx; ++ ++ tmp_ctx = talloc_new(NULL); ++ if (!tmp_ctx) { ++ return ENOMEM; ++ } ++ ++ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_24, &ctx); ++ if (ret) { ++ return ret; ++ } ++ ++ /* Add new indexes */ ++ msg = ldb_msg_new(tmp_ctx); ++ if (!msg) { ++ ret = ENOMEM; ++ goto done; ++ } ++ msg->dn = ldb_dn_new(tmp_ctx, sysdb->ldb, "@ATTRIBUTES"); ++ if (!msg->dn) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ /* Case insensitive search for mail */ ++ ret = ldb_msg_add_empty(msg, SYSDB_USER_EMAIL, LDB_FLAG_MOD_ADD, NULL); ++ if (ret != LDB_SUCCESS) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ret = ldb_msg_add_string(msg, SYSDB_USER_EMAIL, "CASE_INSENSITIVE"); ++ if (ret != LDB_SUCCESS) { ++ ret = ENOMEM; ++ goto done; ++ } ++ ++ ret = ldb_modify(sysdb->ldb, msg); ++ if (ret != LDB_SUCCESS) { ++ ret = sysdb_error_to_errno(ret); ++ goto done; ++ } ++ ++ /* conversion done, update version number */ ++ ret = update_version(ctx); ++ ++done: ++ ret = finish_upgrade(ret, &ctx, ver); ++ talloc_free(tmp_ctx); ++ return ret; ++} ++ + int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver) + { + struct upgrade_ctx *ctx; +-- +2.41.0 + diff --git a/0002-sdap-add-search_bases-option-to-groups_by_user_send.patch b/0002-sdap-add-search_bases-option-to-groups_by_user_send.patch new file mode 100644 index 0000000..e7f048f --- /dev/null +++ b/0002-sdap-add-search_bases-option-to-groups_by_user_send.patch @@ -0,0 +1,154 @@ +From a7621a5b464af7a3c8409dcbde038b35fee2c895 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Tue, 23 Jan 2024 13:47:53 +0100 +Subject: [PATCH 2/3] sdap: add search_bases option to groups_by_user_send() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +AD handles users and computer objects very similar and so does SSSD's +GPO code when lookup up the host's group-memberships. But users and +computers might be stored in different sub-tree of the AD LDAP tree and +if a dedicated user search base is given with the ldap_user_search_base +option in sssd.conf the host object might be in a different sub-tree. To +make sure the host can still be found this patch uses the base DN of +the LDAP tree when searching for hosts in the GPO code. + +Resolves: https://github.com/SSSD/sssd/issues/5708 + +Reviewed-by: Alejandro López +Reviewed-by: Tomáš Halman +(cherry picked from commit 29a77c6e79020d7e8cb474b4d3b394d390eba196) +--- + src/providers/ad/ad_gpo.c | 10 ++++++++++ + src/providers/ldap/ldap_common.h | 1 + + src/providers/ldap/ldap_id.c | 6 +++++- + src/providers/ldap/sdap_async.h | 1 + + src/providers/ldap/sdap_async_initgroups.c | 4 +++- + 5 files changed, 20 insertions(+), 2 deletions(-) + +diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c +index 94959c36b..b0ee3e616 100644 +--- a/src/providers/ad/ad_gpo.c ++++ b/src/providers/ad/ad_gpo.c +@@ -2091,6 +2091,7 @@ ad_gpo_connect_done(struct tevent_req *subreq) + char *server_uri; + LDAPURLDesc *lud; + struct sdap_domain *sdom; ++ struct sdap_search_base **search_bases; + + req = tevent_req_callback_data(subreq, struct tevent_req); + state = tevent_req_data(req, struct ad_gpo_access_state); +@@ -2184,9 +2185,18 @@ ad_gpo_connect_done(struct tevent_req *subreq) + goto done; + } + ++ ret = common_parse_search_base(state, sdom->basedn, state->ldb_ctx, ++ "AD_HOSTS", NULL, &search_bases); ++ if (ret != EOK) { ++ DEBUG(SSSDBG_OP_FAILURE, ++ "Failed to create dedicated search base for host lookups, " ++ "trying with user search base."); ++ } ++ + subreq = groups_by_user_send(state, state->ev, + state->access_ctx->ad_id_ctx->sdap_id_ctx, + sdom, state->conn, ++ search_bases, + state->host_fqdn, + BE_FILTER_NAME, + NULL, +diff --git a/src/providers/ldap/ldap_common.h b/src/providers/ldap/ldap_common.h +index 7159d6356..2c984ef50 100644 +--- a/src/providers/ldap/ldap_common.h ++++ b/src/providers/ldap/ldap_common.h +@@ -304,6 +304,7 @@ struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx, + struct sdap_id_ctx *ctx, + struct sdap_domain *sdom, + struct sdap_id_conn_ctx *conn, ++ struct sdap_search_base **search_bases, + const char *filter_value, + int filter_type, + const char *extra_value, +diff --git a/src/providers/ldap/ldap_id.c b/src/providers/ldap/ldap_id.c +index da54816bd..b3ea2333f 100644 +--- a/src/providers/ldap/ldap_id.c ++++ b/src/providers/ldap/ldap_id.c +@@ -1139,6 +1139,7 @@ struct groups_by_user_state { + struct sdap_id_op *op; + struct sysdb_ctx *sysdb; + struct sss_domain_info *domain; ++ struct sdap_search_base **search_bases; + + const char *filter_value; + int filter_type; +@@ -1160,6 +1161,7 @@ struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx, + struct sdap_id_ctx *ctx, + struct sdap_domain *sdom, + struct sdap_id_conn_ctx *conn, ++ struct sdap_search_base **search_bases, + const char *filter_value, + int filter_type, + const char *extra_value, +@@ -1192,6 +1194,7 @@ struct tevent_req *groups_by_user_send(TALLOC_CTX *memctx, + state->extra_value = extra_value; + state->domain = sdom->dom; + state->sysdb = sdom->dom->sysdb; ++ state->search_bases = search_bases; + + if (state->domain->type == DOM_TYPE_APPLICATION || set_non_posix) { + state->non_posix = true; +@@ -1254,6 +1257,7 @@ static void groups_by_user_connect_done(struct tevent_req *subreq) + sdap_id_op_handle(state->op), + state->ctx, + state->conn, ++ state->search_bases, + state->filter_value, + state->filter_type, + state->extra_value, +@@ -1449,7 +1453,7 @@ sdap_handle_acct_req_send(TALLOC_CTX *mem_ctx, + } + + subreq = groups_by_user_send(state, be_ctx->ev, id_ctx, +- sdom, conn, ++ sdom, conn, NULL, + ar->filter_value, + ar->filter_type, + ar->extra_value, +diff --git a/src/providers/ldap/sdap_async.h b/src/providers/ldap/sdap_async.h +index 5458d21f1..89245f41f 100644 +--- a/src/providers/ldap/sdap_async.h ++++ b/src/providers/ldap/sdap_async.h +@@ -158,6 +158,7 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, + struct sdap_handle *sh, + struct sdap_id_ctx *id_ctx, + struct sdap_id_conn_ctx *conn, ++ struct sdap_search_base **search_bases, + const char *name, + int filter_type, + const char *extra_value, +diff --git a/src/providers/ldap/sdap_async_initgroups.c b/src/providers/ldap/sdap_async_initgroups.c +index 97be594a3..fb3d8fe24 100644 +--- a/src/providers/ldap/sdap_async_initgroups.c ++++ b/src/providers/ldap/sdap_async_initgroups.c +@@ -2732,6 +2732,7 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, + struct sdap_handle *sh, + struct sdap_id_ctx *id_ctx, + struct sdap_id_conn_ctx *conn, ++ struct sdap_search_base **search_bases, + const char *filter_value, + int filter_type, + const char *extra_value, +@@ -2764,7 +2765,8 @@ struct tevent_req *sdap_get_initgr_send(TALLOC_CTX *memctx, + state->orig_user = NULL; + state->timeout = dp_opt_get_int(state->opts->basic, SDAP_SEARCH_TIMEOUT); + state->user_base_iter = 0; +- state->user_search_bases = sdom->user_search_bases; ++ state->user_search_bases = (search_bases == NULL) ? sdom->user_search_bases ++ : search_bases; + if (!state->user_search_bases) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Initgroups lookup request without a user search base\n"); +-- +2.41.0 + diff --git a/0003-sdap-add-naming_context-as-new-member-of-struct-sdap.patch b/0003-sdap-add-naming_context-as-new-member-of-struct-sdap.patch new file mode 100644 index 0000000..a7ff19e --- /dev/null +++ b/0003-sdap-add-naming_context-as-new-member-of-struct-sdap.patch @@ -0,0 +1,194 @@ +From 6a8e60df84d5d2565bec36be19c2def25a6ece1f Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Wed, 24 Jan 2024 14:21:12 +0100 +Subject: [PATCH 3/3] sdap: add naming_context as new member of struct + sdap_domain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The naming_context could be a more reliable source than basedn for the +actual base DN because basedn is set very early from the domain name +given in sssd.conf. Although it is recommended to use the fully +qualified DNS domain name here it is not required. As a result basedn +might not reflect the actual based DN of the LDAP server. Also pure LDAP +server (i.e. not AD or FreeIPA) might use different schemes to set the +base DN which will not be based on the DNS domain of the LDAP server. + +Resolves: https://github.com/SSSD/sssd/issues/5708 + +Reviewed-by: Alejandro López +Reviewed-by: Tomáš Halman +(cherry picked from commit a153f13f296401247a862df2b99048bb1bbb8e2e) +--- + src/providers/ad/ad_gpo.c | 6 ++++-- + src/providers/ldap/sdap.c | 36 +++++++++++++----------------------- + src/providers/ldap/sdap.h | 11 +++++++++++ + 3 files changed, 28 insertions(+), 25 deletions(-) + +diff --git a/src/providers/ad/ad_gpo.c b/src/providers/ad/ad_gpo.c +index b0ee3e616..3d1ad39c7 100644 +--- a/src/providers/ad/ad_gpo.c ++++ b/src/providers/ad/ad_gpo.c +@@ -2185,8 +2185,10 @@ ad_gpo_connect_done(struct tevent_req *subreq) + goto done; + } + +- ret = common_parse_search_base(state, sdom->basedn, state->ldb_ctx, +- "AD_HOSTS", NULL, &search_bases); ++ ret = common_parse_search_base(state, ++ sdom->naming_context == NULL ? sdom->basedn ++ : sdom->naming_context, ++ state->ldb_ctx, "AD_HOSTS", NULL, &search_bases); + if (ret != EOK) { + DEBUG(SSSDBG_OP_FAILURE, + "Failed to create dedicated search base for host lookups, " +diff --git a/src/providers/ldap/sdap.c b/src/providers/ldap/sdap.c +index f5637c5fb..956eba93a 100644 +--- a/src/providers/ldap/sdap.c ++++ b/src/providers/ldap/sdap.c +@@ -1252,19 +1252,10 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + struct sdap_domain *sdom) + { + int ret; +- char *naming_context = NULL; + +- if (!sdom->search_bases +- || !sdom->user_search_bases +- || !sdom->group_search_bases +- || !sdom->netgroup_search_bases +- || !sdom->host_search_bases +- || !sdom->sudo_search_bases +- || !sdom->iphost_search_bases +- || !sdom->ipnetwork_search_bases +- || !sdom->autofs_search_bases) { +- naming_context = get_naming_context(opts->basic, rootdse); +- if (naming_context == NULL) { ++ if (!sdom->naming_context) { ++ sdom->naming_context = get_naming_context(sdom, rootdse); ++ if (sdom->naming_context == NULL) { + DEBUG(SSSDBG_CRIT_FAILURE, "get_naming_context failed.\n"); + + /* This has to be non-fatal, since some servers offer +@@ -1280,7 +1271,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + +@@ -1288,7 +1279,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->user_search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_USER_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + +@@ -1296,7 +1287,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->group_search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_GROUP_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + +@@ -1304,7 +1295,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->netgroup_search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_NETGROUP_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + +@@ -1312,7 +1303,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->host_search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_HOST_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + +@@ -1320,7 +1311,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->sudo_search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_SUDO_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + +@@ -1328,7 +1319,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->service_search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_SERVICE_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + +@@ -1336,7 +1327,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->autofs_search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_AUTOFS_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + +@@ -1344,7 +1335,7 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->iphost_search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_IPHOST_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + +@@ -1352,14 +1343,13 @@ errno_t sdap_set_config_options_with_rootdse(struct sysdb_attrs *rootdse, + if (!sdom->ipnetwork_search_bases) { + ret = sdap_set_search_base(opts, sdom, + SDAP_IPNETWORK_SEARCH_BASE, +- naming_context); ++ sdom->naming_context); + if (ret != EOK) goto done; + } + + ret = EOK; + + done: +- talloc_free(naming_context); + return ret; + } + +diff --git a/src/providers/ldap/sdap.h b/src/providers/ldap/sdap.h +index 161bc5c26..103d50ed4 100644 +--- a/src/providers/ldap/sdap.h ++++ b/src/providers/ldap/sdap.h +@@ -454,6 +454,17 @@ struct sdap_domain { + + char *basedn; + ++ /* The naming_context could be a more reliable source than basedn for the ++ * actual base DN because basedn is set very early from the domain name ++ * given in sssd.conf. Although it is recommended to use the fully ++ * qualified DNS domain name here it is not required. As a result basedn ++ * might not reflect the actual based DN of the LDAP server. Also pure ++ * LDAP server (i.e. not AD or FreeIPA) might use different schemes to set ++ * the base DN which will not be based on the DNS domain of the LDAP ++ * server. naming_context might be NULL even after connection to an LDAP ++ * server. */ ++ char *naming_context; ++ + struct sdap_search_base **search_bases; + struct sdap_search_base **user_search_bases; + struct sdap_search_base **group_search_bases; +-- +2.41.0 + diff --git a/0004-pam-fix-SC-auth-with-multiple-certs-and-missing-logi.patch b/0004-pam-fix-SC-auth-with-multiple-certs-and-missing-logi.patch new file mode 100644 index 0000000..7ba9ba5 --- /dev/null +++ b/0004-pam-fix-SC-auth-with-multiple-certs-and-missing-logi.patch @@ -0,0 +1,233 @@ +From 50077c3255177fe1b01837fbe31a7f8fd47dee74 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Thu, 18 Jan 2024 13:08:17 +0100 +Subject: [PATCH] pam: fix SC auth with multiple certs and missing login name + +While introducing the local_auth_policy option a quite specific use-case +was not covered correctly. If there are multiple matching certificates +on the Smartcard, 'local_auth_policy = only' is set and GDM's Smartcard +mode was used for login, i.e. there is no user name given and the user +has to be derived from the certificate used for login, authentication +failed. The main reason for the failure is that in this case the +Smartcard interaction and the user mapping has to be done first to +determine the user before local_auth_policy is evaluated. As a result +when checking if the authentication can be finished the request was in +an unexpected state because the indicator for local Smartcard +authentication was not enabled. + +Resolves: https://github.com/SSSD/sssd/issues/7109 + +Reviewed-by: Justin Stephenson +Reviewed-by: Scott Poore +(cherry picked from commit 44ec3e4638b0c6f7f45a3390a28c2e8745d52bc3) +--- + src/responder/pam/pamsrv.h | 10 ++++ + src/responder/pam/pamsrv_cmd.c | 17 +++++-- + src/tests/intg/Makefile.am | 2 + + src/tests/intg/test_pam_responder.py | 74 +++++++++++++++++++++++++++- + 4 files changed, 96 insertions(+), 7 deletions(-) + +diff --git a/src/responder/pam/pamsrv.h b/src/responder/pam/pamsrv.h +index 7013a8edd..618836189 100644 +--- a/src/responder/pam/pamsrv.h ++++ b/src/responder/pam/pamsrv.h +@@ -93,7 +93,17 @@ struct pam_auth_req { + struct ldb_message *user_obj; + struct cert_auth_info *cert_list; + struct cert_auth_info *current_cert; ++ /* Switched to 'true' if the backend indicates that it cannot handle ++ * Smartcard authentication, but Smartcard authentication is ++ * possible and local Smartcard authentication is allowed. */ + bool cert_auth_local; ++ /* Switched to 'true' if authentication (not pre-authentication) was ++ * started without a login name and the name had to be lookup up with the ++ * certificate used for authentication. Since reading the certificate from ++ * the Smartcard already involves the PIN validation in this case there ++ * would be no need for an additional Smartcard interaction if only local ++ * Smartcard authentication is possible. */ ++ bool initial_cert_auth_successful; + + bool passkey_data_exists; + uint32_t client_id_num; +diff --git a/src/responder/pam/pamsrv_cmd.c b/src/responder/pam/pamsrv_cmd.c +index c23ea7ba4..a7c181733 100644 +--- a/src/responder/pam/pamsrv_cmd.c ++++ b/src/responder/pam/pamsrv_cmd.c +@@ -2200,8 +2200,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + ret = ENOENT; + goto done; + } +- +- if (cert_count > 1) { ++ /* Multiple certificates are only expected during pre-auth */ ++ if (cert_count > 1 && preq->pd->cmd == SSS_PAM_PREAUTH) { + for (preq->current_cert = preq->cert_list; + preq->current_cert != NULL; + preq->current_cert = sss_cai_get_next(preq->current_cert)) { +@@ -2285,7 +2285,9 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + } + + /* If logon_name was not given during authentication add a +- * SSS_PAM_CERT_INFO message to send the name to the caller. */ ++ * SSS_PAM_CERT_INFO message to send the name to the caller. ++ * Additionally initial_cert_auth_successful is set to ++ * indicate that the user is already authenticated. */ + if (preq->pd->cmd == SSS_PAM_AUTHENTICATE + && preq->pd->logon_name == NULL) { + ret = add_pam_cert_response(preq->pd, +@@ -2297,6 +2299,8 @@ static void pam_forwarder_lookup_by_cert_done(struct tevent_req *req) + preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL; + goto done; + } ++ ++ preq->initial_cert_auth_successful = true; + } + + /* cert_user will be returned to the PAM client as user name, so +@@ -2851,12 +2855,15 @@ static void pam_dom_forwarder(struct pam_auth_req *preq) + if (found) { + if (local_policy != NULL && strcasecmp(local_policy, "only") == 0) { + talloc_free(tmp_ctx); +- DEBUG(SSSDBG_IMPORTANT_INFO, "Local auth only set, skipping online auth\n"); ++ DEBUG(SSSDBG_IMPORTANT_INFO, ++ "Local auth only set and matching certificate was found, " ++ "skipping online auth\n"); + if (preq->pd->cmd == SSS_PAM_PREAUTH) { + preq->pd->pam_status = PAM_SUCCESS; + } else if (preq->pd->cmd == SSS_PAM_AUTHENTICATE + && IS_SC_AUTHTOK(preq->pd->authtok) +- && preq->cert_auth_local) { ++ && (preq->cert_auth_local ++ || preq->initial_cert_auth_successful)) { + preq->pd->pam_status = PAM_SUCCESS; + preq->callback = pam_reply; + } +diff --git a/src/tests/intg/Makefile.am b/src/tests/intg/Makefile.am +index 3866d3ca6..0cfd268dc 100644 +--- a/src/tests/intg/Makefile.am ++++ b/src/tests/intg/Makefile.am +@@ -199,6 +199,7 @@ clean-local: + + PAM_CERT_DB_PATH="$(abs_builddir)/../test_CA/SSSD_test_CA.pem" + SOFTHSM2_CONF="$(abs_builddir)/../test_CA/softhsm2_one.conf" ++SOFTHSM2_TWO_CONF="$(abs_builddir)/../test_CA/softhsm2_two.conf" + + intgcheck-installed: config.py passwd group pam_sss_service pam_sss_alt_service pam_sss_sc_required pam_sss_try_sc pam_sss_allow_missing_name pam_sss_domains sss_netgroup_thread_test + pipepath="$(DESTDIR)$(pipepath)"; \ +@@ -233,6 +234,7 @@ intgcheck-installed: config.py passwd group pam_sss_service pam_sss_alt_service + PAM_CERT_DB_PATH=$(PAM_CERT_DB_PATH) \ + ABS_SRCDIR=$(abs_srcdir) \ + SOFTHSM2_CONF=$(SOFTHSM2_CONF) \ ++ SOFTHSM2_TWO_CONF=$(SOFTHSM2_TWO_CONF) \ + KCM_RENEW=$(KCM_RENEW) \ + FILES_PROVIDER=$(FILES_PROVIDER) \ + DBUS_SOCK_DIR="$(DESTDIR)$(runstatedir)/dbus/" \ +diff --git a/src/tests/intg/test_pam_responder.py b/src/tests/intg/test_pam_responder.py +index 1fc3937e6..0fbf8065e 100644 +--- a/src/tests/intg/test_pam_responder.py ++++ b/src/tests/intg/test_pam_responder.py +@@ -168,7 +168,7 @@ def format_pam_cert_auth_conf(config, provider): + {provider.p} + + [certmap/auth_only/user1] +- matchrule = .*CN=SSSD test cert 0001.* ++ matchrule = .*CN=SSSD test cert 000[12].* + """).format(**locals()) + + +@@ -201,7 +201,7 @@ def format_pam_cert_auth_conf_name_format(config, provider): + {provider.p} + + [certmap/auth_only/user1] +- matchrule = .*CN=SSSD test cert 0001.* ++ matchrule = .*CN=SSSD test cert 000[12].* + """).format(**locals()) + + +@@ -380,6 +380,28 @@ def simple_pam_cert_auth_no_cert(request, passwd_ops_setup): + return None + + ++@pytest.fixture ++def simple_pam_cert_auth_two_certs(request, passwd_ops_setup): ++ """Setup SSSD with pam_cert_auth=True""" ++ config.PAM_CERT_DB_PATH = os.environ['PAM_CERT_DB_PATH'] ++ ++ old_softhsm2_conf = os.environ['SOFTHSM2_CONF'] ++ softhsm2_two_conf = os.environ['SOFTHSM2_TWO_CONF'] ++ os.environ['SOFTHSM2_CONF'] = softhsm2_two_conf ++ ++ conf = format_pam_cert_auth_conf(config, provider_switch(request.param)) ++ create_conf_fixture(request, conf) ++ create_sssd_fixture(request) ++ ++ os.environ['SOFTHSM2_CONF'] = old_softhsm2_conf ++ ++ passwd_ops_setup.useradd(**USER1) ++ passwd_ops_setup.useradd(**USER2) ++ sync_files_provider(USER2['name']) ++ ++ return None ++ ++ + @pytest.fixture + def simple_pam_cert_auth_name_format(request, passwd_ops_setup): + """Setup SSSD with pam_cert_auth=True and full_name_format""" +@@ -522,6 +544,54 @@ def test_sc_auth(simple_pam_cert_auth, env_for_sssctl): + assert err.find("pam_authenticate for user [user1]: Success") != -1 + + ++@pytest.mark.parametrize('simple_pam_cert_auth_two_certs', provider_list(), indirect=True) ++def test_sc_auth_two(simple_pam_cert_auth_two_certs, env_for_sssctl): ++ ++ sssctl = subprocess.Popen(["sssctl", "user-checks", "user1", ++ "--action=auth", "--service=pam_sss_service"], ++ universal_newlines=True, ++ env=env_for_sssctl, stdin=subprocess.PIPE, ++ stdout=subprocess.PIPE, stderr=subprocess.PIPE) ++ ++ try: ++ out, err = sssctl.communicate(input="2\n123456") ++ except Exception: ++ sssctl.kill() ++ out, err = sssctl.communicate() ++ ++ sssctl.stdin.close() ++ sssctl.stdout.close() ++ ++ if sssctl.wait() != 0: ++ raise Exception("sssctl failed") ++ ++ assert err.find("pam_authenticate for user [user1]: Success") != -1 ++ ++ ++@pytest.mark.parametrize('simple_pam_cert_auth_two_certs', provider_list(), indirect=True) ++def test_sc_auth_two_missing_name(simple_pam_cert_auth_two_certs, env_for_sssctl): ++ ++ sssctl = subprocess.Popen(["sssctl", "user-checks", "", ++ "--action=auth", "--service=pam_sss_allow_missing_name"], ++ universal_newlines=True, ++ env=env_for_sssctl, stdin=subprocess.PIPE, ++ stdout=subprocess.PIPE, stderr=subprocess.PIPE) ++ ++ try: ++ out, err = sssctl.communicate(input="2\n123456") ++ except Exception: ++ sssctl.kill() ++ out, err = sssctl.communicate() ++ ++ sssctl.stdin.close() ++ sssctl.stdout.close() ++ ++ if sssctl.wait() != 0: ++ raise Exception("sssctl failed") ++ ++ assert err.find("pam_authenticate for user [user1]: Success") != -1 ++ ++ + @pytest.mark.parametrize('simple_pam_cert_auth', ['proxy_password'], indirect=True) + def test_sc_proxy_password_fallback(simple_pam_cert_auth, env_for_sssctl): + """ +-- +2.41.0 + diff --git a/sssd.spec b/sssd.spec index ccdd569..147e334 100644 --- a/sssd.spec +++ b/sssd.spec @@ -27,14 +27,17 @@ Name: sssd Version: 2.9.4 -Release: 1%{?dist} +Release: 2%{?dist} Summary: System Security Services Daemon License: GPLv3+ URL: https://github.com/SSSD/sssd/ Source0: https://github.com/SSSD/sssd/releases/download/%{version}/sssd-%{version}.tar.gz ### Patches ### -# Patch0001: +Patch0001: 0001-sssd-adding-mail-as-case-insensitive.patch +Patch0002: 0002-sdap-add-search_bases-option-to-groups_by_user_send.patch +Patch0003: 0003-sdap-add-naming_context-as-new-member-of-struct-sdap.patch +Patch0004: 0004-pam-fix-SC-auth-with-multiple-certs-and-missing-logi.patch ### Dependencies ### @@ -1084,6 +1087,11 @@ fi %systemd_postun_with_restart sssd.service %changelog +* Mon Feb 12 2024 Alexey Tikhonov - 2.9.4-2 +- Resolves: RHEL-12503 - AD users are unable to log in due to case sensitivity of user because the domain is found as an alias to the email address. +- Resolves: RHEL-22288 - ssh pubkey stored in ldap/AD no longer works to authenticate via sssd +- Resolves: RHEL-22194 - gdm smartcard login fails with sssd-2.9.3 in case of multiple identities + * Fri Jan 12 2024 Alexey Tikhonov - 2.9.4-1 - Resolves: RHEL-2632 - Rebase SSSD for RHEL 9.4 - Resolves: RHEL-18395 - latest sssd breaks logging in via XDMCP for LDAP/Kerberos users