[alt.sources] chage: Change password aging fields

jfh@rpp386.cactus.org (John F. Haugh II) (08/24/90)

This is the most recent in a long string of login and password and
so on things to come out of here.  This command knows about standard
password files, shadow files, and DBM database files.

The purpose of this command is to provide an interface to the
password expiration information without having to ask yourself what
the value of "K" is, or what letter do you use for 13?

After unsharing you need to edit config.h to reflect your current
configuration and then type "make chage".  There is even a man page
for your reading pleasure.

Unshar and Enjoy!
----- Cut Here -----
#! /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:
#	chage.1
#	Makefile
#	config.h
#	shadow.h
#	chage.c
#	pwent.c
#	pwpack.c
#	age.c
#	shadow.c
# This archive created: Fri Aug 24 08:22:06 1990
# By:	John F. Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'chage.1'" '(1657 characters)'
if test -f 'chage.1'
then
	echo shar: "will not over-write existing file 'chage.1'"
else
sed 's/^X//' << \SHAR_EOF > 'chage.1'
X.TH CHAGE 1
X.SH NAME
Xchage \- change user password expirate information
X.SH SYNOPSIS
X\fBchage\fR [ \fB-m \fImindays\fR ] [ \fB-M \fImaxdays\fR ] [ \fB-d \fIlastday\fR ] \fIuser\fR
X.SH DESCRIPTION
X\fIchage\f changes the number of days between password changes and the
Xdate of the last password change.
XThis information is used by the system to determine when a user must
Xchange their password.
XThe \fIchage\f command is restricted to the root user.
X.PP
XThe value of \fImindays\f is the minimum number of days between
Xpassword changes.
XA value of zero for this field indicates that the user may change
Xher password at any time.
X.PP
XThe value of \fImaxdays\f is the maximum number of days during
Xwhich a password is valid.
XWhen \fImaxdays\f plus \fIlastday\f is less than the current day,
Xthe user will be required to change her password before being
Xable to use her account.
X.PP
XThe value of \fIlastday\f is the number of days since January 1st,
X1970 when the password was last changed.
X.PP
XAll of the above values are stored exactly as days when the shadow
Xpassword file is used, but are converted to and from weeks when the
Xstandard password file is used.
XBecause of this conversion, rounding errors may result.
X.PP
XIf none of the options are selected, \fIchage\f operates in an interactive
Xfashion, prompting the user with the current values for all of the fields.
XEnter the new value to change the field, or leave the line blank to use
Xthe current value.
XThe current value is displayed between a pair of \fB[ ]\f marks.
X.SH Files
X/etc/passwd \- user account information
X.br
X/etc/shadow \- shadow user account information
X.SH See Also
Xpasswd(4),
Xshadow(4)
SHAR_EOF
if test 1657 -ne "`wc -c < 'chage.1'`"
then
	echo shar: "error transmitting 'chage.1'" '(should have been 1657 characters)'
