From 4db40135ef077cff04415e111e2356591a49e08d Mon Sep 17 00:00:00 2001 From: dillon Date: Sun, 13 Dec 1998 01:53:50 +0000 Subject: PR: bin/3478 Have pwd_mkdb lock the source file while rebuilding the database. When called by programs such as vipw, the source file is a temporary file and this does not conflict with the lock on /etc/master.passwd already held by vipw. When run manually, however, master.passwd is typically specified as the argument and the locking prevents other programs from messing with master.passwd during the database rebuild. Also pwd_mkdb uses a blocking exclusive lock as it may be called from a script. The -N option was added to cause pwd_mkdb to get the lock non-blocking and exit with an error if the attempt fails, again useful for scripts. --- usr.sbin/pwd_mkdb/pwd_mkdb.8 | 7 +++++++ usr.sbin/pwd_mkdb/pwd_mkdb.c | 42 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 43 insertions(+), 6 deletions(-) (limited to 'usr.sbin/pwd_mkdb') diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.8 b/usr.sbin/pwd_mkdb/pwd_mkdb.8 index 54abc76..7beecd7 100644 --- a/usr.sbin/pwd_mkdb/pwd_mkdb.8 +++ b/usr.sbin/pwd_mkdb/pwd_mkdb.8 @@ -40,6 +40,7 @@ .Sh SYNOPSIS .Nm pwd_mkdb .Op Fl C +.Op Fl N .Op Fl p .Op Fl d Ar directory .Op Fl s Ar cachesize @@ -67,6 +68,12 @@ The options are as follows: .It Fl C Check if the password file is in the correct format. Do not change, add, or remove any files. +.It Fl N +Tell +.Nm Pwd_mkdb +to exit with an error if it cannot obtain a lock on the file. By default, +we block waiting for a lock on the source file. The lock is held through +the rebuilding of the database. .It Fl p Create a Version 7 style password file and install it into .Pa /etc/passwd . diff --git a/usr.sbin/pwd_mkdb/pwd_mkdb.c b/usr.sbin/pwd_mkdb/pwd_mkdb.c index 9df6680..4c5a518 100644 --- a/usr.sbin/pwd_mkdb/pwd_mkdb.c +++ b/usr.sbin/pwd_mkdb/pwd_mkdb.c @@ -42,7 +42,7 @@ static const char copyright[] = static char sccsid[] = "@(#)pwd_mkdb.c 8.5 (Berkeley) 4/20/94"; #endif static const char rcsid[] = - "$Id: pwd_mkdb.c,v 1.27 1998/09/29 20:01:21 dt Exp $"; + "$Id: pwd_mkdb.c,v 1.28 1998/12/12 16:08:41 foxfair Exp $"; #endif /* not lint */ #include @@ -109,6 +109,7 @@ main(argc, argv) char *username; u_int method, methoduid; int Cflag; + int nblock = 0; Cflag = 0; strcpy(prefix, _PATH_PWD); @@ -133,6 +134,9 @@ main(argc, argv) break; case 'v': /* backward compatible */ break; + case 'N': /* do not wait for lock */ + nblock = LOCK_NB; + break; default: usage(); } @@ -158,9 +162,30 @@ main(argc, argv) (void)umask(0); pname = *argv; - /* Open the original password file */ - if (!(fp = fopen(pname, "r"))) - error(pname); + + /* + * Open and lock the original password file. We have to check + * the hardlink count after we get the lock to handle any potential + * unlink/rename race. + * + * This lock is necessary when someone runs pwd_mkdb manually, directly + * on master.passwd, to handle the case where a user might try to + * change his password while pwd_mkdb is running. + */ + for (;;) { + struct stat st; + + if (!(fp = fopen(pname, "r"))) + error(pname); + if (flock(fileno(fp), LOCK_EX|nblock) < 0) + error("flock"); + if (fstat(fileno(fp), &st) < 0) + error(pname); + if (st.st_nlink != 0) + break; + fclose(fp); + fp = NULL; + } /* check only if password database is valid */ if (Cflag) { @@ -431,8 +456,6 @@ main(argc, argv) /* Set master.passwd permissions, in case caller forgot. */ (void)fchmod(fileno(fp), S_IRUSR|S_IWUSR); - if (fclose(fp) == EOF) - error("close fp"); /* Install as the real password files. */ (void)snprintf(buf, sizeof(buf), "%s/%s.tmp", prefix, _MP_DB); @@ -454,6 +477,13 @@ main(argc, argv) */ (void)snprintf(buf, sizeof(buf), "%s/%s", prefix, _MASTERPASSWD); mv(pname, buf); + + /* + * Close locked password file after rename() + */ + if (fclose(fp) == EOF) + error("close fp"); + exit(0); } -- cgit v1.1