SUMMARY : passwd update problem

From: G.ROBERTSON (sys013@aberdeen.ac.uk)
Date: Wed Oct 16 1991 - 16:06:31 CDT


Recently I wrote....
..
..
> It appeared that the frequent updates to the passwd file on the NIS master
> server caused chaos on the other systems. Most people trying to log in got
> hung. Some users already logged in complained that some software was either
> hanging up completely or exhausting their patience. Some said that they
> apparently called the passwd command successfully, only to find that their
> old passwords still prevailed. Everyone within reach of a telephone complained
> that the systems were running very slowly.
..
..
> It was almost as if the NIS map was being ignored and login and
> other software were attempting to access the passwd file directly.
>
..
..
> I believe I had a hint from this list some time ago that there is a way of
> locking the passwd file for such maintenance work by creating a file with
> an appropriate name for the duration.
>
> We're running 4.1.1.
>

I got lots of replies, which have pinpointed two problem areas:

        a) Dont update the passwd file without lacking it properly
        b) Prevent simultaneous attempts at 'make'ing the passwd NIS map

Chris Rabson pointed out that when running NIS, its no good using /etc/ptmp
as the lock file. You must use

        <the passwd file name>.ptmp

in our case /var/etc/passwd.ptmp.

James P. Dougal provided a script to properly arrange such locking.

Nicky@ca.concordia(see below) provided a 'C' program to carefully apply
a lock, and a script to do this for the passwd file.

Joel L. Seber suggested changing the call in rc.local so that when users
call passwd, it doesn't result in a 'make' of the NIS map, and to use
cron to make the NIS map.

John Stewart pointed out that simultaneous invocations of makedbm are possible
and can result in all sorts of chaos, and also recommended 'make'ing the NIS
map from cron.

----------------------------------------------------------------------------
My original message:

Last week was start of our academic year. We tried to automate the
registration of new users by providing our secretarial staff with "simple"
shell-scripts to do the various jobs concerned. One of the jobs is to
make password file entries. This appeared to create lots of problems.
We run a (mainly) timesharing service on 2 x 4/470's and a 4/490. One of the
4/470's is the NIS master server, the others are slave servers.
It appeared that the frequent updates to the passwd file on the NIS master
server caused chaos on the other systems. Most people trying to log in got
hung. Some users already logged in complained that some software was either
hanging up completely or exhausting their patience. Some said that they
apparently called the passwd command successfully, only to find that their
old passwords still prevailed. Everyone within reach of a telephone complained
that the systems were running very slowly.
..
..
..
I believe I had a hint from this list some time ago that there is a way of
locking the passwd file for such maintenance work by creating a file with
an appropriate name for the duration.

We're running 4.1.1.

-------------------------------------------------------------------------
Some details from replies follow...

From: Ace Stewart <jstewart@edu.syr.cns.zookeeper>

Oh the joys, someone else with our problem -- the NIS master and
slave, password problems abound. Here was our situation, and with the
LISA conference, our final solution.
..
..
Anyhow, everytime one of our slaves had a password change, it would
execute the makedbm. If multiple hits occurred within a short time,
those hits would actually try to override each other, since makedbm
began executing twice.

The results were disastrous; with multiple hits came many-a-crash for
the password file -- and then the NIS master would have to push out a
brand new copy. Naturally enough, we had users whose information would
disappear from the NIS password file until a new copy was there, or
that couldn't log in, would lose "themselves" or send email to a
person who no longer existed ... etc.

We final decided to stop running makedbm every time the yppasswd
wanted to update the file, and instead run it at 1am in the morning,
once which inconveniences users but also stops the password file from
being half written at times.

--------------------------------------------------------------------

From: "Joel L. Seber ... CH210" <JLS2013@EARN.TNTECH>
 
I have experienced the same problem. The problem is that the yppasswdd is
being overloaded, as you expected. Here is my solution in two steps:
 
1) Instead of running the yp password daemon (yppasswdd) as installed by
   suninstall, I changed it in rc.local from:
 
   /usr/etc/rpc.yppasswdd /etc/passwd -m passwd DIR=/etc
 
   to read:
 
   /usr/etc/rpc.yppasswdd /etc/passwd
 
   to prohibit a ypmake whenever someone changed their password.
 