fi
fi
echo shar: "extracting 'Makefile'" '(8119 characters)'
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
sed 's/^X//' << \SHAR_EOF > 'Makefile'
X#
X# Copyright 1988,1989,1990, John F. Haugh II
X# All rights reserved.
X#
X# Non-commercial distribution permitted.  You must provide this source
X# code in any distribution.  This notice must remain intact.
X#
X#	@(#)Makefile	2.15	09:43:26  - Shadow password system
X#
X#	@(#)Makefile	2.15	09:43:26	8/23/90
X#
XSHELL = /bin/sh
X
X# Define the directory login is copied to.  BE VERY CAREFUL!!!
X# LOGINDIR = /bin
XLOGINDIR = /etc
X
X# Pick your favorite C compiler and tags command
XCC = cc
XTAGS = ctags
X
X# OS.  Currently only BSD and USG are defined.  If you don't use BSD,
X# USG (System V) is assumed.
X# OS = -DBSD
X
X# Do you have to do ranlib?  Sorry to hear that ...
XRANLIB = ranlib
X# RANLIB = echo
X
X# Flags for SCO Xenix/386
XCFLAGS = -O -M3 -g $(PWDEF) $(AL64DEF) $(OS)
XLIBS = -lcrypt -ldbm
XLDFLAGS = -M3 -g
XLTFLAGS = 
X# This should be Slibsec.a for small model, or Llibsec.a for
X# large model or whatever.  MUST AGREE WITH CFLAGS!!!
XLIBSEC = Slibsec.a
X
X# Flags for normal machines
X# CFLAGS = -O -g $(PWDEF) $(AL64DEF) $(OS)
X# LIBS =
X# LDFLAGS = -g
X# LIBSEC = libsec.a
X
XLOBJS = lmain.o login.o env.o password.o entry.o valid.o setup.o shell.o age.o \
X	pwent.o utmp.o sub.o mail.o motd.o log.o shadow.o dialup.o dialchk.o \
X	ttytype.o failure.o port.o pwpack.o
X
XLSRCS = lmain.c login.c env.c password.c entry.c valid.c setup.c shell.c age.c \
X	pwent.c utmp.c sub.c mail.c motd.c log.c shadow.c dialup.c dialchk.c \
X	ttytype.c failure.c port.c pwpack.c
X
XSOBJS = smain.o env.o password.o entry.o suvalid.o susetup.o sushell.o \
X	pwent.o susub.o mail.o motd.o sulog.o shadow.o suage.o pwpack.o
X
XSSRCS = smain.c env.c password.c entry.c valid.c setup.c shell.c \
X	pwent.c sub.c mail.c motd.c sulog.c shadow.c age.c pwpack.c
X
XPOBJS = pmain.o password.o entry.o valid.o pwage.o pwent.o obscure.o shadow.o \
X	pwpack.o
X
XPSRCS = pmain.c password.c entry.c valid.c age.c pwent.c obscure.c shadow.c \
X	pwpack.c
X
XGPSRCS = gpmain.c password.c grent.c
X
XGPOBJS = gpmain.o password.o grent.o
X
XPWOBJS = pwconv.o pwent.o shadow.o pwage.o pwpack.o
X
XPWSRCS = pwconv.c pwent.c shadow.c age.c pwpack.c
X
XPWUNOBJS = pwunconv.o pwent.o shadow.o pwage.o pwpack.o
X
XPWUNSRCS = pwunconv.c pwent.c shadow.c age.c pwpack.c
X
XSULOGOBJS = sulogin.o entry.o env.o password.o pwage.o pwent.o setup.o \
X	shadow.o shell.o valid.o pwpack.o
X
XSULOGSRCS = sulogin.c entry.c env.c password.c age.c pwent.c setup.c \
X	shadow.c shell.c valid.c pwpack.c
X
XDBOBJS = mkpasswd.o pwent.o pwpack.o
X
XDBSRCS = mkpasswd.c pwent.c pwpack.c
X
XNGSRCS = newgrp.c shadow.c password.c
X
XNGOBJS = newgrp.o shadow.o password.o
X
XCHFNSRCS = chfn.c pwent.c pwpack.c
X
XCHFNOBJS = chfn.o pwent.o pwpack.o
X
XCHSHSRCS = chsh.c pwent.c pwpack.c
X
XCHSHOBJS = chsh.o pwent.o pwpack.o
X
XCHAGEOBJS = chage.o pwent.o pwpack.o pwage.o shadow.o
X
XCHAGESRCS = chage.c pwent.c pwpack.c age.c shadow.c
X
XALLSRCS = age.c dialchk.c dialup.c entry.c env.c lmain.c log.c login.c mail.c \
X	motd.c obscure.c password.c pmain.c pwconv.c pwent.c pwunconv.c \
X	setup.c shadow.c shell.c smain.c sub.c sulog.c sulogin.c ttytype.c \
X	utmp.c valid.c port.c newgrp.c gpmain.c grent.c mkpasswd.c pwpack.c \
X	chfn.c chsh.c chage.c
X
XFILES1 = README newgrp.c Makefile config.h pwunconv.c obscure.c age.c \
X	sub.c login.c shell.c lastlog.h
X
XFILES2 = pmain.c port.c lmain.c mkpasswd.c sulogin.c pwpack.c dialup.c \
X	sulog.c password.c env.c mail.c dialchk.c
X
XFILES3 = chfn.c chsh.c smain.c faillog.c pwconv.c failure.c utmp.c shadow.c \
X	log.c shadow.h faillog.h
X
XFILES4 = gpmain.c chage.c pwent.c valid.c setup.c entry.c ttytype.c port.h \
X	grent.c motd.c dialup.h
X
XMAN_1 = chage.1 chfn.1 chsh.1 login.1 passwd.1 su.1
XMAN_3 = shadow.3
XMAN_4 = faillog.4 passwd.4 porttime.4 shadow.4
XMAN_8 = faillog.8 pwconv.8 pwunconv.8 sulogin.8
X
XDOCS = $(MAN_1) $(MAN_3) $(MAN_4) $(MAN_8)
X
XBINS = su login pwconv pwunconv passwd sulogin faillog newgrp gpasswd \
X	mkpasswd chfn chsh chage
X
Xall:	$(BINS) $(DOCS)
X
Xlibsec: shadow.o
X	ar rv $(LIBSEC) shadow.o
X	$(RANLIB) $(LIBSEC)
X
Xinstall: all
X	strip $(BINS)
X	cp login $(LOGINDIR)/login
X	cp mkpasswd pwconv pwunconv sulogin /etc
X	cp su passwd gpasswd faillog newgrp chfn chsh /bin
X	cp shadow.h /usr/include
X	chown root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
X		/bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd
X	chgrp root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
X		/bin/su /bin/passwd /bin/gpasswd /bin/newgrp /etc/mkpasswd
X	chown bin /bin/faillog /usr/include/shadow.h
X	chgrp bin /bin/faillog /usr/include/shadow.h
X	chmod 700 /etc/pwconv /etc/pwunconv /etc/sulogin /etc/mkpasswd
X	chmod 4711 $(LOGINDIR)/login /bin/su /bin/passwd /bin/gpasswd \
X		/bin/newgrp /bin/chfn
X	chmod 711 /bin/faillog
X	chmod 444 /usr/include/shadow.h
X
Xlint:	su.L login.L pwconv.L pwunconv.L passwd.L sulogin.L faillog.L \
X	newgrp.L gpasswd.L mkpasswd.L chfn.L chsh.L chage.L
X
Xtags:	$(ALLSRCS)
X	$(TAGS) $(ALLSRCS)
X
XREADME:	s.README
X	get s.README
X	
X$(DOCS):
X	get s.$@
X
Xlogin:	$(LOBJS)
X	$(CC) -o login $(LDFLAGS) $(LOBJS) $(LIBS)
X
Xlogin.L: $(LSRCS)
X	lint $(LSRCS) > login.L
X
Xsu:	$(SOBJS)
X	$(CC) -o su $(LDFLAGS) $(SOBJS) $(LIBS)
X
Xsu.L:	$(SSRCS)
X	lint -DSU $(SSRCS) > su.L
X
Xpasswd:	$(POBJS)
X	$(CC) -o passwd $(LDFLAGS) $(POBJS) $(LIBS)
X
Xpasswd.L: $(PSRCS)
X	lint -DPASSWD $(PSRCS) > passwd.L
X
Xgpasswd: $(GPOBJS)
X	$(CC) -o gpasswd $(LDFLAGS) $(GPOBJS) $(LIBS)
X
Xgpasswd.L: $(GPSRCS)
X	lint $(GPSRCS) > gpasswd.L
X
Xpwconv:	$(PWOBJS)
X	$(CC) -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBS)
X
Xpwconv.L: $(PWSRCS)
X	lint -DPASSWD $(PWSRCS) > pwconv.L
X
Xpwunconv: $(PWUNOBJS)
X	$(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBS)
X
Xpwunconv.L: $(PWUNSRCS)
X	lint -DPASSWD $(PWUNSRCS) > pwunconv.L
X
Xsulogin: $(SULOGOBJS)
X	$(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBS)
X
Xsulogin.L: $(SULOGSRCS)
X	lint $(SULOGSRCS) > sulogin.L
X
Xfaillog: faillog.o
X	$(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS)
X
Xfaillog.L: faillog.c faillog.h config.h
X	lint faillog.c > faillog.L
X
Xmkpasswd: $(DBOBJS)
X	$(CC) -o mkpasswd $(LDFLAGS) $(DBOBJS) $(LIBS)
X
Xmkpasswd.L: $(DBSRCS)
X	lint $(DBSRCS) > mkpasswd.L
X
Xnewgrp: $(NGOBJS)
X	$(CC) -o newgrp $(LDFLAGS) $(NGOBJS) $(LIBS)
X
Xnewgrp.L: $(NGSRCS)
X	lint $(NGSRCS) > newgrp.L
X
Xchfn:	$(CHFNOBJS)
X	$(CC) -o chfn $(LDFLAGS) $(CHFNOBJS) $(LIBS)
X
Xchfn.L:	$(CHFNSRCS)
X	lint $(CHFNSRCS) > chfn.L
X
Xchsh:	$(CHSHOBJS)
X	$(CC) -o chsh $(LDFLAGS) $(CHSHOBJS) $(LIBS)
X
Xchsh.L: $(CHSHSRCS)
X	lint $(CHSHSRCS) > chsh.L
X
Xchage:	$(CHAGEOBJS)
X	$(CC) -o chage $(LDFLAGS) $(CHAGEOBJS) $(LIBS)
X
Xchage.L: $(CHAGESRCS)
X	lint -DPASSWD $(CHAGESRCS) > chage.L
X
Xsushell.c: shell.c
X	cp shell.c sushell.c
X
Xsushell.o: config.h sushell.c
X	$(CC) -c $(CFLAGS) -DSU sushell.c
X
Xsusub.c: sub.c
X	cp sub.c susub.c
X
Xsusub.o: config.h susub.c
X	$(CC) -c $(CFLAGS) -DSU susub.c
X
Xsulog.o: config.h
X
Xsusetup.c: setup.c
X	cp setup.c susetup.c
X
Xsusetup.o: config.h setup.c
X	$(CC) -c $(CFLAGS) -DSU susetup.c
X
Xsuvalid.c: valid.c
X	cp valid.c suvalid.c
X
Xsuvalid.o: config.h valid.c
X	$(CC) -c $(CFLAGS) -DSU suvalid.c
X
Xpmain.o: config.h lastlog.h shadow.h
X
Xpwage.o: age.c config.h
X	cp age.c pwage.c
X	$(CC) -c $(CFLAGS) -DPASSWD pwage.c
X	rm pwage.c
X
Xsuage.o: age.c config.h
X	cp age.c suage.c
X	$(CC) -c $(CFLAGS) -DSU suage.c
X	rm suage.c
X
Xlmain.o: config.h lastlog.h faillog.h
X
Xsmain.o: config.h lastlog.h
X
Xsetup.o: config.h
X
Xutmp.o: config.h
X
Xmail.o: config.h
X
Xmotd.o: config.h
X
Xage.o: config.h
X
Xlog.o: config.h lastlog.h
X
Xshell.o: config.h
X
Xentry.o: config.h shadow.h
X
Xshadow.o: shadow.h
X
Xdialup.o: dialup.h
X
Xdialchk.o: dialup.h config.h
X
Xvalid.o: config.h
X
Xfailure.o: faillog.h config.h
X
Xfaillog.o: faillog.h config.h
X
Xpwent.o: config.h
X
Xport.o: port.h
X
Xnewgrp.o: config.h shadow.h
X
Xmkpasswd.o: config.h
X
Xgpmain.o: config.h
X
Xchfn.o: config.h
X
Xchsh.o: config.h
X
Xchage.o: config.h shadow.h
X
Xclean:
X	-rm -f *.o a.out core npasswd nshadow *.pag *.dir
X
Xclobber: clean
X	-rm -f $(BINS) *.L sushell.c susetup.c susub.c suvalid.c
X
Xshar:	login.sh.1 login.sh.2 login.sh.3 login.sh.4 login.sh.5
X
Xlogin.sh.1: $(FILES1)
X	shar -a $(FILES1) > login.sh.1
X
Xlogin.sh.2: $(FILES2)
X	shar -a $(FILES2) > login.sh.2
X
Xlogin.sh.3: $(FILES3)
X	shar -a $(FILES3) > login.sh.3
X
Xlogin.sh.4: $(FILES4)
X	shar -a $(FILES4) > login.sh.4
X
Xlogin.sh.5: $(DOCS)
X	shar -a $(DOCS) > login.sh.5
SHAR_EOF
if test 8119 -ne "`wc -c < 'Makefile'`"
then
	echo shar: "error transmitting 'Makefile'" '(should have been 8119 characters)'
