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.
This commit is contained in:
Matthew Dillon 1998-12-13 01:53:50 +00:00
parent 0e31b6b580
commit be648216c6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=41712
2 changed files with 43 additions and 6 deletions

View File

@ -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 .

View File

@ -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 <sys/param.h>
@ -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);
}