aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modules/pam_lastlog/pam_lastlog.c36
1 files changed, 26 insertions, 10 deletions
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 <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,
@@ -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);
}
/*