fi
fi
echo shar: "extracting 'config.h'" '(6050 characters)'
if test -f 'config.h'
then
	echo shar: "will not over-write existing file 'config.h'"
else
sed 's/^X//' << \SHAR_EOF > 'config.h'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X/*
X * Configuration file for login.
X *
X *	@(#)config.h	2.6	08:26:28	8/20/90
X */
X
X/*
X * Define DIALUP to use dialup password files.  Define PORTTIME
X * to use the port time restriction file, see port.h for more
X * information.
X */
X
X#define	DIALUP
X#define	PORTTIME
X
X/*
X * Define SHADOWPWD to use shadow [ unreadable ] password file
X */
X
X#define	SHADOWPWD
X
X/*
X * Define DOUBLESIZE to use 16 character passwords
X */
X
X#define DOUBLESIZE
X
X/*
X * Define OBSCURE to include hard password testing code.
X */
X
X#define	OBSCURE
X
X/*
X * Define PASSLENGTH to be shortest legal password
X */
X
X#define	PASSLENGTH	5
X
X/*
X * Define NOBLANK if you want all passwords prompted for, including
X * empty ones.
X
X#undef	NOBLANK
X
X/*
X * Define MAXDAYS to be the default maximum number of days a password
X * is valid for when converting to shadow passwords.  Define MINDAYS
X * to be the minimum number of days before a password may be changed.
X * See pwconv.c for more details.
X */
X
X#define	MAXDAYS	10000
X#define	MINDAYS	0
X
X/*
X * Define NDEBUG for production versions
X */
X
X#define	NDEBUG
X
X/*
X * Define HZ if login must set HZ value
X */
X
X#define	HZ	"HZ=50"
X
X/*
X * Define TZ if login must set timezone
X *
X * The first example sets the variable directly.  The
X * second example names a file which is read to determine
X * the proper value.  The file consists of a single line
X * of the form 'TZ=zone-name'
X */
X
X/* #define	TZ	"TZ=CST6CDT" */
X#define	TZ	"/etc/tzname"
X
X/*
X * Define the default PATH and SUPATH here.  PATH is for non-privileged
X * users, SUPATH is for root.  The first pair are for real trusting
X * systems, the second pair are for the paranoid ...
X */
X
X/* #define	PATH	"PATH=:/bin:/usr/bin"	*/
X/* #define	SUPATH	"PATH=:/bin:/usr/bin:/etc" */
X#define	PATH	"PATH=/bin:/usr/bin"
X#define	SUPATH	"PATH=/bin:/usr/bin:/etc"
X
X/*
X * Define the mailbox directory
X */
X
X#define	MAILDIR	"/usr/spool/mail/"
X
X/*
X * Define AGING if you want the password aging checks made.
X * Define WARNAGE to be the number of days notice a user receives
X * of a soon to expire password.
X */
X
X#define	AGING
X#define	WARNAGE	10
X
X/*
X * Define MAILCHECK if you want the mailbox checked for new mail
X *
X * One of two messages are printed - `You have new mail.' or
X * `You have mail.'.
X */
X
X#define	MAILCHECK
X
X/*
X * Define CONSOLE if you want ROOT restricted to a particular terminal.
X *
X * Use the name of the tty line if you only want a single line, or use
X * the name of the file containing the permissible ports if you wish to
X * allow root logins on more than one port.
X */
X
X/* #define	CONSOLE	"console"	/* root on /dev/console only */
X#define	CONSOLE	"/etc/consoles"		/* check /etc/consoles for a list */
X
X/*
X * Define NOLOGINS if you want to be able to deny non-root users logins.
X * Logins will not be permitted if this file exists.
X */
X
X#define	NOLOGINS	"/etc/nologin"
X
X/*
X * Define NOUSE if you want to be able to declare accounts which can't
X * be logged into.  Define NOLOGIN if you want it to be an su-only account.
X */
X
X#define	NOUSE	"NOUSE"
X#define	NOLOGIN	"NOLOGIN"
X
X/*
X * Define MOTD if you want the message of the day (/etc/motd) printed
X * at login time.
X */
X
X#define	MOTD
X
X/*
X * Define HUSHLOGIN if you want the code added to avoid printing the
X * motd if a file $HOME/.hushlogin exists.  This obviously only matters
X * if any of MOTD, MAILCHECK or LASTLOG are #define'd.
X */
X
X#define	HUSHLOGIN
X
X/*
X * Define LASTLOG if you want a record made of logins in /usr/adm/lastlog.
X */
X
X#define	LASTLOG
X
X/*
X * Define FAILLOG if you want a record make of failed logins in
X * /usr/adm/faillog.  See faillog.h for more details.  See fail(1L)
X * for even still more details ...  Also, define FTMP to record utmp
X * style records for failed logins.  FTMP is the name of a utmp-like
X * file.  You can use who(1) instead of faillog(L), which is an
X * advantage.  Define UNKNOWNS if you do want unknown user names
X * recorded.  This can be a security hole since passwords are often
X * entered mistakenly as user names.
X */
X
X#define	FAILLOG
X#define	FTMP	"/etc/ftmp"
X#define	UNKNOWNS
X
X/*
X * Define TTYPERM to be the initial terminal permissions.  Defining
X * as 0600 will not allow messages, 0622 will.
X */
X
X#define	TTYPERM	0600
X
X/*
X * Define TTYTYPE to the be name of the port to terminal type
X * mapping file.  This is used to set the environmental variable
X * "TERM" to the correct terminal type.
X */
X
X#define	TTYTYPE	"/etc/ttytype"
X
X/*
X * Define QUOTAS if you want the code added in setup.c to support
X * file ulimit and nice [ and umask as well ] setting from the password
X * file.
X */
X
X#define	QUOTAS
X
X/*
X * Pick your version of DBM.  Only DBM is presently supported, NDBM will
X * follow.  You must also define the GETPWENT macro below.
X */
X
X#define	DBM
X
X/*
X * Define file name for sulog.  If SULOG is not defined, there will be
X * no logging.  This is NOT a good idea ...  We also define other file
X * names.
X */
X
X#define	SULOG	"/usr/adm/sulog"
X#define	SUCON	"/dev/console"
X#define	PWDFILE	"/etc/passwd"
X#define	OPWDFILE "/etc/-passwd"
X#define	NPWDFILE "/etc/npasswd"
X#define	OSHADOW "/etc/-shadow"
X#define	NSHADOW "/etc/nshadow"
X#define	GRPFILE	"/etc/group"
X#define	OGRPFILE "/etc/-group"
X#define	NGRPFILE "/etc/ngroup"
X
X/*
X * Define PWDLOCK to be a locking semaphore for updating the password
X * file.  GRPLOCK is the same for the group file.
X */
X
X#define	PWDLOCK	"/etc/.pwdlock"
X#define	GRPLOCK "/etc/.grplock"
X
X/*
X * Wierd stuff follows ...
X *
X *	The following macros exist solely to override stuff ...
X *	You will probably want to change their values to suit your
X *	fancy.
X */
X
X#define	ERASECHAR	'\b'
X#define	KILLCHAR	'\025'
X#define	UMASK		022
X
X#define	ULIMIT	(1L<<20) /* Define if your UNIX supports ulimit() */
X#define	FGETPWENT	/* Define if library does not include FGETPWENT */
X#define	GETPWENT	/* Define if you want my GETPWENT(3) routines */
X#define	NEED_AL64	/* Define if library does not include a64l() */
SHAR_EOF
if test 6050 -ne "`wc -c < 'config.h'`"
then
	echo shar: "error transmitting 'config.h'" '(should have been 6050 characters)'
