diff --git a/modules/pam_faillock/pam_faillock.c b/modules/pam_faillock/pam_faillock.c index 8153638..d71e781 100644 --- a/modules/pam_faillock/pam_faillock.c +++ b/modules/pam_faillock/pam_faillock.c @@ -84,6 +84,7 @@ struct options { uid_t uid; int is_admin; uint64_t now; + int time_jumped; }; static void @@ -98,6 +99,7 @@ args_parse(pam_handle_t *pamh, int argc, const char **argv, opts->fail_interval = 900; opts->unlock_time = 600; opts->root_unlock_time = MAX_TIME_INTERVAL+1; + opts->time_jumped = 0; for (i = 0; i < argc; ++i) { @@ -266,8 +268,6 @@ check_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies latest_time = tallies->records[i].time; } - opts->latest_time = latest_time; - failures = 0; for(i = 0; i < tallies->count; i++) { if ((tallies->records[i].status & TALLY_STATUS_VALID) && @@ -278,6 +278,19 @@ check_tally(pam_handle_t *pamh, struct options *opts, struct tally_data *tallies opts->failures = failures; + if (latest_time > opts->now) { + pam_syslog(pamh, LOG_WARNING, "system time jumped about %ld seconds.", (latest_time - opts->now)); + latest_time = opts->now; + opts->time_jumped = 1; + + for(i = 0; i < tallies->count; i++) { + if (tallies->records[i].status & TALLY_STATUS_VALID) + tallies->records[i].time = latest_time; + } + } + + opts->latest_time = latest_time; + if (opts->deny && failures >= opts->deny) { if ((!opts->is_admin && opts->unlock_time && latest_time + opts->unlock_time < opts->now) || (opts->is_admin && opts->root_unlock_time && latest_time + opts->root_unlock_time < opts->now)) { @@ -508,6 +521,10 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags, rv = PAM_IGNORE; /* this return value should be ignored */ write_tally(pamh, &opts, &tallies, &fd); } + if (opts.time_jumped) { + if (update_tally(fd, &tallies) != 0) + rv = PAM_IGNORE; + } break; }