summaryrefslogtreecommitdiffstats
path: root/libutil
diff options
context:
space:
mode:
authorMatthew Dillon <dillon@FreeBSD.org>1998-12-13 01:36:45 +0000
committerMatthew Dillon <dillon@FreeBSD.org>1998-12-13 01:36:45 +0000
commitd310991f0b18bc6b9ef554b660ea88170557c76f (patch)
tree6e82f2789dc5a5d7229225a155fc4a54ad237e9a /libutil
parent33ad2c7486da901252c1e70f3f599106573a978b (diff)
downloadpw-darwin-d310991f0b18bc6b9ef554b660ea88170557c76f.tar.gz
pw-darwin-d310991f0b18bc6b9ef554b660ea88170557c76f.tar.zst
pw-darwin-d310991f0b18bc6b9ef554b660ea88170557c76f.zip
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.
Diffstat (limited to 'libutil')
-rw-r--r--libutil/pw_util.c28
1 files changed, 22 insertions, 6 deletions
diff --git a/libutil/pw_util.c b/libutil/pw_util.c
index 8a74fc0..93bf4e1 100644
--- a/libutil/pw_util.c
+++ b/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);
}