fi
fi
echo shar: "extracting 'shadow.h'" '(852 characters)'
if test -f 'shadow.h'
then
	echo shar: "will not over-write existing file 'shadow.h'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.h'
X/*
X * Copyright 1988, 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X/*
X * This information is not derived from AT&T licensed sources.  Posted
X * to the USENET 11/88.
X *
X *	@(#)shadow.h	2.2	19:24:13	7/29/90
X */
X
X/*
X * Shadow password security file structure.
X */
X
Xstruct	spwd {
X	char	*sp_namp;	/* login name */
X	char	*sp_pwdp;	/* encrypted password */
X	long	sp_lstchg;	/* date of last change */
X	long	sp_max;		/* maximum number of days between changes */
X	long	sp_min;		/* minimum number of days between changes */
X};
X
X/*
X * Shadow password security file functions.
X */
X
Xstruct	spwd	*getspent ();
Xstruct	spwd	*getspnam ();
Xvoid	setspent ();
Xvoid	endspent ();
Xstruct	spwd	*fgetspent ();
Xint	putspent ();
X
X#define  SHADOW "/etc/shadow"
SHAR_EOF
if test 852 -ne "`wc -c < 'shadow.h'`"
then
	echo shar: "error transmitting 'shadow.h'" '(should have been 852 characters)'
fi
fi
echo shar: "extracting 'chage.c'" '(9374 characters)'
if test -f 'chage.c'
then
	echo shar: "will not over-write existing file 'chage.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chage.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <errno.h>
