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);
(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;
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;
-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
*/
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) {