diff options
Diffstat (limited to 'modules/pam_lastlog/pam_lastlog.c')
-rw-r--r-- | modules/pam_lastlog/pam_lastlog.c | 58 |
1 files changed, 37 insertions, 21 deletions
diff --git a/modules/pam_lastlog/pam_lastlog.c b/modules/pam_lastlog/pam_lastlog.c index abd048df..ec515f56 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 <security/pam_modules.h> #include <security/_pam_macros.h> @@ -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, @@ -358,11 +366,11 @@ last_login_read(pam_handle_t *pamh, int announce, int last_fd, uid_t uid, time_t /* cleanup */ cleanup: - memset(&last_login, 0, sizeof(last_login)); - _pam_overwrite(date); - _pam_overwrite(host); + pam_overwrite_object(&last_login); + pam_overwrite_string(date); + pam_overwrite_string(host); _pam_drop(host); - _pam_overwrite(line); + pam_overwrite_string(line); _pam_drop(line); return retval; @@ -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); } /* @@ -486,7 +502,7 @@ last_login_write(pam_handle_t *pamh, int announce, int last_fd, } /* cleanup */ - memset(&last_login, 0, sizeof(last_login)); + pam_overwrite_object(&last_login); return retval; } @@ -573,12 +589,12 @@ last_login_failed(pam_handle_t *pamh, int announce, const char *user, time_t llt time_t lf_time; lf_time = utuser.ut_tv.tv_sec; - tm = localtime_r (&lf_time, &tm_buf); - strftime (the_time, sizeof (the_time), - /* TRANSLATORS: "strftime options for date of last login" */ - _(" %a %b %e %H:%M:%S %Z %Y"), tm); - - date = the_time; + if ((tm = localtime_r (&lf_time, &tm_buf)) != NULL) { + strftime (the_time, sizeof (the_time), + /* TRANSLATORS: "strftime options for date of last login" */ + _(" %a %b %e %H:%M:%S %Z %Y"), tm); + date = the_time; + } } /* we want & have the host? */ |