X#include <ctype.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifdef	SHADOWPWD
X#include "shadow.h"
X#endif
X#ifdef	DBM
X#include <dbm.h>
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)chage.c	2.2	09:20:57	8/23/90";
X#endif
X
Xchar	*myname;
X
Xtime_t	today;
Xchar	name[BUFSIZ];
Xchar	newage[10];
Xint	mflg;
Xint	Mflg;
Xint	dflg;
X
Xstruct	passwd	pwent;
X#ifdef	SHADOWPWD
Xstruct	spwd	spwd;
X#endif
Xint	mindays;
Xint	maxdays;
Xlong	lastday;
X
Xextern	int	errno;
X
Xchar	Usage[] =
X"Usage: %s [ -m min_days ] [ -M max_days ] [ -w week | -d day ] user\n";
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X	fprintf (stderr, Usage, myname);
X	exit (1);
X}
X
X/*
X * change_field - change a single field if a new value is given.
X *
X * prompt the user with the name of the field being changed and the
X * current value.
X */
X
Xvoid
Xchange_field (val, prompt)
Xint	*val;
Xchar	*prompt;
X{
X	int	newval;
X	char	new[BUFSIZ];
X	char	*cp;
X
X	while (1) {
X		if (*val == -1)
X			printf ("\t%s []: ", prompt);
X		else
X			printf ("\t%s [%d]: ", prompt, *val);
X
X		fgets (new, BUFSIZ, stdin);
X
X		if (cp = strchr (new, '\n'))
X			*cp = '\0';
X		else
X			return;
X
X		if (new[0] == '\0')
X			return;
X
X		newval = strtol (new, &cp, 10);
X		if (cp != new && newval >= -1 && newval <= 10000) {
X			*val = newval;
X			return;
X		}
X		fprintf (stderr, "%s: illegal value: %s\n", myname, new);
X	}
X}
X
X/*
X * new_fields - change the user's password aging information interactively.
X *
X * prompt the user for the two password age values.  set the fields
X * from the user's response, or leave alone if nothing was entered.
X */
X
Xnew_fields ()
X{
X	printf ("Enter the new value, or press return for the default\n\n");
X
X	change_field (&mindays, "Minimum Password Age");
X	change_field (&maxdays, "Maximum Password Age");
X	change_field (&lastday, "Last Password Change");
X}
X
X#ifdef	DBM
X/*
X * update_dbm
X *
X * Updates the DBM password files, if they exist.
X */
X
Xupdate_dbm (pw)
Xstruct	passwd	*pw;
X{
X	datum	key;
X	datum	content;
X	char	data[BUFSIZ];
X	int	len;
X
X	strcpy (data, PWDFILE);
X	strcat (data, ".pag");
X	if (access (data, 0))
X		return;
X
X	len = pw_pack (pw, data);
X	content.dsize = len;
X	content.dptr = data;
X
X	key.dsize = strlen (pw->pw_name);
X	key.dptr = pw->pw_name;
X	store (key, content);
X
X	key.dsize = sizeof pw->pw_uid;
X	key.dptr = (char *) &pw->pw_uid;
X	store (key, content);
X}
X#endif
X
Xint
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	extern	int	optind;
X	extern	char	*optarg;
X	void	die ();
X	char	*cp;
X	char	*getlogin ();
X	int	amroot;
X	int	lockfd = -1;
X	int	flag;
X	struct	passwd	*pw;
X#ifdef	SHADOWPWD
X	struct	spwd	*sp;
X#endif
X	struct	passwd	*getpwuid ();
X	struct	passwd	*getpwnam ();
X	struct	passwd	*sgetpwent ();
X	FILE	*npwd;
X	FILE	*pwd;
X	char	buf[BUFSIZ];
X	char	tmp[BUFSIZ];
X
X	if (myname = strchr (argv[0], '/'))
X		myname++;
X	else
X		myname = argv[0];
X
X	if (getuid () != 0) {
X		fprintf (stderr, "%s: permission denied\n", myname);
X		exit (1);
X	}
X	while ((flag = getopt (argc, argv, "m:M:d:w:")) != EOF) {
X		switch (flag) {
X			case 'm':
X				mflg++;
X				mindays = strtol (optarg, 0, 10);
X				break;
X			case 'M':
X				Mflg++;
X				maxdays = strtol (optarg, 0, 10);
X				break;
X			case 'd':
X				dflg++;
X				lastday = strtol (optarg, 0, 10);
X				break;
X			case 'w':
X				dflg++;
X				lastday = strtol (optarg, 0, 10) * 7;
X				break;
X			default:
X				usage ();
X		}
X	}
X	if (argc != optind + 1)
X		usage ();
X
X	if (! (pw = getpwnam (argv[optind]))) {
X		fprintf (stderr, "%s: unknown user: %s\n",
X			myname, argv[optind]);
X		exit (1);
X	}
X	strcpy (name, pw->pw_name);
X#ifdef	SHADOWPWD
X	if (sp = getspnam (name)) {
X		spwd = *sp;
X		spwd.sp_namp = strdup (sp->sp_namp);
X		spwd.sp_pwdp = strdup (sp->sp_pwdp);
X	}
X#endif
X	pwent = *pw;
X	pwent.pw_name = strdup (pw->pw_name);
X	pwent.pw_passwd = strdup (pw->pw_passwd);
X	pwent.pw_age = strdup (pw->pw_age);
X	pwent.pw_gecos = strdup (pw->pw_gecos);
X	pwent.pw_dir = strdup (pw->pw_dir);
X	pwent.pw_shell = strdup (pw->pw_shell);
X
X	/*
X	 * Set the fields that aren't being set from the command line
X	 * from the password file.
X	 */
X
X#ifdef	SHADOWPWD
X	if (sp) {
X		if (! Mflg)
X			maxdays = spwd.sp_max;
X		if (! mflg)
X			mindays = spwd.sp_min;
X		if (! dflg)
X			lastday = spwd.sp_lstchg;
X	} else
X#endif
X	if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
X		if (! Mflg)
X			maxdays = c64i (pwent.pw_age[0]) * 7;
X		if (! mflg)
X			mindays = c64i (pwent.pw_age[1]) * 7;
X		if (! dflg && strlen (pwent.pw_age) == 4)
X			lastday = a64l (&pwent.pw_age[2]) * 7;
X	}
X
X	/*
X	 * If none of the fields were changed from the command line,
X	 * let the user interactively change them.
X	 */
X
X	if (! mflg && ! Mflg && ! dflg) {
X		printf ("Changing the aging information for %s\n", name);
X		new_fields ();
X	}
X
X	/*
X	 * Output the new password files.
X	 */
X
X	signal (SIGHUP, SIG_IGN);
X	signal (SIGINT, SIG_IGN);
X	signal (SIGQUIT, SIG_IGN);
X	signal (SIGTERM, SIG_IGN);
X
X	ulimit (30000);			/* prevent any funny business */
X	umask (0);			/* get new files modes correct */
X
X#ifndef	NDEBUG
X	if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
X#else
X	if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
X#endif	/* NDEBUG */
X	{
X		puts ("Can't get lock");
X		exit (1);
X	}
X	umask (077);			/* close security holes to come ... */
X
X#ifdef	SHADOWPWD
X	if (sp) {
X		spwd.sp_min = mindays;
X		spwd.sp_max = maxdays;
X		spwd.sp_lstchg = lastday;
X
X		if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1)
X			goto failure;
X
X		if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0)
X			goto failure;
X
X		if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0))
X			goto failure;
X
X		setspent ();
X
X		while (sp = getspent ()) {
X			if (strcmp (sp->sp_namp, name) == 0)
X				break;
X
X			if (putspent (sp, npwd))
X				goto failure;
X		}
X		(void) putspent (&spwd, npwd);	/* add the new entry */
X
X		while (sp = getspent ())	/* finish the other ones off */
X			(void) putspent (sp, npwd);
X
X		endspent ();
X
X		if (ferror (npwd)) {
X			perror (NSHADOW);
X			if (unlink (NPWDFILE) || unlink (PWDLOCK))
X				fputs ("Help!\n", stderr);
X
X			exit (1);
X		}
X		fflush (npwd);
X		fclose (npwd);
X
X		if (access (OSHADOW, 0) == 0) {
X			if (unlink (OSHADOW)) {
X				puts ("Can't remove backup file");
X				goto unlock;
X			}
X		}
X		if (link (SHADOW, OSHADOW) || unlink (SHADOW)) {
X			puts ("Can't save backup file");
X			goto unlock;
X		}
X	#ifndef	BSD
X		if (link (NSHADOW, SHADOW) || unlink (NSHADOW))
X	#else
X		if (rename (NSHADOW, SHADOW))
X	#endif
X		{
X			(void) unlink (OSHADOW);
X			puts ("Can't rename new file");
X			goto unlock;
X		}
X#ifndef	NDEBUG
X		(void) unlink (".pwdlock");
X#else
X		(void) unlink (PWDLOCK);
X#endif
X		exit (0);
X		/*NOTREACHED*/
X	}
X#endif
X	if (maxdays == -1 || mindays == -1 || lastday == -1) {
X		pwent.pw_age = "";
X	} else {
X		if (maxdays > (63*7))
X			maxdays = 63*7;
X		if (mindays > (63*7))
X			mindays = 63*7;
X
X		newage[0] = i64c (maxdays / 7);
X		newage[1] = i64c (mindays / 7);
X		strcpy (&newage[2], l64a (lastday / 7));
X		pwent.pw_age = newage;
X	}
X#ifdef	DBM
X	update_dbm (&pwent);
X#endif
X	if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) {
X		perror (NPWDFILE);
X		exit (1);
X	}
X#ifndef	NDEBUG
X	if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
X#else
X	umask (077);		/* no permissions for non-roots */
X
X	if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
X#endif	/* NDEBUG */
X	{
X		perror (NPWDFILE);
X		exit (1);
X	}
X#ifndef	NDEBUG
X	chmod (NPWDFILE, 0444);		/* lets have some security here ... */
X	chown (NPWDFILE, 0, 0);		/* ... and keep the bad guy away */
X#endif	/* NDEBUG */
X	if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) {
X		perror (NPWDFILE);
X		exit (1);
X	}
X	while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
X		if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
X			fputs (buf, npwd);
X		} else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
X			fputs (buf, npwd);
X		else
X			break;
X	}
X	(void) fprintf (npwd, "%s:", pw->pw_name);
X	if (pwent.pw_age && pwent.pw_age[0])
X		(void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
X	else
X		(void) fprintf (npwd, "%s:", pwent.pw_passwd);
X
X	(void) fprintf (npwd, "%d:%d:%s:%s:%s\n",
X		pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir,
X		pwent.pw_shell);
X
X	while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
X		fputs (buf, npwd);
X
X	if (ferror (npwd)) {
X		perror (NPWDFILE);
X		if (unlink (NPWDFILE) || unlink (PWDLOCK))
X			fputs ("Help!\n", stderr);
X
X		exit (1);
X	}
X	fflush (npwd);
X	fclose (npwd);
X#ifdef	NDEBUG
X	chmod (NPWDFILE, 0644);
X	if (unlink (OPWDFILE) == -1) {
X		if (errno != ENOENT) {
X			puts ("Can't unlink backup file");
X			goto unlock;
X		}
X	}
X	if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
X		puts ("Can't save backup file");
X		goto unlock;
X	}
X#ifndef	BSD
X	if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE))
X#else
X	if (rename (NPWDFILE, PWDFILE))
X#endif
X	{
X		puts ("Can't rename new file");
X		goto unlock;
X	}
X#endif	/* NDEBUG */
X#ifndef	NDEBUG
X	(void) unlink (".pwdlock");
X#else
X	(void) unlink (PWDLOCK);
X#endif
X	exit (0);
X	/*NOTREACHED*/
X
Xfailure:
X	puts ("Permission denied.");
Xunlock:
X	if (lockfd >= 0)
X		(void) unlink (PWDLOCK);
X
X	(void) unlink (NPWDFILE);
X	exit (1);
X	/*NOTREACHED*/
X}
SHAR_EOF
if test 9374 -ne "`wc -c < 'chage.c'`"
then
	echo shar: "error transmitting 'chage.c'" '(should have been 9374 characters)'
