From 99ae894df3a3aa57ec1410174bbf65f764fbd9b5 Mon Sep 17 00:00:00 2001 From: dillon Date: Sun, 13 Dec 1998 01:36:45 +0000 Subject: Handle the race condition where vipw may lock a password file which has just been replaced. After our lock succeeds we check if st_nlink is 0 and if it is we close the descriptor and retry our open/lock sequence. --- lib/libutil/pw_util.c | 28 ++++++++++++++++++++++------ usr.sbin/vipw/pw_util.c | 28 ++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 12 deletions(-) diff --git a/lib/libutil/pw_util.c b/lib/libutil/pw_util.c index 8a74fc01..93bf4e1 100644 --- a/lib/libutil/pw_util.c +++ b/lib/libutil/pw_util.c @@ -36,7 +36,7 @@ static const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94"; #endif static const char rcsid[] = - "$Id: pw_util.c,v 1.10 1998/10/13 14:52:33 des Exp $"; + "$Id: pw_util.c,v 1.11 1998/10/20 11:34:11 des Exp $"; #endif /* not lint */ /* @@ -115,11 +115,27 @@ pw_lock() * that users can't get at the encrypted passwords while editing. * Open should allow flock'ing the file; see 4.4BSD. XXX */ - lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); - if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) - err(1, "%s", _PATH_MASTERPASSWD); - if (flock(lockfd, LOCK_EX|LOCK_NB)) - errx(1, "the password db file is busy"); + for (;;) { + struct stat st; + + lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); + if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) + err(1, "%s", _PATH_MASTERPASSWD); + if (flock(lockfd, LOCK_EX|LOCK_NB)) + errx(1, "the password db file is busy"); + + /* + * If the password file was replaced while we were trying to + * get the lock, our hardlink count will be 0 and we have to + * close and retry. + */ + if (fstat(lockfd, &st) < 0) + errx(1, "fstat() failed"); + if (st.st_nlink != 0) + break; + close(lockfd); + lockfd = -1; + } return (lockfd); } diff --git a/usr.sbin/vipw/pw_util.c b/usr.sbin/vipw/pw_util.c index 8a74fc01..93bf4e1 100644 --- a/usr.sbin/vipw/pw_util.c +++ b/usr.sbin/vipw/pw_util.c @@ -36,7 +36,7 @@ static const char sccsid[] = "@(#)pw_util.c 8.3 (Berkeley) 4/2/94"; #endif static const char rcsid[] = - "$Id: pw_util.c,v 1.10 1998/10/13 14:52:33 des Exp $"; + "$Id: pw_util.c,v 1.11 1998/10/20 11:34:11 des Exp $"; #endif /* not lint */ /* @@ -115,11 +115,27 @@ pw_lock() * that users can't get at the encrypted passwords while editing. * Open should allow flock'ing the file; see 4.4BSD. XXX */ - lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); - if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) - err(1, "%s", _PATH_MASTERPASSWD); - if (flock(lockfd, LOCK_EX|LOCK_NB)) - errx(1, "the password db file is busy"); + for (;;) { + struct stat st; + + lockfd = open(_PATH_MASTERPASSWD, O_RDONLY, 0); + if (lockfd < 0 || fcntl(lockfd, F_SETFD, 1) == -1) + err(1, "%s", _PATH_MASTERPASSWD); + if (flock(lockfd, LOCK_EX|LOCK_NB)) + errx(1, "the password db file is busy"); + + /* + * If the password file was replaced while we were trying to + * get the lock, our hardlink count will be 0 and we have to + * close and retry. + */ + if (fstat(lockfd, &st) < 0) + errx(1, "fstat() failed"); + if (st.st_nlink != 0) + break; + close(lockfd); + lockfd = -1; + } return (lockfd); } -- cgit v1.1