#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# Makefile
# age.c
# config.h
# pwconv.c
# pwent.c
# pwpack.c
# pwunconv.c
# shadow.c
# shadow.h
# This archive created: Fri Nov 9 10:22:06 1990
# By: John F. Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'Makefile'
then
echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
# Copyright 1988,1989,1990, John F. Haugh II
# All rights reserved.
#
# Non-commercial distribution permitted. You must provide this source
# code in any distribution. This notice must remain intact.
#
# %W% %U% - Shadow password system
#
# %W% %U% %G%
#
SHELL = /bin/sh
#
# Set this flag to decide what level of code "get" returns.
# The base USENET release was release 1. It is no longer supported.
# The unreleased version with the utilities added was release 2.
# The unreleased version with database-like file access is release 3.
RELEASE = 3
GFLAGS = -t -r$(RELEASE)
# Define the directory login is copied to. BE VERY CAREFUL!!!
# LOGINDIR = /bin
LOGINDIR = /etc
# Pick your favorite C compiler and tags command
CC = cc
TAGS = ctags
# OS. Currently only BSD and USG are defined. If you don't use BSD,
# USG (System V) is assumed.
OS = -DUSG
# OS = -DBSD
# Do you have to do ranlib? Sorry to hear that ...
RANLIB = ranlib
# RANLIB = echo
# Flags for SCO Xenix/386
CFLAGS = -O -M3 -g $(PWDEF) $(AL64DEF) $(OS)
LIBS = -lcrypt -ldbm
LDFLAGS = -M3 -g
LTFLAGS =
# This should be Slibsec.a for small model, or Llibsec.a for
# large model or whatever. MUST AGREE WITH CFLAGS!!!
LIBSEC = Slibsec.a
# Flags for normal machines
# CFLAGS = -O -g $(PWDEF) $(AL64DEF) $(OS)
# LIBS =
# LDFLAGS = -g
# LIBSEC = libsec.a
# Rules for .L (lint) files
.SUFFIXES: .L
LINT = lint
LINTFLAGS = $(OS)
.c.L:
$(LINT) $(LINTFLAGS) $< > $*.L
LOBJS = lmain.o login.o env.o password.o entry.o valid.o setup.o shell.o age.o \
pwent.o utmp.o sub.o mail.o motd.o log.o shadow.o dialup.o dialchk.o \
ttytype.o failure.o port.o pwpack.o
LSRCS = lmain.c login.c env.c password.c entry.c valid.c setup.c shell.c age.c \
pwent.c utmp.c sub.c mail.c motd.c log.c shadow.c dialup.c dialchk.c \
ttytype.c failure.c port.c pwpack.c
SOBJS = smain.o env.o password.o entry.o suvalid.o susetup.o sushell.o \
pwent.o susub.o mail.o motd.o sulog.o shadow.o suage.o pwpack.o
SSRCS = smain.c env.c password.c entry.c valid.c setup.c shell.c \
pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c
POBJS = pmain.o password.o entry.o valid.o pwage.o pwent.o obscure.o shadow.o \
pwpack.o
PSRCS = pmain.c password.c entry.c valid.c age.c pwent.c obscure.c shadow.c \
pwpack.c
GPSRCS = gpmain.c password.c grent.c
GPOBJS = gpmain.o password.o grent.o
PWOBJS = pwconv.o pwent.o shadow.o pwage.o pwpack.o
PWSRCS = pwconv.c pwent.c shadow.c age.c pwpack.c
PWUNOBJS = pwunconv.o pwent.o shadow.o pwage.o pwpack.o
PWUNSRCS = pwunconv.c pwent.c shadow.c age.c pwpack.c
SULOGOBJS = sulogin.o entry.o env.o password.o pwage.o pwent.o setup.o \
shadow.o shell.o valid.o pwpack.o
SULOGSRCS = sulogin.c entry.c env.c password.c age.c pwent.c setup.c \
shadow.c shell.c valid.c pwpack.c
DBOBJS = mkpasswd.o pwent.o pwpack.o
DBSRCS = mkpasswd.c pwent.c pwpack.c
NGSRCS = newgrp.c shadow.c password.c
NGOBJS = newgrp.o shadow.o password.o
CHFNSRCS = chfn.c pwent.c pwpack.c
CHFNOBJS = chfn.o pwent.o pwpack.o
CHSHSRCS = chsh.c pwent.c pwpack.c
CHSHOBJS = chsh.o pwent.o pwpack.o
CHAGEOBJS = chage.o pwent.o pwpack.o pwage.o shadow.o
CHAGESRCS = chage.c pwent.c pwpack.c age.c shadow.c
ALLSRCS = age.c dialchk.c dialup.c entry.c env.c lmain.c log.c login.c mail.c \
motd.c obscure.c password.c pmain.c pwconv.c pwent.c pwunconv.c \
setup.c shadow.c shell.c smain.c sub.c sulog.c sulogin.c ttytype.c \
utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
chfn.c chsh.c chage.c
FILES1 = README newgrp.c Makefile config.h pwunconv.c obscure.c age.c \
sub.c login.c shell.c lastlog.h
FILES2 = pmain.c port.c lmain.c mkpasswd.c sulogin.c pwpack.c dialup.c \
sulog.c password.c env.c mail.c dialchk.c
FILES3 = chfn.c chsh.c smain.c faillog.c pwconv.c failure.c utmp.c shadow.c \
log.c shadow.h faillog.h
FILES4 = gpmain.c chage.c pwent.c valid.c setup.c entry.c ttytype.c port.h \
grent.c motd.c dialup.h
MAN_1 = chage.1 chfn.1 chsh.1 login.1 passwd.1 su.1
MAN_3 = shadow.3
MAN_4 = faillog.4 passwd.4 porttime.4 shadow.4
MAN_8 = faillog.8 pwconv.8 pwunconv.8 sulogin.8
DOCS = $(MAN_1) $(MAN_3) $(MAN_4) $(MAN_8)
BINS = su login pwconv pwunconv passwd sulogin faillog newgrp gpasswd \
mkpasswd chfn chsh chage
all: $(BINS) $(DOCS)
libsec: shadow.o
ar rv $(LIBSEC) shadow.o
$(RANLIB) $(LIBSEC)
install: all
strip $(BINS)
cp login $(LOGINDIR)/login
cp mkpasswd pwconv pwunconv sulogin /etc
cp su passwd gpasswd faillog newgrp chfn chsh /bin
cp shadow.h /usr/include
chown root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
/bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd
chgrp root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
/bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd
chown bin /bin/faillog /usr/include/shadow.h
chgrp bin /bin/faillog /usr/include/shadow.h
chmod 700 /etc/pwconv /etc/pwunconv /etc/sulogin /etc/mkpasswd
chmod 4711 $(LOGINDIR)/login /bin/su /bin/passwd /bin/gpasswd \
/bin/newgrp /bin/chfn
chmod 711 /bin/faillog
chmod 444 /usr/include/shadow.h
lint: su.lint login.lint pwconv.lint pwunconv.lint passwd.lint sulogin.lint \
faillog.lint newgrp.lint gpasswd.lint mkpasswd.lint chfn.lint \
chsh.lint chage.lint $(ALLSRCS:.c=.L)
tags: $(ALLSRCS)
$(TAGS) $(ALLSRCS)
README: s.README
get -t -r$(RELEASE) s.README
$(DOCS):
get -t -r$(RELEASE) s.$@
login: $(LOBJS)
$(CC) -o login $(LDFLAGS) $(LOBJS) $(LIBS)
login.lint: $(LSRCS)
$(LINT) $(LINTFLAGS) $(LSRCS) > login.lint
su: $(SOBJS)
$(CC) -o su $(LDFLAGS) $(SOBJS) $(LIBS)
su.lint: $(SSRCS)
$(LINT) $(LINTFLAGS) -DSU $(SSRCS) > su.lint
passwd: $(POBJS)
$(CC) -o passwd $(LDFLAGS) $(POBJS) $(LIBS)
passwd.lint: $(PSRCS)
$(LINT) $(LINTFLAGS) -DPASSWD $(PSRCS) > passwd.lint
gpasswd: $(GPOBJS)
$(CC) -o gpasswd $(LDFLAGS) $(GPOBJS) $(LIBS)
gpasswd.lint: $(GPSRCS)
$(LINT) $(LINTFLAGS) $(GPSRCS) > gpasswd.lint
pwconv: $(PWOBJS) config.h
$(CC) -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBS)
pwconv.lint: $(PWSRCS) config.h
$(LINT) $(LINTFLAGS) -DPASSWD $(PWSRCS) > pwconv.lint
pwunconv: $(PWUNOBJS)
$(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBS)
pwunconv.lint: $(PWUNSRCS)
$(LINT) $(LINTFLAGS) -DPASSWD $(PWUNSRCS) > pwunconv.lint
sulogin: $(SULOGOBJS)
$(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBS)
sulogin.lint: $(SULOGSRCS)
$(LINT) $(LINTFLAGS) $(SULOGSRCS) > sulogin.lint
faillog: faillog.o
$(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS)
faillog.lint: faillog.c faillog.h config.h
$(LINT) $(LINTFLAGS) faillog.c > faillog.lint
mkpasswd: $(DBOBJS)
$(CC) -o mkpasswd $(LDFLAGS) $(DBOBJS) $(LIBS)
mkpasswd.lint: $(DBSRCS)
$(LINT) $(LINTFLAGS) $(DBSRCS) > mkpasswd.lint
newgrp: $(NGOBJS)
$(CC) -o newgrp $(LDFLAGS) $(NGOBJS) $(LIBS)
newgrp.lint: $(NGSRCS)
$(LINT) $(LINTFLAGS) $(NGSRCS) > newgrp.lint
chfn: $(CHFNOBJS)
$(CC) -o chfn $(LDFLAGS) $(CHFNOBJS) $(LIBS)
chfn.lint: $(CHFNSRCS)
$(LINT) $(LINTFLAGS) $(CHFNSRCS) > chfn.lint
chsh: $(CHSHOBJS)
$(CC) -o chsh $(LDFLAGS) $(CHSHOBJS) $(LIBS)
chsh.lint: $(CHSHSRCS)
$(LINT) $(LINTFLAGS) $(CHSHSRCS) > chsh.lint
chage: $(CHAGEOBJS)
$(CC) -o chage $(LDFLAGS) $(CHAGEOBJS) $(LIBS)
chage.lint: $(CHAGESRCS)
$(LINT) $(LINTFLAGS) -DPASSWD $(CHAGESRCS) > chage.lint
sushell.c: shell.c
cp shell.c sushell.c
sushell.o: config.h sushell.c
$(CC) -c $(CFLAGS) -DSU sushell.c
susub.c: sub.c
cp sub.c susub.c
susub.o: config.h susub.c
$(CC) -c $(CFLAGS) -DSU susub.c
sulog.o: config.h
susetup.c: setup.c
cp setup.c susetup.c
susetup.o: config.h setup.c
$(CC) -c $(CFLAGS) -DSU susetup.c
suvalid.c: valid.c
cp valid.c suvalid.c
suvalid.o: config.h valid.c
$(CC) -c $(CFLAGS) -DSU suvalid.c
pmain.o: config.h lastlog.h shadow.h
pwage.o: age.c config.h
cp age.c pwage.c
$(CC) -c $(CFLAGS) -DPASSWD pwage.c
rm pwage.c
suage.o: age.c config.h
cp age.c suage.c
$(CC) -c $(CFLAGS) -DSU suage.c
rm suage.c
lmain.o: config.h lastlog.h faillog.h
smain.o: config.h lastlog.h
setup.o: config.h
utmp.o: config.h
mail.o: config.h
motd.o: config.h
age.o: config.h
log.o: config.h lastlog.h
shell.o: config.h
entry.o: config.h shadow.h
shadow.o: shadow.h
dialup.o: dialup.h
dialchk.o: dialup.h config.h
valid.o: config.h
failure.o: faillog.h config.h
faillog.o: faillog.h config.h
pwent.o: config.h
port.o: port.h
newgrp.o: config.h shadow.h
mkpasswd.o: config.h
gpmain.o: config.h
chfn.o: config.h
chsh.o: config.h
chage.o: config.h shadow.h
pwconv.o: config.h shadow.h
pwunconv.o: config.h shadow.h
clean:
-rm -f *.o a.out core npasswd nshadow *.pag *.dir
clobber: clean
-rm -f $(BINS) *.lint *.L sushell.c susetup.c susub.c suvalid.c
nuke: clobber
-for file in * ; do \
if [ -f s.$$file -a ! -f p.$$file ] ; then \
rm -f $$file ;\
fi ;\
done
shar: login.sh.1 login.sh.2 login.sh.3 login.sh.4 login.sh.5
login.sh.1: $(FILES1)
shar -a $(FILES1) > login.sh.1
login.sh.2: $(FILES2)
shar -a $(FILES2) > login.sh.2
login.sh.3: $(FILES3)
shar -a $(FILES3) > login.sh.3
login.sh.4: $(FILES4)
shar -a $(FILES4) > login.sh.4
login.sh.5: $(DOCS)
shar -a $(DOCS) > login.sh.5
SHAR_EOF
fi
if test -f 'age.c'
then
echo shar: "will not over-write existing file 'age.c'"
else
cat << \SHAR_EOF > 'age.c'
/*
* Copyright 1989, 1990, John F. Haugh II
* All rights reserved.
*
* Use, duplication, and disclosure prohibited without
* the express written permission of the author.
*/
#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#include "config.h"
#ifndef lint
static char _sccsid[] = "@(#)age.c 2.6 10:20:04 11/9/90";
#endif
#ifndef PASSWD
extern char *newenvp[];
#endif
#ifndef WARNAGE
#define WARNAGE 10
#endif
time_t time ();
int c64i (c)
char c;
{
if (c == '.')
return (0);
if (c == '/')
return (1);
if (c >= '0' && c <= '9')
return (c - '0' + 2);
if (c >= 'A' && c <= 'Z')
return (c - 'A' + 12);
if (c >= 'a' && c <= 'z')
return (c - 'a' + 38);
else
return (-1);
}
int i64c (i)
int i;
{
if (i < 0)
return ('.');
else if (i > 63)
return ('z');
if (i == 0)
return ('.');
if (i == 1)
return ('/');
if (i >= 2 && i <= 11)
return ('0' - 2 + i);
if (i >= 12 && i <= 37)
return ('A' - 12 + i);
if (i >= 38 && i <= 63)
return ('a' - 38 + i);
return ('\0');
}
#ifdef AGING
#ifdef NEED_AL64
#ifdef PASSWD
char *l64a (l)
long l;
{
static char buf[8];
int i = 0;
if (i < 0L)
return ((char *) 0);
do {
buf[i++] = i64c ((int) (l % 64));
buf[i] = '\0';
} while (l /= 64L, l > 0 && i < 6);
return (buf);
}
#endif
long a64l (s)
char *s;
{
int i;
long value;
long shift = 0;
for (i = 0, value = 0L;i < 6 && *s;s++) {
value += (c64i (*s) << shift);
shift += 6;
}
return (value);
}
#endif
#ifndef PASSWD
void expire (name, last, min, max)
char *name;
long last;
int min;
int max;
{
long clock;
long week;
long expires;
extern int errno;
(void) time (&clock);
clock /= (24L * 60L * 60L);
if (min < 0)
min = 0;
if (max < 0)
max = 10000; /* 10000 is infinity */
if (last <= 0L)
expires = 0L;
else
expires = last + max;
if (max < 10000 && (clock >= expires || min == max)) {
#ifndef SU
printf ("Your password has expired.");
if (max < min) {
puts (" Contact the system administrator.\n");
exit (1);
}
puts (" Choose a new one.\n");
execl ("/bin/passwd", "-passwd", name, (char *) 0);
puts ("Can't execute /bin/passwd");
exit (errno);
#else
printf ("Your password has expired.\n");
#ifdef SULOG
sulog (0);
#endif
exit (1);
#endif
}
}
void agecheck (last, min, max, warn)
long last;
int min;
int max;
int warn;
{
long clock = time ((long *) 0) / (24L * 3600);
long remain;
if (last == 0)
return;
if ((remain = (last + max) - clock) <= warn)
printf ("Your password will expire in %d %s.\n",
remain, remain == 1 ? "day":"days");
}
#endif
#endif
SHAR_EOF
fi
if test -f 'config.h'
then
echo shar: "will not over-write existing file 'config.h'"
else
cat << \SHAR_EOF > 'config.h'
/*
* Copyright 1989, 1990, John F. Haugh II
* All rights reserved.
*
* Use, duplication, and disclosure prohibited without
* the express written permission of the author.
*/
/*
* Configuration file for login.
*
* @(#)config.h 2.6 08:26:28 8/20/90
*/
/*
* Define DIALUP to use dialup password files. Define PORTTIME
* to use the port time restriction file, see port.h for more
* information.
*/
#define DIALUP
#define PORTTIME
/*
* Define SHADOWPWD to use shadow [ unreadable ] password file
*/
#define SHADOWPWD
/*
* Define DOUBLESIZE to use 16 character passwords
*/
#define DOUBLESIZE
/*
* Define OBSCURE to include hard password testing code.
*/
#define OBSCURE
/*
* Define PASSLENGTH to be shortest legal password
*/
#define PASSLENGTH 5
/*
* Define NOBLANK if you want all passwords prompted for, including
* empty ones.
#undef NOBLANK
/*
* Define MAXDAYS to be the default maximum number of days a password
* is valid for when converting to shadow passwords. Define MINDAYS
* to be the minimum number of days before a password may be changed.
* See pwconv.c for more details.
*/
#define MAXDAYS 10000
#define MINDAYS 0
/*
* Define NDEBUG for production versions
*/
#define NDEBUG
/*
* Define HZ if login must set HZ value
*/
#define HZ "HZ=50"
/*
* Define TZ if login must set timezone
*
* The first example sets the variable directly. The
* second example names a file which is read to determine
* the proper value. The file consists of a single line
* of the form 'TZ=zone-name'
*/
/* #define TZ "TZ=CST6CDT" */
#define TZ "/etc/tzname"
/*
* Define the default PATH and SUPATH here. PATH is for non-privileged
* users, SUPATH is for root. The first pair are for real trusting
* systems, the second pair are for the paranoid ...
*/
/* #define PATH "PATH=:/bin:/usr/bin" */
/* #define SUPATH "PATH=:/bin:/usr/bin:/etc" */
#define PATH "PATH=/bin:/usr/bin"
#define SUPATH "PATH=/bin:/usr/bin:/etc"
/*
* Define the mailbox directory
*/
#define MAILDIR "/usr/spool/mail/"
/*
* Define AGING if you want the password aging checks made.
* Define WARNAGE to be the number of days notice a user receives
* of a soon to expire password.
*/
#define AGING
#define WARNAGE 10
/*
* Define MAILCHECK if you want the mailbox checked for new mail
*
* One of two messages are printed - `You have new mail.' or
* `You have mail.'.
*/
#define MAILCHECK
/*
* Define CONSOLE if you want ROOT restricted to a particular terminal.
*
* Use the name of the tty line if you only want a single line, or use
* the name of the file containing the permissible ports if you wish to
* allow root logins on more than one port.
*/
/* #define CONSOLE "console" /* root on /dev/console only */
#define CONSOLE "/etc/consoles" /* check /etc/consoles for a list */
/*
* Define NOLOGINS if you want to be able to deny non-root users logins.
* Logins will not be permitted if this file exists.
*/
#define NOLOGINS "/etc/nologin"
/*
* Define NOUSE if you want to be able to declare accounts which can't
* be logged into. Define NOLOGIN if you want it to be an su-only account.
*/
#define NOUSE "NOUSE"
#define NOLOGIN "NOLOGIN"
/*
* Define MOTD if you want the message of the day (/etc/motd) printed
* at login time.
*/
#define MOTD
/*
* Define HUSHLOGIN if you want the code added to avoid printing the
* motd if a file $HOME/.hushlogin exists. This obviously only matters
* if any of MOTD, MAILCHECK or LASTLOG are #define'd.
*/
#define HUSHLOGIN
/*
* Define LASTLOG if you want a record made of logins in /usr/adm/lastlog.
*/
#define LASTLOG
/*
* Define FAILLOG if you want a record make of failed logins in
* /usr/adm/faillog. See faillog.h for more details. See fail(1L)
* for even still more details ... Also, define FTMP to record utmp
* style records for failed logins. FTMP is the name of a utmp-like
* file. You can use who(1) instead of faillog(L), which is an
* advantage. Define UNKNOWNS if you do want unknown user names
* recorded. This can be a security hole since passwords are often
* entered mistakenly as user names.
*/
#define FAILLOG
#define FTMP "/etc/ftmp"
#define UNKNOWNS
/*
* Define TTYPERM to be the initial terminal permissions. Defining
* as 0600 will not allow messages, 0622 will.
*/
#define TTYPERM 0600
/*
* Define TTYTYPE to the be name of the port to terminal type
* mapping file. This is used to set the environmental variable
* "TERM" to the correct terminal type.
*/
#define TTYTYPE "/etc/ttytype"
/*
* Define QUOTAS if you want the code added in setup.c to support
* file ulimit and nice [ and umask as well ] setting from the password
* file.
*/
#define QUOTAS
/*
* Pick your version of DBM. Only DBM is presently supported, NDBM will
* follow. You must also define the GETPWENT macro below.
*/
#define DBM
/*
* Define file name for sulog. If SULOG is not defined, there will be
* no logging. This is NOT a good idea ... We also define other file
* names.
*/
#define SULOG "/usr/adm/sulog"
#define SUCON "/dev/console"
#define PWDFILE "/etc/passwd"
#define OPWDFILE "/etc/-passwd"
#define NPWDFILE "/etc/npasswd"
#define OSHADOW "/etc/-shadow"
#define NSHADOW "/etc/nshadow"
#define GRPFILE "/etc/group"
#define OGRPFILE "/etc/-group"
#define NGRPFILE "/etc/ngroup"
/*
* Define PWDLOCK to be a locking semaphore for updating the password
* file. GRPLOCK is the same for the group file.
*/
#define PWDLOCK "/etc/.pwdlock"
#define GRPLOCK "/etc/.grplock"
/*
* Wierd stuff follows ...
*
* The following macros exist solely to override stuff ...
* You will probably want to change their values to suit your
* fancy.
*/
#define ERASECHAR '\b'
#define KILLCHAR '\025'
#define UMASK 022
#define ULIMIT (1L<<20) /* Define if your UNIX supports ulimit() */
#define FGETPWENT /* Define if library does not include FGETPWENT */
#define GETPWENT /* Define if you want my GETPWENT(3) routines */
#define NEED_AL64 /* Define if library does not include a64l() */
SHAR_EOF
fi
if test -f 'pwconv.c'
then
echo shar: "will not over-write existing file 'pwconv.c'"
else
cat << \SHAR_EOF > 'pwconv.c'
/*
* Copyright 1989, 1990, John F. Haugh II
* All rights reserved.
*
* Use, duplication, and disclosure prohibited without
* the express written permission of the author.
*/
/*
* pwconv - convert and update shadow password files
*
* Pwconv copies the old password file information to a new shadow
* password file, merging entries from an optional existing shadow
* file.
*
* The new password file is left in npasswd, the new shadow file is
* left in nshadow. Existing shadow entries are copied as is.
* New entries are created with passwords which expire in MAXDAYS days,
* with a last changed date of today, unless password aging
* information was already present. Likewise, the minimum number of
* days before which the password may be changed is controlled by
* MINDAYS. The number of warning days is set to WARNAGE if that
* macro exists. Entries with blank passwordsare not copied to the
* shadow file at all.
*/
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <pwd.h>
#ifndef BSD
#include <string.h>
#else
#define strchr index
#define strrchr rindex
#include <strings.h>
#endif
#include "config.h"
#include "shadow.h"
#ifndef lint
static char _sccsid[] = "@(#)pwconv.c 3.1 08:21:33 11/9/90";
#endif
char buf[BUFSIZ];
long time ();
long a64l ();
int main ()
{
long today;
struct passwd *pw;
struct passwd *sgetpwent ();
FILE *pwd;
FILE *npwd;
FILE *shadow;
struct spwd *spwd;
struct spwd tspwd;
int fd;
char *cp;
if (! (pwd = fopen (PWDFILE, "r"))) {
perror (PWDFILE);
exit (1);
}
unlink ("npasswd");
if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
! (npwd = fdopen (fd, "w"))) {
perror ("npasswd");
exit (1);
}
unlink ("nshadow");
if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
! (shadow = fdopen (fd, "w"))) {
perror ("nshadow");
(void) unlink ("npasswd");
(void) unlink ("nshadow");
exit (1);
}
(void) time (&today);
today /= (24L * 60L * 60L);
while (fgets (buf, BUFSIZ, pwd) == buf) {
if (cp = strrchr (buf, '\n'))
*cp = '\0';
if (buf[0] == '#') { /* comment line */
(void) fprintf (npwd, "%s\n", buf);
continue;
}
if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */
(void) fprintf (npwd, "%s\n", buf);
continue;
}
if (pw->pw_passwd[0] == '\0') { /* no password, skip */
(void) fprintf (npwd, "%s\n", buf);
continue;
}
setspent (); /* rewind old shadow file */
if (spwd = getspnam (pw->pw_name)) {
if (putspent (spwd, shadow)) { /* copy old entry */
perror ("nshadow");
goto error;
}
} else { /* need a new entry. */
tspwd.sp_namp = pw->pw_name;
tspwd.sp_pwdp = pw->pw_passwd;
pw->pw_passwd = "x";
if (pw->pw_age) { /* copy old password age stuff */
if (strlen (pw->pw_age) >= 2) {
tspwd.sp_min = c64i (pw->pw_age[1]);
tspwd.sp_max = c64i (pw->pw_age[0]);
} else {
tspwd.sp_min = tspwd.sp_max = -1;
}
if (strlen (pw->pw_age) == 4)
tspwd.sp_lstchg = a64l (&pw->pw_age[2]);
else
tspwd.sp_lstchg = -1;
/*
* Convert weeks to days
*/
if (tspwd.sp_min != -1)
tspwd.sp_min *= 7;
if (tspwd.sp_max != -1)
tspwd.sp_max *= 7;
if (tspwd.sp_lstchg != -1)
tspwd.sp_lstchg *= 7;
} else { /* fake up new password age stuff */
tspwd.sp_max = MAXDAYS;
tspwd.sp_min = MINDAYS;
tspwd.sp_lstchg = today;
}
#ifdef WARNAGE
tspwd.sp_warn = WARNAGE;
tspwd.sp_inact = tspwd.sp_expire = tspwd.sp_flag = -1;
#else
tspwd.sp_warn = tspwd.sp_inact = tspwd.sp_expire =
tspwd.sp_flag = -1;
#endif
if (putspent (&tspwd, shadow)) { /* output entry */
perror ("nshadow");
goto error;
}
}
(void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:",
pw->pw_name, pw->pw_passwd,
pw->pw_uid, pw->pw_gid,
pw->pw_gecos, pw->pw_dir);
if (fprintf (npwd, "%s\n",
pw->pw_shell ? pw->pw_shell:"") == EOF) {
perror ("npasswd");
goto error;
}
}
endspent ();
if (ferror (npwd) || ferror (shadow)) {
perror ("pwconv");
error:
(void) unlink ("npasswd");
(void) unlink ("nshadow");
exit (1);
}
(void) fclose (pwd);
(void) fclose (npwd);
(void) fclose (shadow);
exit (0);
}
SHAR_EOF
fi
if test -f 'pwent.c'
then
echo shar: "will not over-write existing file 'pwent.c'"
else
cat << \SHAR_EOF > 'pwent.c'
/*
* Copyright 1989, 1990, John F. Haugh II
* All rights reserved.
*
* Use, duplication, and disclosure prohibited without
* the express written permission of the author.
*
* Duplication is permitted for non-commercial [ profit making ]
* purposes provided this and other copyright notices remain
* intact.
*/
#include <stdio.h>
#include <pwd.h>
#include <string.h>
#include "config.h"
#ifdef DBM
#include <dbm.h>
#endif
#ifndef lint
static char _sccsid[] = "@(#)pwent.c 2.4 23:41:33 10/28/90";
#endif
#define SBUFSIZ 64
#define NFIELDS 7
static FILE *pwdfp;
static char pwdbuf[BUFSIZ];
static char *pwdfile = "/etc/passwd";
#ifdef DBM
static int dbmopened;
static int dbmerror;
#endif
static char *pwdfields[NFIELDS];
static struct passwd pwent;
/*
* sgetpwent - convert a string to a (struct passwd)
*
* sgetpwent() parses a string into the parts required for a password
* structure. Strict checking is made for the UID and GID fields and
* presence of the correct number of colons. Any failing tests result
* in a NULL pointer being returned.
*/
struct passwd *sgetpwent (buf)
char *buf;
{
int i;
char *cp;
/*
* Copy the string to a static buffer so the pointers into
* the password structure remain valid.
*/
strncpy (pwdbuf, buf, BUFSIZ);
pwdbuf[BUFSIZ-1] = '\0';
/*
* Save a pointer to the start of each colon separated
* field. The fields are converted into NUL terminated strings.
*/
for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) {
pwdfields[i] = cp;
if (cp = strchr (cp, ':'))
*cp++ = 0;
}
/*
* There must be exactly NFIELDS colon separated fields or
* the entry is invalid. Also, the UID and GID must be non-blank.
*/
if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0')
return 0;
/*
* Each of the fields is converted the appropriate data type
* and the result assigned to the password structure. If the
* UID or GID does not convert to an integer value, a NULL
* pointer is returned.
*/
pwent.pw_name = pwdfields[0];
pwent.pw_passwd = pwdfields[1];
if ((pwent.pw_uid = strtol (pwdfields[2], &cp, 10)) == 0 && *cp)
return 0;
if ((pwent.pw_gid = strtol (pwdfields[3], &cp, 10)) == 0 && *cp)
return 0;
if (cp = strchr (pwent.pw_passwd, ',')) {
pwent.pw_age = cp + 1;
*cp = '\0';
} else
pwent.pw_age = "";
pwent.pw_gecos = pwdfields[4];
pwent.pw_dir = pwdfields[5];
pwent.pw_shell = pwdfields[6];
return (&pwent);
}
#ifdef FGETPWENT
/*
* fgetpwent - get a password file entry from a stream
*
* fgetpwent() reads the next line from a password file formatted stream
* and returns a pointer to the password structure for that line.
*/
struct passwd *fgetpwent (fp)
FILE *fp;
{
char buf[BUFSIZ];
while (fgets (buf, BUFSIZ, fp) != (char *) 0) {
buf[strlen (buf) - 1] = '\0';
return (sgetpwent (buf));
}
return 0;
}
#endif
#ifdef GETPWENT
/*
* endpwent - close a password file
*
* endpwent() closes the password file if open.
*/
int endpwent ()
{
if (pwdfp)
if (fclose (pwdfp))
return -1;
return 0;
}
/*
* getpwent - get a password entry from the password file
*
* getpwent() opens the password file, if not already opened, and reads
* a single entry. NULL is returned if any errors are encountered reading
* the password file.
*/
struct passwd *getpwent ()
{
if (! pwdfp && setpwent ())
return 0;
return fgetpwent (pwdfp);
}
/*
* getpwuid - locate the password entry for a given UID
*
* getpwuid() locates the first password file entry for the given UID.
* If there is a valid DBM file, the DBM files are queried first for
* the entry. Otherwise, a linear search is begun of the password file
* searching for an entry which matches the provided UID.
*/
struct passwd *getpwuid (uid)
int uid;
{
struct passwd *pwd;
#ifdef DBM
datum key;
datum content;
/*
* Attempt to open the DBM files if they have never been opened
* and an error has never been returned.
*/
if (! dbmerror && ! dbmopened) {
char dbmfiles[BUFSIZ];
strcpy (dbmfiles, pwdfile);
strcat (dbmfiles, ".pag");
if (access (dbmfiles, 0) || dbminit (pwdfile))
dbmerror = 1;
else
dbmopened = 1;
}
/*
* If the DBM file are now open, create a key for this UID and
* try to fetch the entry from the database. A matching record
* will be unpacked into a static structure and returned to
* the user.
*/
if (dbmopened) {
pwent.pw_uid = uid;
key.dsize = sizeof pwent.pw_uid;
key.dptr = (char *) &pwent.pw_uid;
content = fetch (key);
if (content.dptr != 0) {
memcpy (pwdbuf, content.dptr, content.dsize);
pw_unpack (pwdbuf, content.dsize, &pwent);
return &pwent;
}
}
#endif
/*
* Rewind the database and begin searching for an entry which
* matches the UID. Return the entry when a match is found.
*/
if (setpwent ())
return 0;
while (pwd = getpwent ())
if (pwd->pw_uid == uid)
return pwd;
return 0;
}
struct passwd *getpwnam (name)
char *name;
{
struct passwd *pwd;
#ifdef DBM
datum key;
datum content;
/*
* Attempt to open the DBM files if they have never been opened
* and an error has never been returned.
*/
if (! dbmerror && ! dbmopened) {
char dbmfiles[BUFSIZ];
strcpy (dbmfiles, pwdfile);
strcat (dbmfiles, ".pag");
if (access (dbmfiles, 0) || dbminit (pwdfile))
dbmerror = 1;
else
dbmopened = 1;
}
/*
* If the DBM file are now open, create a key for this UID and
* try to fetch the entry from the database. A matching record
* will be unpacked into a static structure and returned to
* the user.
*/
if (dbmopened) {
key.dsize = strlen (name);
key.dptr = name;
content = fetch (key);
if (content.dptr != 0) {
memcpy (pwdbuf, content.dptr, content.dsize);
pw_unpack (pwdbuf, content.dsize, &pwent);
return &pwent;
}
}
#endif
/*
* Rewind the database and begin searching for an entry which
* matches the name. Return the entry when a match is found.
*/
if (setpwent ())
return 0;
while (pwd = getpwent ())
if (strcmp (pwd->pw_name, name) == 0)
return pwd;
return 0;
}
/*
* setpwent - open the password file
*
* setpwent() opens the system password file, and the DBM password files
* if they are present. The system password file is rewound if it was
* open already.
*/
int setpwent ()
{
if (! pwdfp) {
if (! (pwdfp = fopen (pwdfile, "r")))
return -1;
} else {
if (fseek (pwdfp, 0L, 0) != 0)
return -1;
}
#ifdef DBM
/*
* Attempt to open the DBM files if they have never been opened
* and an error has never been returned.
*/
if (! dbmerror && ! dbmopened) {
char dbmfiles[BUFSIZ];
strcpy (dbmfiles, pwdfile);
strcat (dbmfiles, ".pag");
if (access (dbmfiles, 0) || dbminit (pwdfile))
dbmerror = 1;
else
dbmopened = 1;
}
#endif
return 0;
}
#endif
SHAR_EOF
fi
if test -f 'pwpack.c'
then
echo shar: "will not over-write existing file 'pwpack.c'"
else
cat << \SHAR_EOF > 'pwpack.c'
/*
* Copyright 1990, John F. Haugh II
* All rights reserved.
*
* Use, duplication, and disclosure prohibited without
* the express written permission of the author.
*
* Duplication is permitted for non-commercial [ profit making ]
* purposes provided this and other copyright notices remain
* intact.
*/
#include <stdio.h>
#include <pwd.h>
#ifdef BSD
#include <strings.h>
#else
#include <string.h>
#endif
#ifndef lint
static char sccsid[] = "@(#)pwpack.c 2.3 23:06:29 8/5/90";
#endif
int pw_pack (passwd, buf)
struct passwd *passwd;
char *buf;
{
char *cp;
cp = buf;
strcpy (cp, passwd->pw_name);
cp += strlen (cp) + 1;
strcpy (cp, passwd->pw_passwd);
if (passwd->pw_age && passwd->pw_age[0]) {
cp += strlen (cp);
*cp++ = ',';
strcpy (cp, passwd->pw_age);
}
cp += strlen (cp) + 1;
memcpy (cp, (void *) &passwd->pw_uid, sizeof passwd->pw_uid);
cp += sizeof passwd->pw_uid;
memcpy (cp, (void *) &passwd->pw_gid, sizeof passwd->pw_gid);
cp += sizeof passwd->pw_gid;
strcpy (cp, passwd->pw_gecos);
cp += strlen (cp) + 1;
strcpy (cp, passwd->pw_dir);
cp += strlen (cp) + 1;
strcpy (cp, passwd->pw_shell);
cp += strlen (cp) + 1;
return cp - buf;
}
int pw_unpack (buf, len, passwd)
char *buf;
int len;
struct passwd *passwd;
{
char *org = buf;
char *cp;
passwd->pw_name = buf;
buf += strlen (buf) + 1;
if (buf - org > len)
return -1;
passwd->pw_passwd = buf;
buf += strlen (buf) + 1;
if (buf - org > len)
return -1;
if (cp = strchr (passwd->pw_passwd, ',')) {
*cp++ = '\0';
passwd->pw_age = cp;
} else
passwd->pw_age = "";
memcpy ((void *) &passwd->pw_uid, (void *) buf, sizeof passwd->pw_uid);
buf += sizeof passwd->pw_uid;
if (buf - org > len)
return -1;
memcpy ((void *) &passwd->pw_gid, (void *) buf, sizeof passwd->pw_gid);
buf += sizeof passwd->pw_gid;
if (buf - org > len)
return -1;
passwd->pw_gecos = buf;
buf += strlen (buf) + 1;
if (buf - org > len)
return -1;
passwd->pw_dir = buf;
buf += strlen (buf) + 1;
if (buf - org > len)
return -1;
passwd->pw_shell = buf;
buf += strlen (buf) + 1;
if (buf - org > len)
return -1;
return 0;
}
SHAR_EOF
fi
if test -f 'pwunconv.c'
then
echo shar: "will not over-write existing file 'pwunconv.c'"
else
cat << \SHAR_EOF > 'pwunconv.c'
/*
* Copyright 1989, 1990, John F. Haugh II
* All rights reserved.
*
* Use, duplication, and disclosure prohibited without
* the express written permission of the author.
*/
/*
* pwunconv - restore old password file from shadow password file.
*
* Pwunconv copies the password file information from the shadow
* password file, merging entries from an optional existing shadow
* file.
*
* The new password file is left in npasswd. There is no new
* shadow file. Password aging information is translated where
* possible.
*/
#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <pwd.h>
#include "config.h"
#include "shadow.h"
#ifndef lint
static char _sccsid[] = "@(#)pwunconv.c 3.1 08:47:18 11/9/90";
#endif
char buf[BUFSIZ];
char *l64a ();
int main ()
{
struct passwd *pw;
struct passwd *sgetpwent ();
FILE *pwd;
FILE *npwd;
struct spwd *spwd;
int fd;
char newage[5];
if (! (pwd = fopen (PWDFILE, "r"))) {
perror (PWDFILE);
return (1);
}
unlink ("npasswd");
if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
! (npwd = fdopen (fd, "w"))) {
perror ("npasswd");
return (1);
}
while (fgets (buf, BUFSIZ, pwd) == buf) {
buf[strlen (buf) - 1] = '\0'; /* remove '\n' character */
if (buf[0] == '#') { /* comment line */
(void) fprintf (npwd, "%s\n", buf);
continue;
}
if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */
(void) fprintf (npwd, "%s\n", buf);
continue;
}
setspent (); /* rewind shadow file */
if (! (spwd = getspnam (pw->pw_name))) {
(void) fprintf (npwd, "%s\n", buf);
continue;
}
pw->pw_passwd = spwd->sp_pwdp;
/*
* Password aging works differently in the two different systems.
* With shadow password files you apparently must have some aging
* information. The maxweeks or minweeks may not map exactly.
* In pwconv we set max == 10000, which is about 30 years. Here
* we have to undo that kludge. So, if maxdays == 10000, no aging
* information is put into the new file. Otherwise, the days are
* converted to weeks and so on.
*/
if (spwd->sp_max > (63*7) && spwd->sp_max < 10000)
spwd->sp_max = (63*7); /* 10000 is infinity this week */
if (spwd->sp_min >= 0 && spwd->sp_min <= 63*7 &&
spwd->sp_max >= 0 && spwd->sp_max <= 63*7) {
if (spwd->sp_lstchg == -1)
spwd->sp_lstchg = clock ((long *) 0) /
(24L*60L*60L);
spwd->sp_max /= 7; /* turn it into weeks */
spwd->sp_min /= 7;
spwd->sp_lstchg /= 7;
strncpy (newage, l64a (spwd->sp_lstchg * (64L*64L) +
spwd->sp_min * (64L) + spwd->sp_max), 5);
pw->pw_age = newage;
} else
pw->pw_age = "";
if (putpwent (pw, npwd)) {
perror (stderr, "pwunconv: write error");
exit (1);
}
}
endspent ();
if (ferror (npwd)) {
perror ("pwunconv");
(void) unlink ("npasswd");
}
(void) fclose (npwd);
(void) fclose (pwd);
return (0);
}
SHAR_EOF
fi
if test -f 'shadow.c'
then
echo shar: "will not over-write existing file 'shadow.c'"
else
cat << \SHAR_EOF > 'shadow.c'
/*
* Copyright 1989, 1990, John F. Haugh II
* All rights reserved.
*
* Use, duplication, and disclosure prohibited without
* the express written permission of the author.
*/
#include "shadow.h"
#include <stdio.h>
#ifndef BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define strchr index
#define strrchr rindex
#endif
#ifndef lint
static char _sccsid[] = "@(#)shadow.c 3.1 08:12:34 11/9/90";
#endif
static FILE *shadow;
#define FIELDS 9
#define OFIELDS 5
void
setspent ()
{
if (shadow)
rewind (shadow);
else
shadow = fopen (SHADOW, "r");
}
void
endspent ()
{
if (shadow)
(void) fclose (shadow);
shadow = (FILE *) 0;
}
struct spwd *
sgetspent (string)
char *string;
{
static char buf[BUFSIZ];
static struct spwd spwd;
char *fields[FIELDS];
char *cp;
char *cpp;
int atoi ();
long atol ();
int i;
strncpy (buf, string, BUFSIZ-1);
buf[BUFSIZ-1] = '\0';
if (cp = strrchr (buf, '\n'))
*cp = '\0';
for (cp = buf, i = 0;*cp && i < FIELDS;i++) {
fields[i] = cp;
while (*cp && *cp != ':')
cp++;
if (*cp)
*cp++ = '\0';
}
if (*cp || (i != FIELDS && i != OFIELDS))
return 0;
spwd.sp_namp = fields[0];
spwd.sp_pwdp = fields[1];
if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp)
if (fields[2][0] == '\0')
spwd.sp_lstchg = -1;
else
return 0;
if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp)
if (fields[3][0] == '\0')
spwd.sp_min = -1;
else
return 0;
if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp)
if (fields[4][0] == '\0')
spwd.sp_max = -1;
else
return 0;
if (i == OFIELDS) {
spwd.sp_warn = spwd.sp_inact = spwd.sp_expire =
spwd.sp_flag = -1;
return &spwd;
}
if ((spwd.sp_warn = strtol (fields[5], &cpp, 10)) == 0 && *cpp)
if (fields[5][0] == '\0')
spwd.sp_warn = -1;
else
return 0;
if ((spwd.sp_inact = strtol (fields[6], &cpp, 10)) == 0 && *cpp)
if (fields[6][0] == '\0')
spwd.sp_inact = -1;
else
return 0;
if ((spwd.sp_expire = strtol (fields[7], &cpp, 10)) == 0 && *cpp)
if (fields[7][0] == '\0')
spwd.sp_expire = -1;
else
return 0;
if ((spwd.sp_flag = strtol (fields[8], &cpp, 10)) == 0 && *cpp)
if (fields[8][0] == '\0')
spwd.sp_flag = -1;
else
return 0;
return (&spwd);
}
struct spwd
*fgetspent (fp)
FILE *fp;
{
char buf[BUFSIZ];
if (! fp)
return (0);
if (fgets (buf, BUFSIZ, fp) == (char *) 0)
return (0);
return sgetspent (buf);
}
struct spwd
*getspent ()
{
if (! shadow)
setspent ();
return (fgetspent (shadow));
}
struct spwd
*getspnam (name)
char *name;
{
struct spwd *spwd;
setspent ();
while ((spwd = getspent ()) != (struct spwd *) 0) {
if (strcmp (name, spwd->sp_namp) == 0)
return (spwd);
}
return (0);
}
int
putspent (spwd, fp)
struct spwd *spwd;
FILE *fp;
{
int errors = 0;
if (! fp || ! spwd)
return -1;
if (fprintf (fp, "%s:%s:", spwd->sp_namp, spwd->sp_pwdp) < 0)
errors++;
if (spwd->sp_lstchg != -1) {
if (fprintf (fp, "%ld:", spwd->sp_lstchg) < 0)
errors++;
} else if (putc (':', fp) == EOF)
errors++;
if (spwd->sp_min != -1) {
if (fprintf (fp, "%ld:", spwd->sp_min) < 0)
errors++;
} else if (putc (':', fp) == EOF)
errors++;
if (spwd->sp_max != -1) {
if (fprintf (fp, "%ld:", spwd->sp_max) < 0)
errors++;
} else if (putc (':', fp) == EOF)
errors++;
if (spwd->sp_warn != -1) {
if (fprintf (fp, "%ld:", spwd->sp_warn) < 0)
errors++;
} else if (putc (':', fp) == EOF)
errors++;
if (spwd->sp_inact != -1) {
if (fprintf (fp, "%ld:", spwd->sp_inact) < 0)
errors++;
} else if (putc (':', fp) == EOF)
errors++;
if (spwd->sp_expire != -1) {
if (fprintf (fp, "%ld:", spwd->sp_expire) < 0)
errors++;
} else if (putc (':', fp) == EOF)
errors++;
if (spwd->sp_flag != -1) {
if (fprintf (fp, "%ld:", spwd->sp_flag) < 0)
errors++;
} else if (putc (':', fp) == EOF)
errors++;
if (putc ('\n', fp) == EOF)
errors++;
if (errors)
return -1;
else
return 0;
}
SHAR_EOF
fi
if test -f 'shadow.h'
then
echo shar: "will not over-write existing file 'shadow.h'"
else
cat << \SHAR_EOF > 'shadow.h'
/*
* Copyright 1988, 1989, 1990, John F. Haugh II
* All rights reserved.
*
* Use, duplication, and disclosure prohibited without
* the express written permission of the author.
*/
/*
* This information is not derived from AT&T licensed sources. Posted
* to the USENET 11/88, and updated 11/90 with information from SVR4.
*
* @(#)shadow.h 3.1 10:14:23 11/9/90
*/
/*
* Shadow password security file structure.
*/
struct spwd {
char *sp_namp; /* login name */
char *sp_pwdp; /* encrypted password */
long sp_lstchg; /* date of last change */
long sp_min; /* minimum number of days between changes */
long sp_max; /* maximum number of days between changes */
long sp_warn; /* number of days of warning before password
expires */
long sp_inact; /* number of days after password expires
until the account becomes unusable. */
long sp_expire; /* days since 1/1/70 until account expires */
unsigned long sp_flag; /* reserved for future use */
};
/*
* Shadow password security file functions.
*/
struct spwd *getspent ();
struct spwd *getspnam ();
struct spwd *sgetspent ();
void setspent ();
void endspent ();
struct spwd *fgetspent ();
int putspent ();
#define SHADOW "/etc/shadow"
SHAR_EOF
fi
exit 0
# End of shell archive