fi
fi
echo shar: "extracting 'pwent.c'" '(6779 characters)'
if test -f 'pwent.c'
then
	echo shar: "will not over-write existing file 'pwent.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwent.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X *
X * Duplication is permitted for non-commercial [ profit making ]
X * purposes provided this and other copyright notices remain
X * intact.
X */
X
X#include <stdio.h>
X#include <pwd.h>
X#include <string.h>
X#include "config.h"
X
X#ifdef	DBM
X#include <dbm.h>
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)pwent.c	2.3	01:08:16	8/3/90";
X#endif
X
X#define	SBUFSIZ	64
X#define	NFIELDS	7
X
Xstatic	FILE	*pwdfp;
Xstatic	char	pwdbuf[BUFSIZ];
Xstatic	char	*pwdfile = "/etc/passwd";
X#ifdef	DBM
Xstatic	int	dbmopened;
Xstatic	int	dbmerror;
X#endif
Xstatic	char	*pwdfields[NFIELDS];
Xstatic	struct	passwd	pwent;
X
X/*
X * sgetpwent - convert a string to a (struct passwd)
X *
X * sgetpwent() parses a string into the parts required for a password
X * structure.  Strict checking is made for the UID and GID fields and
X * presence of the correct number of colons.  Any failing tests result
X * in a NULL pointer being returned.
X */
X
Xstruct	passwd	*sgetpwent (buf)
Xchar	*buf;
X{
X	int	i;
X	char	*cp;
X
X	/*
X	 * Copy the string to a static buffer so the pointers into
X	 * the password structure remain valid.
X	 */
X
X	strncpy (pwdbuf, buf, BUFSIZ);
X	pwdbuf[BUFSIZ-1] = '\0';
X
X	/*
X	 * Save a pointer to the start of each colon separated
X	 * field.  The fields are converted into NUL terminated strings.
X	 */
X
X	for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) {
X		pwdfields[i] = cp;
X		if (cp = strchr (cp, ':'))
X			*cp++ = 0;
X	}
X
X	/*
X	 * There must be exactly NFIELDS colon separated fields or
X	 * the entry is invalid.  Also, the UID and GID must be non-blank.
X	 */
X
X	if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0')
X		return 0;
X
X	/*
X	 * Each of the fields is converted the appropriate data type
X	 * and the result assigned to the password structure.  If the
X	 * UID or GID does not convert to an integer value, a NULL
X	 * pointer is returned.
X	 */
X
X	pwent.pw_name = pwdfields[0];
X	pwent.pw_passwd = pwdfields[1];
X	if ((pwent.pw_uid = strtol (pwdfields[2], &cp, 10)) == 0 && *cp)
X		return 0;
X
X	if ((pwent.pw_gid = strtol (pwdfields[3], &cp, 10)) == 0 && *cp)
X		return 0;
X
X	if (cp = strchr (pwent.pw_passwd, ',')) {
X		pwent.pw_age = cp + 1;
X		*cp = '\0';
X	}
X	pwent.pw_gecos = pwdfields[4];
X	pwent.pw_dir = pwdfields[5];
X	pwent.pw_shell = pwdfields[6];
X
X	return (&pwent);
X}
X#ifdef FGETPWENT
X/*
X * fgetpwent - get a password file entry from a stream
X *
X * fgetpwent() reads the next line from a password file formatted stream
X * and returns a pointer to the password structure for that line.
X */
X
Xstruct	passwd	*fgetpwent (fp)
XFILE	*fp;
X{
X	char	buf[BUFSIZ];
X
X	while (fgets (buf, BUFSIZ, fp) != (char *) 0) {
X		buf[strlen (buf) - 1] = '\0';
X		return (sgetpwent (buf));
X	}
X	return 0;
X}
X#endif
X#ifdef	GETPWENT
X
X/*
X * endpwent - close a password file
X *
X * endpwent() closes the password file if open.
X */
X
Xint	endpwent ()
X{
X	if (pwdfp)
X		if (fclose (pwdfp))
X			return -1;
X
X	return 0;
X}
X
X/*
X * getpwent - get a password entry from the password file
X *
X * getpwent() opens the password file, if not already opened, and reads
X * a single entry.  NULL is returned if any errors are encountered reading
X * the password file.
X */
X
Xstruct	passwd	*getpwent ()
X{
X	if (! pwdfp && setpwent ())
X		return 0;
X
X	return fgetpwent (pwdfp);
X}
X
X/*
X * getpwuid - locate the password entry for a given UID
X *
X * getpwuid() locates the first password file entry for the given UID.
X * If there is a valid DBM file, the DBM files are queried first for
X * the entry.  Otherwise, a linear search is begun of the password file
X * searching for an entry which matches the provided UID.
X */
X
Xstruct	passwd	*getpwuid (uid)
Xint	uid;
X{
X	struct	passwd	*pwd;
X#ifdef	DBM
X	datum	key;
X	datum	content;
X
X	/*
X	 * Attempt to open the DBM files if they have never been opened
X	 * and an error has never been returned.
X	 */
X
X	if (! dbmerror && ! dbmopened) {
X		char	dbmfiles[BUFSIZ];
X
X		strcpy (dbmfiles, pwdfile);
X		strcat (dbmfiles, ".pag");
X
X		if (access (dbmfiles, 0) || dbminit (pwdfile))
X			dbmerror = 1;
X		else
X			dbmopened = 1;
X	}
X
X	/*
X	 * If the DBM file are now open, create a key for this UID and
X	 * try to fetch the entry from the database.  A matching record
X	 * will be unpacked into a static structure and returned to
X	 * the user.
X	 */
X
X	if (dbmopened) {
X		pwent.pw_uid = uid;
X		key.dsize = sizeof pwent.pw_uid;
X		key.dptr = (char *) &pwent.pw_uid;
X		content = fetch (key);
X		if (content.dptr != 0) {
X			memcpy (pwdbuf, content.dptr, content.dsize);
X			pw_unpack (pwdbuf, content.dsize, &pwent);
X			return &pwent;
X		}
X	}
X#endif
X	/*
X	 * Rewind the database and begin searching for an entry which
X	 * matches the UID.  Return the entry when a match is found.
X	 */
X
X	if (setpwent ())
X		return 0;
X
X	while (pwd = getpwent ())
X		if (pwd->pw_uid == uid)
X			return pwd;
X
X	return 0;
X}
X
Xstruct	passwd	*getpwnam (name)
Xchar	*name;
X{
X	struct	passwd	*pwd;
X#ifdef	DBM
X	datum	key;
X	datum	content;
X
X	/*
X	 * Attempt to open the DBM files if they have never been opened
X	 * and an error has never been returned.
X	 */
X
X	if (! dbmerror && ! dbmopened) {
X		char	dbmfiles[BUFSIZ];
X
X		strcpy (dbmfiles, pwdfile);
X		strcat (dbmfiles, ".pag");
X
X		if (access (dbmfiles, 0) || dbminit (pwdfile))
X			dbmerror = 1;
X		else
X			dbmopened = 1;
X	}
X
X	/*
X	 * If the DBM file are now open, create a key for this UID and
X	 * try to fetch the entry from the database.  A matching record
X	 * will be unpacked into a static structure and returned to
X	 * the user.
X	 */
X
X	if (dbmopened) {
X		key.dsize = strlen (name);
X		key.dptr = name;
X		content = fetch (key);
X		if (content.dptr != 0) {
X			memcpy (pwdbuf, content.dptr, content.dsize);
X			pw_unpack (pwdbuf, content.dsize, &pwent);
X			return &pwent;
X		}
X	}
X#endif
X	/*
X	 * Rewind the database and begin searching for an entry which
X	 * matches the name.  Return the entry when a match is found.
X	 */
X
X	if (setpwent ())
X		return 0;
X
X	while (pwd = getpwent ())
X		if (strcmp (pwd->pw_name, name) == 0)
X			return pwd;
X
X	return 0;
X}
X
X/*
X * setpwent - open the password file
X *
X * setpwent() opens the system password file, and the DBM password files
X * if they are present.  The system password file is rewound if it was
X * open already.
X */
X
Xint	setpwent ()
X{
X	if (! pwdfp) {
X		if (! (pwdfp = fopen (pwdfile, "r")))
X			return -1;
X	} else {
X		if (fseek (pwdfp, 0L, 0) != 0)
X			return -1;
X	}
X#ifdef	DBM
X	/*
X	 * Attempt to open the DBM files if they have never been opened
X	 * and an error has never been returned.
X	 */
X
X	if (! dbmerror && ! dbmopened) {
X		char	dbmfiles[BUFSIZ];
X
X		strcpy (dbmfiles, pwdfile);
X		strcat (dbmfiles, ".pag");
X
X		if (access (dbmfiles, 0) || dbminit (pwdfile))
X			dbmerror = 1;
X		else
X			dbmopened = 1;
X	}
X#endif
X	return 0;
X}
X#endif
SHAR_EOF
if test 6779 -ne "`wc -c < 'pwent.c'`"
then
	echo shar: "error transmitting 'pwent.c'" '(should have been 6779 characters)'
