From 2e7910e3be93d99e865d9b86c38a1b56e4a95d6e Mon Sep 17 00:00:00 2001 From: Davin Shearer <2205472+scholarsmate@users.noreply.github.com> Date: Thu, 28 Apr 2022 04:18:24 -0400 Subject: pam_lastlog: fix file locking Fixed 2 instances in the pam_lastlog module where file locks were not being enforced when reading and writing last login records. * modules/pam_lastlog/pam_lastlog.c (last_login_write): The write lock failure is fatal after 3 tries. (last_login_read): The read lock failure is non-fatal after 3 tries. It is non-fatal in the read case due to concerns about a possible DoS. --- modules/pam_lastlog/pam_lastlog.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) (limited to 'modules/pam_lastlog') diff --git a/modules/pam_lastlog/pam_lastlog.c b/modules/pam_lastlog/pam_lastlog.c index 121e7560..797a61ce 100644 --- a/modules/pam_lastlog/pam_lastlog.c +++ b/modules/pam_lastlog/pam_lastlog.c @@ -57,14 +57,13 @@ struct lastlog { # define PATH_LOGIN_DEFS "/etc/login.defs" #endif -/* XXX - time before ignoring lock. Is 1 sec enough? */ -#define LASTLOG_IGNORE_LOCK_TIME 1 - #define DEFAULT_HOST "" /* "[no.where]" */ #define DEFAULT_TERM "" /* "tt???" */ #define DEFAULT_INACTIVE_DAYS 90 #define MAX_INACTIVE_DAYS 100000 +#define LOCK_RETRIES 3 /* number of file lock retries */ +#define LOCK_RETRY_DELAY 1 /* seconds to wait between lock attempts */ #include #include @@ -266,6 +265,7 @@ last_login_read(pam_handle_t *pamh, int announce, int last_fd, uid_t uid, time_t { struct flock last_lock; struct lastlog last_login; + int lock_retries = LOCK_RETRIES; int retval = PAM_SUCCESS; char the_time[256]; char *date = NULL; @@ -278,11 +278,19 @@ last_login_read(pam_handle_t *pamh, int announce, int last_fd, uid_t uid, time_t last_lock.l_start = sizeof(last_login) * (off_t) uid; last_lock.l_len = sizeof(last_login); - if (fcntl(last_fd, F_SETLK, &last_lock) < 0) { + while (fcntl(last_fd, F_SETLK, &last_lock) < 0) { + if (0 == --lock_retries) { + /* read lock failed, proceed anyway to avoid possible DoS */ + D(("locking %s failed", _PATH_LASTLOG)); + pam_syslog(pamh, LOG_INFO, + "file %s is locked/read, proceeding anyway", + _PATH_LASTLOG); + break; + } D(("locking %s failed..(waiting a little)", _PATH_LASTLOG)); - pam_syslog(pamh, LOG_WARNING, - "file %s is locked/read", _PATH_LASTLOG); - sleep(LASTLOG_IGNORE_LOCK_TIME); + pam_syslog(pamh, LOG_INFO, + "file %s is locked/read, retrying", _PATH_LASTLOG); + sleep(LOCK_RETRY_DELAY); } if (pam_modutil_read(last_fd, (char *) &last_login, @@ -380,6 +388,7 @@ last_login_write(pam_handle_t *pamh, int announce, int last_fd, int setrlimit_res; struct flock last_lock; struct lastlog last_login; + int lock_retries = LOCK_RETRIES; time_t ll_time; const void *void_remote_host = NULL; const char *remote_host; @@ -426,10 +435,17 @@ last_login_write(pam_handle_t *pamh, int announce, int last_fd, last_lock.l_start = sizeof(last_login) * (off_t) uid; last_lock.l_len = sizeof(last_login); - if (fcntl(last_fd, F_SETLK, &last_lock) < 0) { + while (fcntl(last_fd, F_SETLK, &last_lock) < 0) { + if (0 == --lock_retries) { + D(("locking %s failed", _PATH_LASTLOG)); + pam_syslog(pamh, LOG_ERR, + "file %s is locked/write", _PATH_LASTLOG); + return PAM_SERVICE_ERR; + } D(("locking %s failed..(waiting a little)", _PATH_LASTLOG)); - pam_syslog(pamh, LOG_WARNING, "file %s is locked/write", _PATH_LASTLOG); - sleep(LASTLOG_IGNORE_LOCK_TIME); + pam_syslog(pamh, LOG_INFO, + "file %s is locked/write, retrying", _PATH_LASTLOG); + sleep(LOCK_RETRY_DELAY); } /* -- cgit v1.2.3