2) In cron, make an entry similiar to this (it should all be one long line):
 
   0,5,10,15,20,25,30,35,40,45,50,55 7,8,9,10,11,12,13,14,15,16,
   17,18,19,20,21,22,23 * * * ( cd /var/yp ; make all ) >/dev/null
 
   This will cause a ypmake every 5 minutes, thereby reducing the strain on
   the yp server. The only restriction is that your users must not log out
   and back in until 5 minutes has passed. Otherwise, the ypmake has not
   occurred and their system will lock.

jls2013@tntech.bitnet |

--------------------------------------------------------------------

From: Christopher RABSON <albion@ca.mcgill.cs.milo>

..
..
        From what we have been able to determine, 'rpc.yppasswdd' creates a
        lock-file 'passwd.ptmp' in the same directory as the NIS 'passwd'
        file. We have a utility called 'viyp` that we use to edit the
        NIS password file when necessary, and it seems to prevent the kinds
        of problems that you are seeing. It basically works on the same
        priciple as 'vipw', but also does a 'make' on the password file.
        The person who wrote it is Bill Heelan (wheelan@cs.mcgill.ca) if
        you are interested.

------------------------------------------------------------------------------

From: nicky@ca.concordia.davinci

I was looking into the same problem last year. I found some help
from Bill Heelan at McGill University here in Montreal. I hope
this helps. If not, it will at least give you a good starting
point for your own locking mechanism.

There are 2 programs that you may be interested in. First is
lockit.c and finally a vipw.

---CUT HERE--- lockit.c

/*
    This program has only been run under Sun OS 4.1. I make no guarantee
    that this program works on your system -- I haven't seen any problems,
    but you might want to look it over in any case.

                                 - Bill Heelan (wheelan@cs.mcgill.ca)

    Try to create a lock file, possibly trying some number of times.
    If successful return 0 (SUCCESS), otherwise return non-zero, the
    exact value depending on the particular error.

    Usage:

        lockit [-s <secs-to-sleep>] [-t <#-tries>] <lock-file-name>

    where <lock-file-name> is the name of the lock file to try to create.
    If it is not a fully specified path, then it will try to create it in
    the current directory.

    If '-t' is given with an integer value greater than 1, then 'lockit'
    will try to create the file that many times. If '-t' is not specified
    the number of tries defaults to 1.

    '-s' specifies the number of seconds to sleep between tries (if the
    number of tries is greater than one). Its default value is 1.
*/

#include <stdio.h>
#include <errno.h>
#include <sys/file.h>
#include <signal.h>
#include <string.h>

/*
   Return codes.
*/

#define SUCCESS 0
#define F_ERROR 1 /* open returned an error other than EEXISTS */
#define F_EXISTS 2 /* the final open returned EEXISTS */
#define F_MISC 3 /* any other reason it didn't work (e.g. bad arg) */

#define MASK 0660 /* octal file creation mask */