fi
fi
echo shar: "extracting 'pwpack.c'" '(2139 characters)'
if test -f 'pwpack.c'
then
	echo shar: "will not over-write existing file 'pwpack.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwpack.c'
X/*
X * Copyright 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X *
X * Duplication is permitted for non-commercial [ profit making ]
X * purposes provided this and other copyright notices remain
X * intact.
X */
X
X#include <stdio.h>
X#include <pwd.h>
X#ifdef	BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)pwpack.c	2.3	23:06:29	8/5/90";
X#endif
X
Xint	pw_pack (passwd, buf)
Xstruct	passwd	*passwd;
Xchar	*buf;
X{
X	char	*cp;
X
X	cp = buf;
X	strcpy (cp, passwd->pw_name);
X	cp += strlen (cp) + 1;
X
X	strcpy (cp, passwd->pw_passwd);
X	if (passwd->pw_age && passwd->pw_age[0]) {
X		cp += strlen (cp);
X		*cp++ = ',';
X		strcpy (cp, passwd->pw_age);
X	}
X	cp += strlen (cp) + 1;
X
X	memcpy (cp, (void *) &passwd->pw_uid, sizeof passwd->pw_uid);
X	cp += sizeof passwd->pw_uid;
X
X	memcpy (cp, (void *) &passwd->pw_gid, sizeof passwd->pw_gid);
X	cp += sizeof passwd->pw_gid;
X
X	strcpy (cp, passwd->pw_gecos);
X	cp += strlen (cp) + 1;
X
X	strcpy (cp, passwd->pw_dir);
X	cp += strlen (cp) + 1;
X
X	strcpy (cp, passwd->pw_shell);
X		cp += strlen (cp) + 1;
X
X	return cp - buf;
X}
X
Xint	pw_unpack (buf, len, passwd)
Xchar	*buf;
Xint	len;
Xstruct	passwd	*passwd;
X{
X	char	*org = buf;
X	char	*cp;
X
X	passwd->pw_name = buf;
X	buf += strlen (buf) + 1;
X	if (buf - org > len)
X		return -1;
X
X	passwd->pw_passwd = buf;
X	buf += strlen (buf) + 1;
X	if (buf - org > len)
X		return -1;
X
X	if (cp = strchr (passwd->pw_passwd, ',')) {
X		*cp++ = '\0';
X		passwd->pw_age = cp;
X	} else
X		passwd->pw_age = "";
X
X	memcpy ((void *) &passwd->pw_uid, (void *) buf, sizeof passwd->pw_uid);
X	buf += sizeof passwd->pw_uid;
X	if (buf - org > len)
X		return -1;
X
X	memcpy ((void *) &passwd->pw_gid, (void *) buf, sizeof passwd->pw_gid);
X	buf += sizeof passwd->pw_gid;
X	if (buf - org > len)
X		return -1;
X
X	passwd->pw_gecos = buf;
X	buf += strlen (buf) + 1;
X	if (buf - org > len)
X		return -1;
X
X	passwd->pw_dir = buf;
X	buf += strlen (buf) + 1;
X	if (buf - org > len)
X		return -1;
X
X	passwd->pw_shell = buf;
X	buf += strlen (buf) + 1;
X	if (buf - org > len)
X		return -1;
X
X	return 0;
X}
SHAR_EOF
if test 2139 -ne "`wc -c < 'pwpack.c'`"
then
	echo shar: "error transmitting 'pwpack.c'" '(should have been 2139 characters)'
fi
fi
echo shar: "extracting 'age.c'" '(2531 characters)'
if test -f 'age.c'
then
	echo shar: "will not over-write existing file 'age.c'"
