Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 15 May 2002 13:58:21 -0400 (EDT)
From:      "Geoffrey C. Speicher" <geoff@sea-incorporated.com>
To:        "Matthew D. Fuller" <fullermd@over-yonder.net>
Cc:        Matt Simerson <freebsd@blockads.com>, freebsd-hackers@freebsd.org
Subject:   Re: bug in pw, freebsd 4.5 [patch]
Message-ID:  <Pine.BSF.4.10.10205151330160.59079-100000@sea-incorporated.com>
In-Reply-To: <Pine.BSF.4.10.10205130919570.52656-100000@sea-incorporated.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, 13 May 2002, Geoffrey C. Speicher wrote:

> On Thu, 2 May 2002, Matthew D. Fuller wrote:
> 
> > I'll see if I can put some time over the next few days into delving into
> > it and at least getting the first step (of making the locking work more
> > usefully) work.
> 
> Hi Matt.  Just wondering if you've made any progress on making pw use a
> lockfile.  Is there anything I can do to help?

OK, I'm answering my own question.  Please review the two patches below
and provide feedback.  They appear to work for me.  Some notes:

 1. The lock isn't very fine-grained.  We grab one giant lock before
    doing any operations at all, and let it go right before we exit.
    The alternative is to lock /etc/master.passwd and /etc/group
    individually, only when they're updated, but I saw no point in going
    that far.

 2. The lockfile is /var/run/pw.lock and it always contains the pid of
    the pw process that most recently grabbed the lock.

 3. The lockfile is never deleted, because doing so seemed to cause a
    race condition between the time the file is closed and unlinked,
    leading to password file corruption again.  If anyone has a solution
    to this, please speak up.

 4. Should this thread be moved to -stable?

 5. To test, backup your /etc/master.passwd and /etc/group, and then try
    something like this, several times with the old pw to verify
    consistent breakage, and then several times with the new pw to verify
    that it doesn't break anymore.

    # in one terminal, run this first
    i=0
    while [ $i -le 1000 ]; do
        pw add user testuser$i
        i=$(($i+1))
    done

    # in another terminal, wait about 10-15 seconds and then run this
    # (or tail -f /etc/master.passwd and run it when testuser500 shows up)
    i=0
    while [ $i -le 500 ]; do
        pw del user testuser$i
        i=$(($i+1))
    done


Geoff


--- pwupd.h.orig        Tue May 14 22:06:37 2002
+++ pwupd.h     Wed May 15 13:35:14 2002
@@ -110,6 +110,12 @@
 #ifndef _GROUP
 #define _GROUP         "group"
 #endif
+#ifndef _PWLOCK
+#define _PWLOCK                "/var/run/pw.lock"
+#endif
+#ifndef _LOCK_FILE_MODE
+#define _LOCK_FILE_MODE        (S_IRUSR | S_IWUSR)
+#endif

 __BEGIN_DECLS
 int addpwent __P((struct passwd * pwd));



--- pw.c.orig   Wed May 15 13:35:21 2002
+++ pw.c        Wed May 15 13:37:53 2002
@@ -98,10 +98,12 @@
 main(int argc, char *argv[])
 {
        int             ch;
+       int             lockfd;
        int             mode = -1;
        int             which = -1;
        char            *config = NULL;
        struct userconf *cnf;
+       char            *pidstr;

        static const char *opts[W_NUM][M_NUM] =
        {
@@ -202,6 +204,17 @@
                errx(EX_NOPERM, "you must be root to run this program");

        /*
+        * Gain exclusive lock before updating any files
+        */
+       lockfd = open(_PWLOCK, O_WRONLY | O_CREAT | O_EXLOCK,
_LOCK_FILE_MODE);
+       if (lockfd == -1)
+               err(EX_UNAVAILABLE, "%s", _PWLOCK);
+
+       ftruncate(lockfd,0);
+       write(lockfd, pidstr, asprintf(&pidstr, "%d", getpid()));
+       free(pidstr);
+
+       /*
         * We should immediately look for the -q 'quiet' switch so that we
         * don't bother with extraneous errors
         */
@@ -226,7 +239,7 @@
                        setgrdir(etcpath);
                }
        }
-
+
        /*
         * Now, let's do the common initialisation
         */
@@ -259,6 +272,12 @@
                                pw_log(cnf, mode, which, "NIS maps
updated");
                }
        }
+
+       /*
+        * Release the lock
+        */
+       close(lockfd);
+
        return ch;
 }



To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.10.10205151330160.59079-100000>