main( ac, av )
    int ac ;
    char *av[] ;
{
    extern char *tail() ;
    extern void usage() ;
    char *lock_file_name ;
    char prog[ 128 ] ;
    int fd ;
    int sleep_time ;
    int tries ;

    sleep_time = 1 ;
    tries = 1 ;
    lock_file_name = (char *)NULL ;

    strcpy( prog, tail( av[0] )) ;

    while( ++av, --ac )
    {
        if( av[0][0] != '-' )
        {
            if( lock_file_name == (char *)NULL )
                lock_file_name = av[0] ;
            else
            {
                fprintf( stderr, "%s: a lock file name has already been
specified.\n",
                         prog ) ;
                usage( prog ) ;
            }
        }
        else
        {
            switch( av[0][1] )
            {
            case 's': /* number of seconds to sleep between tries */

                ++av ;
                if( --ac > 0 )
                {
                    if( sscanf( av[0], "%d", &sleep_time ) != 1 )
                    {
                        fprintf( stderr, "%s: -s requires numeric argument.\n",
                                 prog ) ;
                        usage( prog ) ;
                    }
                    else
                    {
                        if( sleep_time < 0 )
                        {
                            fprintf( stderr, "%s: argument to '-s' must
be non-negative.\n",
                                     prog ) ;
                            exit( F_MISC ) ;
                        }
                    }
                }
                else
                {
                    fprintf( stderr, "%s: -s requires an argument.\n",
                             prog ) ;
                    usage( prog ) ;
                }

                break ;

            case 't': /* number of times to retry */

                ++av ;
                if( --ac > 0 )
                {
                    if( sscanf( av[0], "%d", &tries ) != 1 )
                    {
                        fprintf( stderr, "%s: -t requires numeric argument.\n",
                                 prog ) ;
                        usage( prog ) ;
                    }
                    else
                    {
                        if( tries < 1 )
                        {
                            fprintf( stderr, "%s: argument to '-t' must
be greater than zero.\n",
                                     prog ) ;
                            exit( F_MISC ) ;
                        }
                    }
                }
                else
                {
                    fprintf( stderr, "%s: -t requires an argument.\n",
                             prog ) ;
                    usage( prog ) ;
                }

                break ;

            default:

                fprintf( stderr, "%s: unknown option '%s'.\n", prog, av[0] ) ;
                usage( prog ) ;
            }
        }
    }

    if( lock_file_name == (char *)NULL )
    {
        fprintf( stderr, "%s: a lock-file name must be specified.\n",
                 prog ) ;
        usage( prog ) ;
    }

    /*
        Try to exclusively create the lock file. If requested, try a few
        times.
    */

    umask( 0 ) ;
    if(( fd = open( lock_file_name, O_CREAT | O_EXCL | O_WRONLY, MASK )) != -1 )
    {
        close( fd ) ;
        exit( SUCCESS ) ;
    }
    else
    {
        if( errno != EEXIST )
        {
           perror( prog ) ;
           fprintf( stderr, "%s: error trying to open lock file [%s].\n",
                    prog, lock_file_name ) ;
           exit( F_ERROR ) ;
        }

        while( --tries )
        {
            sleep((unsigned)sleep_time) ;

            if(( fd = open( lock_file_name, O_CREAT | O_EXCL |
O_WRONLY, MASK )) != -1 )
            {
                close( fd ) ;
                exit( SUCCESS ) ;
            }
            else
            {
                if( errno != EEXIST )
                {
                   perror( prog ) ;
                   fprintf( stderr, "%s: error trying to open lock file [%s].\n",
                            prog, lock_file_name ) ;
                   exit( F_ERROR ) ;
                }
            }
        }
    }

    close( fd ) ;
    exit( F_EXISTS ) ;
}

char *tail( path )
    char *path ;
{
    char *p ;

    return (p = strrchr( path, '/' )) == (char *)NULL ? path : ++p ;
}

void usage( prog )
    char *prog ;
{
    fprintf( stderr, "Usage: %s [-t <#-tries>] [-s <secs-to-sleep>]
<lock-file-name>\n",
             prog ) ;
    exit( F_MISC ) ;
}

---CUT HERE--- vipw

#!/bin/sh
#
# A "vipw" for the YP password file.
#
# This program has only been run under Sun OS 4.1. I make no guarantee
# that this program works on your system -- I haven't seen any problems,
# but you might want to look it over in any case.
#
# - Bill Heelan (wheelan@cs.mcgill.ca)
#
#
# This script has only been run under Sun OS 4.1.
#
# 'lockit' is a program that uses open(2) with O_EXCL to create a lock
# file. /usr/socs/etc is where we have it on our system...
#
# /usr/local/bin is where we keep the editor 'jove'.
#
PATH=/usr/socs/etc:/bin:/usr/ucb:/usr/local/bin

YPDIR=/var/etc/`domainname`
YPDB=/var/yp
YPPASSWD=$YPDIR/passwd
YPLOCK=$YPPASSWD.ptmp

rval=0
updated=0
trap "rm -f $YPLOCK ; exit 2" 1 2 3 15
if lockit $YPLOCK ; then
    chmod 644 $YPLOCK
    if cp $YPPASSWD $YPLOCK ; then
        ${EDITOR:-/usr/ucb/vi} $YPLOCK

        echo -n "Update the YP password file? [y|n] "
        read ans
        case $ans in
           Y*|y*)
               mv $YPLOCK $YPPASSWD
               updated=1
               break ;;

           N*|n*)
               echo "YP password file unchanged."
               rm -f $YPLOCK
               break ;;

           *)
               echo "Invalid response -- YP password file unchanged."
               rm -f $YPLOCK
               rval=1
               break ;;
        esac
    else
        echo "Error copying to lock file -- YP password file unchanged."
        rm -f $YPLOCK
        rval=1
    fi
else
    echo "The YP password file is busy ($YPLOCK exists) -- try again later."
    rval=1
fi

if [ $rval = 0 -a $updated = 1 ] ; then
    echo ""
    echo "Making the YP password dbm file."
    (cd $YPDB ; make passwd)
fi
exit $rval

---CUT HERE--- end



This archive was generated by hypermail 2.1.2 : Fri Sep 28 2001 - 23:06:18 CDT