else
sed 's/^X//' << \SHAR_EOF > 'age.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)age.c	2.5	07:46:56	8/14/90";
X#endif
X
X#ifndef	PASSWD
Xextern	char	*newenvp[];
X#endif
X
X#ifndef	WARNAGE
X#define	WARNAGE	10
X#endif
X
Xtime_t	time ();
X
Xint	c64i (c)
Xchar	c;
X{
X	if (c == '.')
X		return (0);
X
X	if (c == '/')
X		return (1);
X
X	if (c >= '0' && c <= '9')
X		return (c - '0' + 2);
X
X	if (c >= 'A' && c <= 'Z')
X		return (c - 'A' + 12);
X
X	if (c >= 'a' && c <= 'z')
X		return (c - 'a' + 38);
X	else
X		return (-1);
X}
X
Xint	i64c (i)
Xint	i;
X{
X	if (i < 0)
X		return ('.');
X	else if (i > 63)
X		return ('z');
X
X	if (i == 0)
X		return ('.');
X
X	if (i == 1)
X		return ('/');
X
X	if (i >= 2 && i <= 11)
X		return ('0' - 2 + i);
X
X	if (i >= 12 && i <= 37)
X		return ('A' - 12 + i);
X
X	if (i >= 38 && i <= 63)
X		return ('a' - 38 + i);
X
X	return ('\0');
X}
X
X#ifdef	AGING
X#ifdef	NEED_AL64
X#ifdef	PASSWD
Xchar	*l64a (l)
Xlong	l;
X{
X	static	char	buf[8];
X	int	i = 0;
X
X	if (i < 0L)
X		return ((char *) 0);
X
X	do {
X		buf[i++] = i64c ((int) (l % 64));
X		buf[i] = '\0';
X	} while (l /= 64L, l > 0 && i < 6);
X
X	return (buf);
X}
X#endif
X
Xlong	a64l (s)
Xchar	*s;
X{
X	int	i;
X	long	value;
X	long	shift = 0;
X
X	for (i = 0, value = 0L;i < 6 && *s;s++) {
X		value += (c64i (*s) << shift);
X		shift += 6;
X	}
X	return (value);
X}
X#endif
X#ifndef	PASSWD
Xvoid	expire (last, min, max, incr)
Xlong	last;
Xint	min;
Xint	max;
Xint	incr;
X{
X	long	clock;
X	long	week;
X	long	expires;
X	extern	char	name[];
X	extern	int	errno;
X
X	(void) time (&clock);
X	clock /= (24L * 60L * 60L);
X
X	if (last == 0L)
X		expires = 0L;
X	else
X		expires = (last + max) * incr;
X
X	if (clock >= expires || min == max) {
X#ifndef	SU
X		printf ("Your password has expired.");
X
X		if (max < min) {
X			puts ("  Contact the system administrator.\n");
X			exit (1);
X		}
X		puts ("  Choose a new one.\n");
X
X		execl ("/bin/passwd", "-passwd", name, (char *) 0);
X		puts ("Can't execute /bin/passwd");
X		exit (errno);
X#else
X		printf ("Your password has expired.\n");
X#ifdef	SULOG
X		sulog (0);
X#endif
X		exit (1);
X#endif
X	}
X}
X
Xvoid	agecheck (last, min, max, incr)
Xlong	last;
Xint	min;
Xint	max;
Xint	incr;
X{
X	long	clock = time ((long *) 0) / (24L * 3600);
X	long	remain;
X
X	if (last == 0)
X		return;
X
X	if ((remain = ((last + max) * incr) - clock) <= WARNAGE)
X		printf ("Your password will expire in %d %s.\n",
X			remain, remain == 1 ? "day":"days");
X}
X#endif
X#endif
SHAR_EOF
if test 2531 -ne "`wc -c < 'age.c'`"
then
	echo shar: "error transmitting 'age.c'" '(should have been 2531 characters)'
fi
fi
echo shar: "extracting 'shadow.c'" '(1969 characters)'
if test -f 'shadow.c'
then
	echo shar: "will not over-write existing file 'shadow.c'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include "shadow.h"
X#include <stdio.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)shadow.c	2.5	19:24:12	7/29/90";
X#endif
X
Xstatic	FILE	*shadow;
X#define	FIELDS	5
X
Xvoid	setspent ()
X{
X	if (shadow)
X		rewind (shadow);
X	else
X		shadow = fopen (SHADOW, "r");
X}
X
Xvoid	endspent ()
X{
X	if (shadow)
X		(void) fclose (shadow);
X
X	shadow = (FILE *) 0;
X}
X
Xstruct	spwd	*fgetspent (fp)
XFILE	*fp;
X{
X	static	struct	spwd	spwd;
X	static	char	buf[BUFSIZ];
X	char	*fields[FIELDS];
X	char	*cp;
X	int	i;
X	int	atoi ();
X	long	atol ();
X
X	if (! fp)
X		return (0);
X
X	if (fgets (buf, BUFSIZ, fp) == (char *) 0)
X		return (0);
X
X	if (cp = strrchr (buf, '\n'))
X		*cp = '\0';
X
X	for (cp = buf, i = 0;i < FIELDS;i++) {
X		fields[i] = cp;
X		while (*cp && *cp != ':')
X			cp++;
X
X		if (*cp)
X			*cp++ = '\0';
X	}
X	if (*cp || i != FIELDS)
X		return 0;
X
X	spwd.sp_namp = fields[0];
X	spwd.sp_pwdp = fields[1];
X
X	if ((spwd.sp_lstchg = strtol (fields[2], (char **) 0, 10)) == -1)
X		return 0;
X
X	if ((spwd.sp_min = strtol (fields[3], (char **) 0, 10)) == -1)
X		return 0;
X
X	if ((spwd.sp_max = strtol (fields[4], (char **) 0, 10)) == -1)
X		return 0;
X
X	return (&spwd);
X}
X
Xstruct	spwd	*getspent ()
X{
X	if (! shadow)
X		setspent ();
X
X	return (fgetspent (shadow));
X}
X
Xstruct	spwd	*getspnam (name)
Xchar	*name;
X{
X	struct	spwd	*spwd;
X
X	setspent ();
X
X	while ((spwd = getspent ()) != (struct spwd *) 0) {
X		if (strcmp (name, spwd->sp_namp) == 0)
X			return (spwd);
X	}
X	return (0);
X}
X
Xint	putspent (spwd, fp)
Xstruct	spwd	*spwd;
XFILE	*fp;
X{
X	if (! fp)
X		return -1;
X
X	fprintf (fp, "%s:%s:%ld:%ld:%ld\n",
X			spwd->sp_namp, spwd->sp_pwdp,
X			spwd->sp_lstchg, spwd->sp_min, spwd->sp_max);
X
X	if (ferror (fp))
X		return -1;
X	else
X		return 0;
X}
SHAR_EOF
if test 1969 -ne "`wc -c < 'shadow.c'`"
then
	echo shar: "error transmitting 'shadow.c'" '(should have been 1969 characters)'
fi
fi
exit 0
#	End of shell archive
----- Whip me, Beat me, Make me write bad checks! -----
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org
"SCCS, the source motel!  Programs check in and never check out!"
		-- Ken Thompson