From 3e0b54867e22523cffda3b80e179df89b6d81bcd Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 2 Sep 2020 16:37:42 +0200 Subject: [PATCH] user-record: don't refuse login when last pw change time is in the future The RTC is like just off, it's a weird system state, let's continue without requiring pw change. --- src/home/homed-home.c | 2 +- src/home/pam_systemd_home.c | 5 +++++ src/shared/user-record-show.c | 4 ++++ src/shared/user-record.c | 9 +++++++++ 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/home/homed-home.c b/src/home/homed-home.c index e4757c724a..328ec32fd3 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -1574,7 +1574,7 @@ static int home_may_change_password( assert(h); r = user_record_test_password_change_required(h->record); - if (IN_SET(r, -EKEYREVOKED, -EOWNERDEAD, -EKEYEXPIRED)) + if (IN_SET(r, -EKEYREVOKED, -EOWNERDEAD, -EKEYEXPIRED, -ESTALE)) return 0; /* expired in some form, but changing is allowed */ if (IN_SET(r, -EKEYREJECTED, -EROFS)) return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Expiration settings of account %s do not allow changing of password.", h->user_name); diff --git a/src/home/pam_systemd_home.c b/src/home/pam_systemd_home.c index db182dc999..8fe52f44aa 100644 --- a/src/home/pam_systemd_home.c +++ b/src/home/pam_systemd_home.c @@ -904,6 +904,11 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Password will expire soon, please change."); break; + case -ESTALE: + /* If the system clock is wrong, let's log but continue */ + pam_syslog(handle, LOG_WARNING, "Couldn't check if password change is required, last change is in the future, system clock likely wrong."); + break; + case -EROFS: /* All good, just means the password if we wanted to change we couldn't, but we don't need to */ break; diff --git a/src/shared/user-record-show.c b/src/shared/user-record-show.c index 7839f6c2b8..9046fafcb2 100644 --- a/src/shared/user-record-show.c +++ b/src/shared/user-record-show.c @@ -124,6 +124,10 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) { printf(" Password OK: %schange not permitted%s\n", ansi_highlight_yellow(), ansi_normal()); break; + case -ESTALE: + printf(" Password OK: %slast password change in future%s\n", ansi_highlight_yellow(), ansi_normal()); + break; + default: if (r < 0) { errno = -r; diff --git a/src/shared/user-record.c b/src/shared/user-record.c index e14a8f44cb..4149205b8a 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -2061,6 +2061,7 @@ int user_record_test_password_change_required(UserRecord *h) { -EKEYEXPIRED: Password is about to expire, warn user -ENETDOWN: Record has expiration info but no password change timestamp -EROFS: No password change required nor permitted + -ESTALE: RTC likely incorrect, last password change is in the future 0: No password change required, but permitted */ @@ -2070,6 +2071,14 @@ int user_record_test_password_change_required(UserRecord *h) { n = now(CLOCK_REALTIME); + /* Password change in the future? Then our RTC is likely incorrect */ + if (h->last_password_change_usec != UINT64_MAX && + h->last_password_change_usec > n && + (h->password_change_min_usec != UINT64_MAX || + h->password_change_max_usec != UINT64_MAX || + h->password_change_inactive_usec != UINT64_MAX)) + return -ESTALE; + /* Then, let's check if password changing is currently allowed at all */ if (h->password_change_min_usec != UINT64_MAX) {