diff --git a/0004-TS_CACHE-never-try-to-upgrade-timestamps-cache.patch b/0004-TS_CACHE-never-try-to-upgrade-timestamps-cache.patch new file mode 100644 index 0000000..60f5383 --- /dev/null +++ b/0004-TS_CACHE-never-try-to-upgrade-timestamps-cache.patch @@ -0,0 +1,208 @@ +From 09b23e78806d8930c3f1b9e411dc8cf464c18998 Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Tue, 16 Jul 2024 13:08:02 +0200 +Subject: [PATCH 4/5] TS_CACHE: never try to upgrade timestamps cache +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +It's easier and more consistent to recreate it instead. + +This is a natural extension of 3b67fc6488ac10ca13561d9032f59951f82203e6 + +Reviewed-by: Alejandro López +Reviewed-by: Sumit Bose +Reviewed-by: Tomáš Halman +(cherry picked from commit fc2a26c306e51b66680aef85aa0d2c41d8049a7f) +--- + src/db/sysdb_init.c | 103 +---------------------------------------- + src/db/sysdb_upgrade.c | 45 ------------------ + 2 files changed, 1 insertion(+), 147 deletions(-) + +diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c +index 38a9cd64a..a1d02d49c 100644 +--- a/src/db/sysdb_init.c ++++ b/src/db/sysdb_init.c +@@ -376,57 +376,6 @@ static errno_t sysdb_cache_create_empty(struct ldb_context *ldb, + return EOK; + } + +-static errno_t sysdb_ts_cache_upgrade(TALLOC_CTX *mem_ctx, +- struct sysdb_ctx *sysdb, +- struct ldb_context *ldb, +- struct sss_domain_info *domain, +- const char *cur_version, +- const char **_new_version) +-{ +- errno_t ret; +- TALLOC_CTX *tmp_ctx; +- const char *version; +- struct ldb_context *save_ldb; +- +- tmp_ctx = talloc_new(NULL); +- if (tmp_ctx == NULL) { +- return ENOMEM; +- } +- +- /* The upgrade process depends on having ldb around, yet the upgrade +- * function shouldn't set the ldb pointer, only the connect function +- * should after it's successful. To avoid hard refactoring, save the +- * ldb pointer here and restore in the 'done' handler +- */ +- save_ldb = sysdb->ldb; +- sysdb->ldb = ldb; +- +- version = talloc_strdup(tmp_ctx, cur_version); +- if (version == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- DEBUG(SSSDBG_CONF_SETTINGS, +- "Upgrading timstamp cache of DB [%s] from version: %s\n", +- domain->name, version); +- +- if (strcmp(version, SYSDB_TS_VERSION_0_1) == 0) { +- ret = sysdb_ts_upgrade_01(sysdb, &version); +- if (ret != EOK) { +- goto done; +- } +- } +- +- ret = EOK; +- +-done: +- sysdb->ldb = save_ldb; +- *_new_version = version; +- talloc_free(tmp_ctx); +- return ret; +-} +- + static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + struct sysdb_dom_upgrade_ctx *upgrade_ctx, +@@ -884,56 +833,6 @@ static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb, + } + + ret = sysdb_ts_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version); +- switch (ret) { +- case ERR_SYSDB_VERSION_TOO_OLD: +- if (upgrade_ctx == NULL) { +- DEBUG(SSSDBG_FATAL_FAILURE, +- "DB version too old [%s], expected [%s] for domain %s!\n", +- version, SYSDB_VERSION, domain->name); +- break; +- } +- +- ret = sysdb_ts_cache_upgrade(tmp_ctx, sysdb, ldb, domain, version, +- &version); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- "Could not upgrade the timestamp ldb file (%d) (%s)\n", +- ret, sss_strerror(ret)); +- break; +- } +- +- /* The version should now match SYSDB_VERSION. +- * If not, it means we didn't match any of the +- * known older versions. The DB might be +- * corrupt or generated by a newer version of +- * SSSD. +- */ +- ret = sysdb_version_check(SYSDB_TS_VERSION, version); +- if (ret == EOK) { +- /* The cache has been upgraded. +- * We need to reopen the LDB to ensure that +- * any changes made above take effect. +- */ +- ret = sysdb_ldb_reconnect(tmp_ctx, +- sysdb->ldb_ts_file, +- LDB_FLG_NOSYNC, +- &ldb); +- if (ret != EOK) { +- DEBUG(SSSDBG_MINOR_FAILURE, +- "Could not reopen the timestamp ldb file (%d) (%s)\n", +- ret, sss_strerror(ret)); +- } +- } +- break; +- case ERR_SYSDB_VERSION_TOO_NEW: +- DEBUG(SSSDBG_MINOR_FAILURE, +- "DB version too new [%s], expected [%s] for domain %s!\n", +- version, SYSDB_TS_VERSION, domain->name); +- break; +- default: +- break; +- } +- + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "The timestamps cache could not be opened. " +@@ -953,7 +852,7 @@ static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb, + ret = sysdb_ts_cache_connect(tmp_ctx, sysdb, domain, &ldb, &version); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, +- "Could not delete the timestamp ldb file (%d) (%s)\n", ++ "sysdb_ts_cache_connect() failed after cache deletion [%d]: %s\n", + ret, sss_strerror(ret)); + } + } +diff --git a/src/db/sysdb_upgrade.c b/src/db/sysdb_upgrade.c +index 328bd2962..37c0007cb 100644 +--- a/src/db/sysdb_upgrade.c ++++ b/src/db/sysdb_upgrade.c +@@ -2774,51 +2774,6 @@ done: + return ret; + } + +-int sysdb_ts_upgrade_01(struct sysdb_ctx *sysdb, const char **ver) +-{ +- struct upgrade_ctx *ctx; +- errno_t ret; +- struct ldb_message *msg = NULL; +- +- ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_TS_VERSION_0_2, &ctx); +- if (ret) { +- return ret; +- } +- +- /* Remove @IDXONE from index */ +- talloc_free(msg); +- msg = ldb_msg_new(ctx); +- if (msg == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- msg->dn = ldb_dn_new(msg, sysdb->ldb, "@INDEXLIST"); +- if (msg->dn == NULL) { +- ret = ENOMEM; +- goto done; +- } +- +- ret = ldb_msg_add_empty(msg, "@IDXONE", LDB_FLAG_MOD_DELETE, NULL); +- 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); +- return ret; +-} +- + /* + * Example template for future upgrades. + * Copy and change version numbers as appropriate. +-- +2.45.2 + diff --git a/0005-SYSDB-remove-index-on-dataExpireTimestamp.patch b/0005-SYSDB-remove-index-on-dataExpireTimestamp.patch new file mode 100644 index 0000000..ee1a718 --- /dev/null +++ b/0005-SYSDB-remove-index-on-dataExpireTimestamp.patch @@ -0,0 +1,147 @@ +From 13e3d0390b9aaf72a855b857857c3cdd6eb6252a Mon Sep 17 00:00:00 2001 +From: Alexey Tikhonov +Date: Fri, 21 Jun 2024 19:09:29 +0200 +Subject: [PATCH 5/5] SYSDB: remove index on `dataExpireTimestamp` +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This index was only used in cleanup tasks that don't run often. +On the other hand, this index is huge and degrades performance of libldb +in general. + +Reviewed-by: Alejandro López +Reviewed-by: Sumit Bose +Reviewed-by: Tomáš Halman +(cherry picked from commit f0d45464cee1d2a6a2719dbffe5bbf6189d0554a) +--- + src/db/sysdb_init.c | 8 ++++++++ + src/db/sysdb_private.h | 9 +++++---- + src/db/sysdb_upgrade.c | 27 +++++++++++++++++++++++++++ + 3 files changed, 40 insertions(+), 4 deletions(-) + +diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c +index a1d02d49c..68b9744dd 100644 +--- a/src/db/sysdb_init.c ++++ b/src/db/sysdb_init.c +@@ -559,6 +559,13 @@ static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx, + } + } + ++ if (strcmp(version, SYSDB_VERSION_0_24) == 0) { ++ ret = sysdb_upgrade_24(sysdb, &version); ++ if (ret != EOK) { ++ goto done; ++ } ++ } ++ + ret = EOK; + done: + sysdb->ldb = save_ldb; +@@ -765,6 +772,7 @@ static int sysdb_domain_cache_connect(struct sysdb_ctx *sysdb, + ret = sysdb_domain_cache_upgrade(tmp_ctx, sysdb, upgrade_ctx, + ldb, domain, version, &version); + if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, "sysdb_domain_cache_upgrade() failed\n"); + goto done; + } + +diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h +index 63f7b5601..b814f97a5 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_25 "0.25" + #define SYSDB_VERSION_0_24 "0.24" + #define SYSDB_VERSION_0_23 "0.23" + #define SYSDB_VERSION_0_22 "0.22" +@@ -48,7 +49,7 @@ + #define SYSDB_VERSION_0_2 "0.2" + #define SYSDB_VERSION_0_1 "0.1" + +-#define SYSDB_VERSION SYSDB_VERSION_0_24 ++#define SYSDB_VERSION SYSDB_VERSION_0_25 + + #define SYSDB_BASE_LDIF \ + "dn: @ATTRIBUTES\n" \ +@@ -72,7 +73,6 @@ + "@IDXATTR: uidNumber\n" \ + "@IDXATTR: gidNumber\n" \ + "@IDXATTR: lastUpdate\n" \ +- "@IDXATTR: dataExpireTimestamp\n" \ + "@IDXATTR: originalDN\n" \ + "@IDXATTR: nameAlias\n" \ + "@IDXATTR: servicePort\n" \ +@@ -104,10 +104,11 @@ + "\n" + + /* The timestamp cache has its own versioning */ ++#define SYSDB_TS_VERSION_0_3 "0.3" + #define SYSDB_TS_VERSION_0_2 "0.2" + #define SYSDB_TS_VERSION_0_1 "0.1" + +-#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_2 ++#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_3 + + #define SYSDB_TS_BASE_LDIF \ + "dn: @ATTRIBUTES\n" \ +@@ -115,7 +116,6 @@ + "\n" \ + "dn: @INDEXLIST\n" \ + "@IDXATTR: lastUpdate\n" \ +- "@IDXATTR: dataExpireTimestamp\n" \ + "\n" \ + "dn: cn=sysdb\n" \ + "cn: sysdb\n" \ +@@ -194,6 +194,7 @@ 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_upgrade_24(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 37c0007cb..b010488ca 100644 +--- a/src/db/sysdb_upgrade.c ++++ b/src/db/sysdb_upgrade.c +@@ -2774,6 +2774,33 @@ done: + return ret; + } + ++int sysdb_upgrade_24(struct sysdb_ctx *sysdb, const char **ver) ++{ ++ struct upgrade_ctx *ctx; ++ errno_t ret; ++ ++ ret = commence_upgrade(sysdb, sysdb->ldb, SYSDB_VERSION_0_25, &ctx); ++ if (ret) { ++ return ret; ++ } ++ ++ ret = sysdb_ldb_mod_index(sysdb, SYSDB_IDX_DELETE, sysdb->ldb, "dataExpireTimestamp"); ++ if (ret == ENOENT) { /*nothing to delete */ ++ ret = EOK; ++ } ++ if (ret != EOK) { ++ DEBUG(SSSDBG_TRACE_FUNC, "sysdb_ldb_mod_index() failed [%d]: %s\n", ++ ret, sss_strerror(ret)); ++ goto done; ++ } ++ ++ ret = update_version(ctx); ++ ++done: ++ ret = finish_upgrade(ret, &ctx, ver); ++ return ret; ++} ++ + /* + * Example template for future upgrades. + * Copy and change version numbers as appropriate. +-- +2.45.2 + diff --git a/0006-pam_sss-fix-passthrow-of-old-authtok-from-another-pa.patch b/0006-pam_sss-fix-passthrow-of-old-authtok-from-another-pa.patch new file mode 100644 index 0000000..43f9e2d --- /dev/null +++ b/0006-pam_sss-fix-passthrow-of-old-authtok-from-another-pa.patch @@ -0,0 +1,115 @@ +From 39cbb8df402f59b4df2442eb291600773e7062cc Mon Sep 17 00:00:00 2001 +From: Petr Mikhalicin +Date: Fri, 10 Nov 2023 15:24:48 +0600 +Subject: [PATCH 6/8] pam_sss: fix passthrow of old authtok from another pam + modules at PAM_PRELIM_CHECK + +pam_sss ignored old authtoks passed from another pam modules + +Resolves: https://github.com/SSSD/sssd/issues/7007 +Resolves: https://github.com/SSSD/sssd/issues/5418 + +Reviewed-by: Iker Pedrosa +Reviewed-by: Sumit Bose +(cherry picked from commit ae6b9163be0a5a8846e8dbf2e0da2c29221781b9) + +Reviewed-by: Sumit Bose +--- + src/sss_client/pam_sss.c | 75 ++++++++++++++++++++++++---------------- + 1 file changed, 45 insertions(+), 30 deletions(-) + +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index 41a528dda..5171e58ec 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -2728,42 +2728,57 @@ static int get_authtok_for_password_change(pam_handle_t *pamh, + exp_data = NULL; + } + +- /* we query for the old password during PAM_PRELIM_CHECK to make +- * pam_sss work e.g. with pam_cracklib */ + if (pam_flags & PAM_PRELIM_CHECK) { +- if ( (getuid() != 0 || exp_data ) && !(flags & PAM_CLI_FLAGS_USE_FIRST_PASS)) { +- if (flags & PAM_CLI_FLAGS_USE_2FA +- || (pi->otp_vendor != NULL && pi->otp_token_id != NULL +- && pi->otp_challenge != NULL)) { +- if (pi->password_prompting) { +- ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "), +- _("Second Factor (optional): ")); +- } else { +- ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "), +- _("Second Factor: ")); +- } ++ if (getuid() == 0 && !exp_data ) ++ return PAM_SUCCESS; ++ ++ if (flags & PAM_CLI_FLAGS_USE_2FA ++ || (pi->otp_vendor != NULL && pi->otp_token_id != NULL ++ && pi->otp_challenge != NULL)) { ++ if (pi->password_prompting) { ++ ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "), ++ _("Second Factor (optional): ")); + } else { +- ret = prompt_password(pamh, pi, _("Current Password: ")); ++ ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "), ++ _("Second Factor: ")); + } +- if (ret != PAM_SUCCESS) { +- D(("failed to get credentials from user")); +- return ret; ++ } else if ((flags & PAM_CLI_FLAGS_USE_FIRST_PASS) ++ && check_authtok_data(pamh, pi) != 0) { ++ if (pi->pamstack_oldauthtok == NULL) { ++ pi->pam_authtok_type = SSS_AUTHTOK_TYPE_EMPTY; ++ pi->pam_authtok = NULL; ++ pi->pam_authtok_size = 0; ++ } else { ++ pi->pam_authtok = strdup(pi->pamstack_oldauthtok); ++ if (pi->pam_authtok == NULL) { ++ D(("strdup failed")); ++ return PAM_BUF_ERR; ++ } ++ pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; ++ pi->pam_authtok_size = strlen(pi->pam_authtok); + } ++ ret = PAM_SUCCESS; ++ } else { ++ ret = prompt_password(pamh, pi, _("Current Password: ")); ++ } ++ if (ret != PAM_SUCCESS) { ++ D(("failed to get credentials from user")); ++ return ret; ++ } + +- ret = pam_set_item(pamh, PAM_OLDAUTHTOK, pi->pam_authtok); +- if (ret != PAM_SUCCESS) { +- D(("Failed to set PAM_OLDAUTHTOK [%s], " +- "oldauthtok may not be available", +- pam_strerror(pamh,ret))); +- return ret; +- } ++ ret = pam_set_item(pamh, PAM_OLDAUTHTOK, pi->pam_authtok); ++ if (ret != PAM_SUCCESS) { ++ D(("Failed to set PAM_OLDAUTHTOK [%s], " ++ "oldauthtok may not be available", ++ pam_strerror(pamh,ret))); ++ return ret; ++ } + +- if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_2FA) { +- ret = keep_authtok_data(pamh, pi); +- if (ret != 0) { +- D(("Failed to store authtok data to pam handle. Password " +- "change might fail.")); +- } ++ if (pi->pam_authtok_type == SSS_AUTHTOK_TYPE_2FA) { ++ ret = keep_authtok_data(pamh, pi); ++ if (ret != 0) { ++ D(("Failed to store authtok data to pam handle. Password " ++ "change might fail.")); + } + } + +-- +2.45.2 + diff --git a/0007-krb5_child-do-not-try-passwords-with-OTP.patch b/0007-krb5_child-do-not-try-passwords-with-OTP.patch new file mode 100644 index 0000000..27c987f --- /dev/null +++ b/0007-krb5_child-do-not-try-passwords-with-OTP.patch @@ -0,0 +1,178 @@ +From ef375cdd67b51d8fb63cae4d3cd40f3a5c2bc173 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Mon, 1 Jul 2024 20:40:30 +0200 +Subject: [PATCH 7/8] krb5_child: do not try passwords with OTP +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +During two-factor authentication (OTP) krb5_child should use use the +dedicated OTP auth types SSS_AUTHTOK_TYPE_2FA and +SSS_AUTHTOK_TYPE_2FA_SINGLE exclusively and should not try password or +other types. + +The special handling needed of ssh under certain conditions are +documented in the code and the man page. + +Resolves: https://github.com/SSSD/sssd/issues/7456 + +Reviewed-by: Justin Stephenson +Reviewed-by: Tomáš Halman +(cherry picked from commit af799964e5fa1264467b49988021c054586eff27) + +Reviewed-by: Sumit Bose +--- + src/man/sssd.conf.5.xml | 11 +++++++++ + src/providers/krb5/krb5_child.c | 11 +-------- + src/sss_client/pam_sss.c | 44 ++++++++++++++++++++++++--------- + 3 files changed, 44 insertions(+), 22 deletions(-) + +diff --git a/src/man/sssd.conf.5.xml b/src/man/sssd.conf.5.xml +index fb86a4e41..8ac1a4418 100644 +--- a/src/man/sssd.conf.5.xml ++++ b/src/man/sssd.conf.5.xml +@@ -4559,6 +4559,17 @@ ldap_user_extra_attrs = phone:telephoneNumber + to log in either only with the password or with both factors + two-step prompting has to be used. + ++ ++ Some clients, such as SSH with ++ 'PasswordAuthentication yes', generate their own prompts ++ and do not use prompts provided by SSSD or other PAM ++ modules. Additionally, for SSH with ++ PasswordAuthentication, if two-factor authentication is ++ available, SSSD expects that the ++ credentials entered by the user at the SSH password prompt ++ will always be the two factors in a single string, even if ++ two-factor authentication is optional. ++ + + + +diff --git a/src/providers/krb5/krb5_child.c b/src/providers/krb5/krb5_child.c +index 494711de9..cb9a9ce73 100644 +--- a/src/providers/krb5/krb5_child.c ++++ b/src/providers/krb5/krb5_child.c +@@ -536,15 +536,6 @@ static krb5_error_code tokeninfo_matches(TALLOC_CTX *mem_ctx, + size_t fa2_len; + + switch (sss_authtok_get_type(auth_tok)) { +- case SSS_AUTHTOK_TYPE_PASSWORD: +- ret = sss_authtok_get_password(auth_tok, &pwd, &len); +- if (ret != EOK) { +- DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_password failed.\n"); +- return ret; +- } +- +- return tokeninfo_matches_pwd(mem_ctx, ti, pwd, len, out_token, out_pin); +- break; + case SSS_AUTHTOK_TYPE_2FA_SINGLE: + ret = sss_authtok_get_2fa_single(auth_tok, &pwd, &len); + if (ret != EOK) { +@@ -569,7 +560,7 @@ static krb5_error_code tokeninfo_matches(TALLOC_CTX *mem_ctx, + "Unsupported authtok type %d\n", sss_authtok_get_type(auth_tok)); + } + +- return EINVAL; ++ return EAGAIN; + } + + static krb5_error_code answer_otp(krb5_context ctx, +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index 5171e58ec..d43bd0f55 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -1656,6 +1656,7 @@ static int prompt_password(pam_handle_t *pamh, struct pam_items *pi, + } + + static int prompt_2fa(pam_handle_t *pamh, struct pam_items *pi, ++ bool second_factor_optional, + const char *prompt_fa1, const char *prompt_fa2) + { + int ret; +@@ -1706,13 +1707,30 @@ static int prompt_2fa(pam_handle_t *pamh, struct pam_items *pi, + goto done; + } + +- if (resp[1].resp == NULL || *(resp[1].resp) == '\0' +- || (pi->pam_service != NULL && strcmp(pi->pam_service, "sshd") == 0 +- && strcmp(resp[0].resp, resp[1].resp) == 0)) { ++ if (resp[1].resp == NULL || *(resp[1].resp) == '\0') { + /* Missing second factor, assume first factor contains combined 2FA +- * credentials. +- * Special handling for SSH with password authentication. Combined +- * 2FA credentials are used but SSH puts them in both responses. */ ++ * credentials if the second factor is not optional. If it is optional ++ * then it is assumed that the first factor contain the password. */ ++ pi->pam_authtok = strndup(resp[0].resp, MAX_AUTHTOK_SIZE); ++ if (pi->pam_authtok == NULL) { ++ D(("strndup failed.")); ++ ret = PAM_BUF_ERR; ++ goto done; ++ } ++ pi->pam_authtok_size = strlen(pi->pam_authtok) + 1; ++ pi->pam_authtok_type = second_factor_optional ++ ? SSS_AUTHTOK_TYPE_PASSWORD ++ : SSS_AUTHTOK_TYPE_2FA_SINGLE; ++ } else if (pi->pam_service != NULL && strcmp(pi->pam_service, "sshd") == 0 ++ && strcmp(resp[0].resp, resp[1].resp) == 0) { ++ /* Special handling for SSH with password authentication (ssh's ++ * 'PasswordAuthentication' option. In this mode the ssh client ++ * directly prompts the user for a password and the prompts we are ++ * sending are ignored. Since we send two prompts ssh * will create two ++ * response as well with the same content. We assume that the combined ++ * 2FA credentials are used even if the second factor is optional ++ * because there is no indication about the intention of the user. As a ++ * result we prefer the more secure variant. */ + + pi->pam_authtok = strndup(resp[0].resp, MAX_AUTHTOK_SIZE); + if (pi->pam_authtok == NULL) { +@@ -1721,7 +1739,7 @@ static int prompt_2fa(pam_handle_t *pamh, struct pam_items *pi, + goto done; + } + pi->pam_authtok_size = strlen(pi->pam_authtok) + 1; +- pi->pam_authtok_type = SSS_AUTHTOK_TYPE_PASSWORD; ++ pi->pam_authtok_type = SSS_AUTHTOK_TYPE_2FA_SINGLE; + } else { + + ret = sss_auth_pack_2fa_blob(resp[0].resp, 0, resp[1].resp, 0, NULL, 0, +@@ -2487,7 +2505,7 @@ static int prompt_by_config(pam_handle_t *pamh, struct pam_items *pi) + ret = prompt_password(pamh, pi, pc_get_password_prompt(pi->pc[c])); + break; + case PC_TYPE_2FA: +- ret = prompt_2fa(pamh, pi, pc_get_2fa_1st_prompt(pi->pc[c]), ++ ret = prompt_2fa(pamh, pi, false, pc_get_2fa_1st_prompt(pi->pc[c]), + pc_get_2fa_2nd_prompt(pi->pc[c])); + break; + case PC_TYPE_2FA_SINGLE: +@@ -2564,10 +2582,10 @@ static int get_authtok_for_authentication(pam_handle_t *pamh, + || (pi->otp_vendor != NULL && pi->otp_token_id != NULL + && pi->otp_challenge != NULL)) { + if (pi->password_prompting) { +- ret = prompt_2fa(pamh, pi, _("First Factor: "), ++ ret = prompt_2fa(pamh, pi, true, _("First Factor: "), + _("Second Factor (optional): ")); + } else { +- ret = prompt_2fa(pamh, pi, _("First Factor: "), ++ ret = prompt_2fa(pamh, pi, false, _("First Factor: "), + _("Second Factor: ")); + } + } else if (pi->passkey_prompt_pin) { +@@ -2736,10 +2754,12 @@ static int get_authtok_for_password_change(pam_handle_t *pamh, + || (pi->otp_vendor != NULL && pi->otp_token_id != NULL + && pi->otp_challenge != NULL)) { + if (pi->password_prompting) { +- ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "), ++ ret = prompt_2fa(pamh, pi, true, ++ _("First Factor (Current Password): "), + _("Second Factor (optional): ")); + } else { +- ret = prompt_2fa(pamh, pi, _("First Factor (Current Password): "), ++ ret = prompt_2fa(pamh, pi, false, ++ _("First Factor (Current Password): "), + _("Second Factor: ")); + } + } else if ((flags & PAM_CLI_FLAGS_USE_FIRST_PASS) +-- +2.45.2 + diff --git a/0008-pam_sss-add-missing-optional-2nd-factor-handling.patch b/0008-pam_sss-add-missing-optional-2nd-factor-handling.patch new file mode 100644 index 0000000..62c1ec4 --- /dev/null +++ b/0008-pam_sss-add-missing-optional-2nd-factor-handling.patch @@ -0,0 +1,45 @@ +From 7e76396a891b4c704f1db8c71a217f869bef0ec3 Mon Sep 17 00:00:00 2001 +From: Sumit Bose +Date: Fri, 12 Jul 2024 13:46:00 +0200 +Subject: [PATCH 8/8] pam_sss: add missing optional 2nd factor handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This is a follow up to pull-request #7462 and adds the proper handling of +an optional second factor in case the prompting is configured. + +Resolves: https://github.com/SSSD/sssd/issues/7456 + +Reviewed-by: Justin Stephenson +Reviewed-by: Tomáš Halman +(cherry picked from commit 077d2993a1b306e7cfe61618cbd5d03c602572f8) + +Reviewed-by: Sumit Bose +--- + src/sss_client/pam_sss.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/src/sss_client/pam_sss.c b/src/sss_client/pam_sss.c +index d43bd0f55..d1101e16c 100644 +--- a/src/sss_client/pam_sss.c ++++ b/src/sss_client/pam_sss.c +@@ -2505,8 +2505,13 @@ static int prompt_by_config(pam_handle_t *pamh, struct pam_items *pi) + ret = prompt_password(pamh, pi, pc_get_password_prompt(pi->pc[c])); + break; + case PC_TYPE_2FA: +- ret = prompt_2fa(pamh, pi, false, pc_get_2fa_1st_prompt(pi->pc[c]), +- pc_get_2fa_2nd_prompt(pi->pc[c])); ++ if (pi->password_prompting) { ++ ret = prompt_2fa(pamh, pi, true, pc_get_2fa_1st_prompt(pi->pc[c]), ++ pc_get_2fa_2nd_prompt(pi->pc[c])); ++ } else { ++ ret = prompt_2fa(pamh, pi, false, pc_get_2fa_1st_prompt(pi->pc[c]), ++ pc_get_2fa_2nd_prompt(pi->pc[c])); ++ } + break; + case PC_TYPE_2FA_SINGLE: + ret = prompt_2fa_single(pamh, pi, +-- +2.45.2 + diff --git a/sssd.spec b/sssd.spec index 1a9775c..fa50f47 100644 --- a/sssd.spec +++ b/sssd.spec @@ -27,7 +27,7 @@ Name: sssd Version: 2.9.5 -Release: 3%{?dist} +Release: 4%{?dist} Summary: System Security Services Daemon License: GPLv3+ URL: https://github.com/SSSD/sssd/ @@ -37,6 +37,11 @@ Source0: https://github.com/SSSD/sssd/releases/download/%{version}/sssd-%{versio Patch0001: 0001-spec-change-passkey_child-owner.patch Patch0002: 0002-sysdb-do-not-fail-to-add-non-posix-user-to-MPG-domai.patch Patch0003: 0003-ad-use-right-memory-context-in-GPO-code.patch +Patch0004: 0004-TS_CACHE-never-try-to-upgrade-timestamps-cache.patch +Patch0005: 0005-SYSDB-remove-index-on-dataExpireTimestamp.patch +Patch0006: 0006-pam_sss-fix-passthrow-of-old-authtok-from-another-pa.patch +Patch0007: 0007-krb5_child-do-not-try-passwords-with-OTP.patch +Patch0008: 0008-pam_sss-add-missing-optional-2nd-factor-handling.patch ### Dependencies ### @@ -1086,6 +1091,10 @@ fi %systemd_postun_with_restart sssd.service %changelog +* Thu Jul 18 2024 Alexey Tikhonov - 2.9.5-4 +- Resolves: RHEL-49711 - SYSDB: remove index on dataExpireTimestamp +- Resolves: RHEL-49811 - 2FA is being enforced after upgrading 2.9.1->2.9.4 + * Mon Jul 8 2024 Alexey Tikhonov - 2.9.5-3 - Resolves: RHEL-40742 - passkey_child with wrong owner