[comp.sources.bugs] Shadow login: patch #7

jfh@rpp386.Dallas.TX.US (John F. Haugh II) (03/27/89)

This is a shar file ...

Unwrap and apply the file `patches' to your patch level 6 source
code.  Sorry this is so large.  There are several new ideas on
the burner, the next bug fix will be a complete reposting ...

When you are done, you will be at patchlevel 7.  Read the file
'patches' for a list of what it fixes.

- John.
--
#! /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:
#	patches
#	faillog.c
#	faillog.h
#	failure.c
# This archive created: Sun Mar 26 21:23:02 1989
# By:	John F. Haugh II (River Parishes Programming, Dallas TX)
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'patches'
then
	echo shar: "will not over-write existing file 'patches'"
else
cat << \SHAR_EOF > 'patches'
Oh?  Another week gone by?  Must be time for patch #7 ...

New features [ freeping creaturism alert ... ]

	- Timezone file may be specified instead of value only
	- Comments now allowed in dialup device file
	- Added tags rule to Makefile
	- Added libsec.a [ shadow library ] rule to Makefile
	- Login failure tracking [ tnx to Chip Rosenthal & Jim O'Connor ]
	- Login failure control utility

Bugs fixed

	- Dialup password file works correctly
	- putspent() works on 16 bit machines
	- removed unneeded lastlog.h references
	- su(1) handles LOGNAME correctly

The manual page for faillog(1L) hasn't been written yet.  Read the
source code, and if you figure it out, write one and send it to me ...
--
*** Makefile
--- new/Makefile
**************
*** 1,5
  #
! #	@(#)Makefile	1.5 - System V shadow password system
  #
  #	@(#)Makefile	1.5	15:59:30	3/4/89
  #
--- 1,5 -----
  #
! #	@(#)Makefile	1.6 - System V shadow password system
  #
  #	@(#)Makefile	1.6	21:15:26	3/26/89
  #
**************
*** 1,7
  #
  #	@(#)Makefile	1.5 - System V shadow password system
  #
! #	@(#)Makefile	1.5	15:59:30	3/4/89
  #
  SHELL = /bin/sh
  # Uncomment the next line if you need fgetpwent()
--- 1,7 -----
  #
  #	@(#)Makefile	1.6 - System V shadow password system
  #
! #	@(#)Makefile	1.6	21:15:26	3/26/89
  #
  SHELL = /bin/sh
  # Uncomment the next line if you need fgetpwent()
**************
*** 9,14
  # Uncomment the next line if you need a64l() and l64a().
  AL64DEF = -DNEED_AL64
  
  # Flags for SCO Xenix/386
  CFLAGS = -O -M3 -g $(PWDEF) $(AL64DEF)
  LIBS = -lcrypt
--- 9,26 -----
  # Uncomment the next line if you need a64l() and l64a().
  AL64DEF = -DNEED_AL64
  
+ # 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
+ 
+ # 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)
  LIBS = -lcrypt
**************
*** 14,19
  LIBS = -lcrypt
  LDFLAGS = -M3 -g
  LTFLAGS = 
  
  # Flags for normal machines
  # CFLAGS = -O -g $(PWDEF) $(AL64DEF)
--- 26,34 -----
  LIBS = -lcrypt
  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)
**************
*** 19,24
  # CFLAGS = -O -g $(PWDEF) $(AL64DEF)
  # LIBS =
  # LDFLAGS = -g
  
  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 \
--- 34,40 -----
  # CFLAGS = -O -g $(PWDEF) $(AL64DEF)
  # LIBS =
  # LDFLAGS = -g
+ # LIBSEC = libsec.a
  
  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 \
**************
*** 22,28
  
  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
  
  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 \
--- 38,44 -----
  
  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
  
  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 \
**************
*** 26,32
  
  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
  
  SOBJS = smain.o env.o password.o entry.o valid.o susetup.o sushell.o \
  	pwent.o susub.o mail.o motd.o sulog.o shadow.o age.o
--- 42,48 -----
  
  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
  
  SOBJS = smain.o env.o password.o entry.o valid.o susetup.o sushell.o \
  	pwent.o susub.o mail.o motd.o sulog.o shadow.o age.o
**************
*** 52,57
  SULOGSRCS = sulogin.c entry.c env.c password.c age.c pwent.c setup.c \
  	shadow.c shell.c valid.c
  
  FILES1 = README log.c mail.c shadow.h sulog.c Makefile entry.c obscure.c \
  	setup.c sub.c config.h pmain.c sulogin.c dialup.h ttytype.c
  
--- 68,78 -----
  SULOGSRCS = sulogin.c entry.c env.c password.c age.c pwent.c setup.c \
  	shadow.c shell.c valid.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
+ 
  FILES1 = README log.c mail.c shadow.h sulog.c Makefile entry.c obscure.c \
  	setup.c sub.c config.h pmain.c sulogin.c dialup.h ttytype.c
  
**************
*** 57,63
  
  FILES2 = lastlog.h login.c motd.c password.c shell.c utmp.c age.c env.c \
  	pwent.c shadow.c valid.c lmain.c smain.c pwconv.c dialup.c dialchk.c \
! 	pwunconv.c
  
  DOCS = login.1 passwd.1 passwd.4 shadow.3 shadow.4 su.1 sulogin.8 pwconv.8 \
  	pwunconv.8
--- 78,84 -----
  
  FILES2 = lastlog.h login.c motd.c password.c shell.c utmp.c age.c env.c \
  	pwent.c shadow.c valid.c lmain.c smain.c pwconv.c dialup.c dialchk.c \
! 	pwunconv.c failure.c faillog.h faillog.c
  
  DOCS = login.1 passwd.1 passwd.4 shadow.3 shadow.4 su.1 sulogin.8 pwconv.8 \
  	pwunconv.8
**************
*** 62,68
  DOCS = login.1 passwd.1 passwd.4 shadow.3 shadow.4 su.1 sulogin.8 pwconv.8 \
  	pwunconv.8
  
! all:	su login pwconv pwunconv passwd sulogin
  
  lint:	su.L login.L pwconv.L pwunconv.L passwd.L sulogin.L
  
--- 83,89 -----
  DOCS = login.1 passwd.1 passwd.4 shadow.3 shadow.4 su.1 sulogin.8 pwconv.8 \
  	pwunconv.8
  
! all:	su login pwconv pwunconv passwd sulogin faillog
  
  libsec: shadow.o
  	ar rv $(LIBSEC) shadow.o
**************
*** 64,70
  
  all:	su login pwconv pwunconv passwd sulogin
  
! lint:	su.L login.L pwconv.L pwunconv.L passwd.L sulogin.L
  
  login:	$(LOBJS)
  	cc -o login $(LDFLAGS) $(LOBJS) $(LIBS)
--- 85,93 -----
  
  all:	su login pwconv pwunconv passwd sulogin faillog
  
! libsec: shadow.o
! 	ar rv $(LIBSEC) shadow.o
! 	$(RANLIB) $(LIBSEC)
  
  install: all
  	cp login $(LOGINDIR)/login
**************
*** 66,73
  
  lint:	su.L login.L pwconv.L pwunconv.L passwd.L sulogin.L
  
! login:	$(LOBJS)
! 	cc -o login $(LDFLAGS) $(LOBJS) $(LIBS)
  
  login.L: $(LSRCS)
  	lint $(LSRCS) > login.L
--- 89,107 -----
  	ar rv $(LIBSEC) shadow.o
  	$(RANLIB) $(LIBSEC)
  
! install: all
! 	cp login $(LOGINDIR)/login
! 	cp pwconv pwunconv sulogin /etc
! 	cp su passwd faillog /bin
! 	chown root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
! 		/bin/su /bin/passwd
! 	chgrp root $(LOGINDIR)/login /etc/pwconv /etc/pwunconv /etc/sulogin \
! 		/bin/su /bin/passwd
! 	chown bin /bin/faillog
! 	chgrp bin /bin/faillog
! 	chmod 700 /etc/pwconv /etc/pwunconv /etc/sulogin
! 	chmod 4711 $(LOGINDIR)/login /bin/su /bin/passwd
! 	chmod 711 /bin/faillog
  
  lint:	su.L login.L pwconv.L pwunconv.L passwd.L sulogin.L faillog.L
  
**************
*** 69,74
  login:	$(LOBJS)
  	cc -o login $(LDFLAGS) $(LOBJS) $(LIBS)
  
  login.L: $(LSRCS)
  	lint $(LSRCS) > login.L
  
--- 103,116 -----
  	chmod 4711 $(LOGINDIR)/login /bin/su /bin/passwd
  	chmod 711 /bin/faillog
  
+ lint:	su.L login.L pwconv.L pwunconv.L passwd.L sulogin.L faillog.L
+ 
+ tags:	$(ALLSRCS)
+ 	$(TAGS) $(ALLSRCS)
+ 
+ login:	$(LOBJS)
+ 	$(CC) -o login $(LDFLAGS) $(LOBJS) $(LIBS)
+ 
  login.L: $(LSRCS)
  	lint $(LSRCS) > login.L
  
**************
*** 73,79
  	lint $(LSRCS) > login.L
  
  su:	$(SOBJS)
! 	cc -o su $(LDFLAGS) $(SOBJS) $(LIBS)
  
  su.L:	$(SSRCS)
  	lint -DSU $(SSRCS) > su.L
--- 115,121 -----
  	lint $(LSRCS) > login.L
  
  su:	$(SOBJS)
! 	$(CC) -o su $(LDFLAGS) $(SOBJS) $(LIBS)
  
  su.L:	$(SSRCS)
  	lint -DSU $(SSRCS) > su.L
**************
*** 79,85
  	lint -DSU $(SSRCS) > su.L
  
  passwd:	$(POBJS)
! 	cc -o passwd $(LDFLAGS) $(POBJS) $(LIBS)
  
  passwd.L: $(PSRCS)
  	lint -DPASSWD $(PSRCS) > passwd.L
--- 121,127 -----
  	lint -DSU $(SSRCS) > su.L
  
  passwd:	$(POBJS)
! 	$(CC) -o passwd $(LDFLAGS) $(POBJS) $(LIBS)
  
  passwd.L: $(PSRCS)
  	lint -DPASSWD $(PSRCS) > passwd.L
**************
*** 85,91
  	lint -DPASSWD $(PSRCS) > passwd.L
  
  pwconv:	$(PWOBJS)
! 	cc -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBS)
  
  pwconv.L: $(PWSRCS)
  	lint -DPASSWD $(PWSRCS) > pwconv.L
--- 127,133 -----
  	lint -DPASSWD $(PSRCS) > passwd.L
  
  pwconv:	$(PWOBJS)
! 	$(CC) -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBS)
  
  pwconv.L: $(PWSRCS)
  	lint -DPASSWD $(PWSRCS) > pwconv.L
**************
*** 91,97
  	lint -DPASSWD $(PWSRCS) > pwconv.L
  
  pwunconv: $(PWUNOBJS)
! 	cc -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBS)
  
  pwunconv.L: $(PWUNSRCS)
  	lint -DPASSWD $(PWUNSRCS) > pwunconv.L
--- 133,139 -----
  	lint -DPASSWD $(PWSRCS) > pwconv.L
  
  pwunconv: $(PWUNOBJS)
! 	$(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBS)
  
  pwunconv.L: $(PWUNSRCS)
  	lint -DPASSWD $(PWUNSRCS) > pwunconv.L
**************
*** 97,103
  	lint -DPASSWD $(PWUNSRCS) > pwunconv.L
  
  sulogin: $(SULOGOBJS)
! 	cc -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBS)
  
  sulogin.L: $(SULOGSRCS)
  	lint $(SULOGSRCS) > sulogin.L
--- 139,145 -----
  	lint -DPASSWD $(PWUNSRCS) > pwunconv.L
  
  sulogin: $(SULOGOBJS)
! 	$(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBS)
  
  sulogin.L: $(SULOGSRCS)
  	lint $(SULOGSRCS) > sulogin.L
**************
*** 102,107
  sulogin.L: $(SULOGSRCS)
  	lint $(SULOGSRCS) > sulogin.L
  
  sushell.o: config.h shell.c
  	cc -c $(CFLAGS) -DSU shell.c
  	mv shell.o sushell.o
--- 144,155 -----
  sulogin.L: $(SULOGSRCS)
  	lint $(SULOGSRCS) > sulogin.L
  
+ faillog: faillog.o
+ 	$(CC) -o faillog $(LDFLAGS) faillog.o $(LIBS)
+ 
+ faillog.L: faillog.c faillog.h config.h
+ 	lint faillog.c > faillog.L
+ 
  sushell.o: config.h shell.c
  	$(CC) -c $(CFLAGS) -DSU shell.c
  	mv shell.o sushell.o
**************
*** 103,109
  	lint $(SULOGSRCS) > sulogin.L
  
  sushell.o: config.h shell.c
! 	cc -c $(CFLAGS) -DSU shell.c
  	mv shell.o sushell.o
  
  susub.o: config.h sub.c
--- 151,157 -----
  	lint faillog.c > faillog.L
  
  sushell.o: config.h shell.c
! 	$(CC) -c $(CFLAGS) -DSU shell.c
  	mv shell.o sushell.o
  
  susub.o: config.h sub.c
**************
*** 107,113
  	mv shell.o sushell.o
  
  susub.o: config.h sub.c
! 	cc -c $(CFLAGS) -DSU sub.c
  	mv sub.o susub.o
  
  sulog.o: config.h
--- 155,161 -----
  	mv shell.o sushell.o
  
  susub.o: config.h sub.c
! 	$(CC) -c $(CFLAGS) -DSU sub.c
  	mv sub.o susub.o
  
  sulog.o: config.h
**************
*** 113,119
  sulog.o: config.h
  
  susetup.o: config.h setup.c
! 	cc -c $(CFLAGS) -DSU setup.c
  	mv setup.o susetup.o
  
  pmain.o: config.h lastlog.h shadow.h
--- 161,167 -----
  sulog.o: config.h
  
  susetup.o: config.h setup.c
! 	$(CC) -c $(CFLAGS) -DSU setup.c
  	mv setup.o susetup.o
  
  pmain.o: config.h lastlog.h shadow.h
**************
*** 120,126
  
  pwage.o: age.c config.h
  	cp age.c pwage.c
! 	cc -c $(CFLAGS) -DPASSWD pwage.c
  	rm pwage.c
  
  lmain.o: config.h lastlog.h
--- 168,174 -----
  
  pwage.o: age.c config.h
  	cp age.c pwage.c
! 	$(CC) -c $(CFLAGS) -DPASSWD pwage.c
  	rm pwage.c
  
  lmain.o: config.h lastlog.h
**************
*** 151,156
  
  valid.o: config.h
  
  clean:
  	-rm -f *.o a.out core npasswd nshadow
  
--- 199,208 -----
  
  valid.o: config.h
  
+ failure.o: faillog.h config.h
+ 
+ faillog.o: faillog.h config.h
+ 
  clean:
  	-rm -f *.o a.out core npasswd nshadow
  
**************
*** 155,161
  	-rm -f *.o a.out core npasswd nshadow
  
  clobber: clean
! 	-rm -f su login passwd pwconv pwunconv sulogin *.L
  
  shar:	login.sh.1 login.sh.2 login.sh.3
  
--- 207,213 -----
  	-rm -f *.o a.out core npasswd nshadow
  
  clobber: clean
! 	-rm -f su login passwd pwconv pwunconv sulogin faillog *.L
  
  shar:	login.sh.1 login.sh.2 login.sh.3
  
*** README
--- new/README
**************
*** 19,25
  Begin by reading and editing the config.h file.  All options are selected
  by using #define's.  A brief description for each available option appears
  below.  You may want to print this file out as it is LONG and you will
! need to refer to it while editting config.h
  
  Note that there are MANY options.  As distributed most options are turned
  on, which produces a really nice package.  This is the system as used on
--- 19,27 -----
  Begin by reading and editing the config.h file.  All options are selected
  by using #define's.  A brief description for each available option appears
  below.  You may want to print this file out as it is LONG and you will
! need to refer to it while editting config.h.  You will also have to edit
! the Makefile.  The possible differences are documented there.  Pay close
! attention to the install: rule.
  
  Note that there are MANY options.  As distributed most options are turned
  on, which produces a really nice package.  This is the system as used on
**************
*** 94,100
  	various utilities.
  
  	Select this option by defining the TZ macro to have
! 	the desired environmental variable value.
  
  Password Aging -
  	This option includes code to perform password aging.
--- 96,103 -----
  	various utilities.
  
  	Select this option by defining the TZ macro to have
! 	the desired environmental variable value, or the name
! 	of the file containing the desired value.
  
  Password Aging -
  	This option includes code to perform password aging.
**************
*** 147,152
  	You will need to determine if you system already has
  	a lastlog.h file and use that file if present.
  
  Terminal Permissions - 
  	This option allows the terminal modes to be set at
  	login time.  This is particularly useful to disable
--- 150,164 -----
  	You will need to determine if you system already has
  	a lastlog.h file and use that file if present.
  
+ Failed Login Logging -
+ 	This option causes a record to be kept of the most
+ 	recent login failure by date and port.  A cummulative
+ 	count of failures is maintained and compared against
+ 	an allowable limit.
+ 
+ 	Select this option by defining the FAILLOG macro.
+ 
+ 	See the file faillog.h for more details.
  Terminal Permissions - 
  	This option allows the terminal modes to be set at
  	login time.  This is particularly useful to disable
*** config.h
--- new/config.h
**************
*** 1,7
  /*
   * Configuration file for login.
   *
!  *	@(#)config.h	1.4	11:17:19	3/8/89
   */
  
  /*
--- 1,7 -----
  /*
   * Configuration file for login.
   *
!  *	@(#)config.h	1.5	21:15:33	3/26/89
   */
  
  /*
**************
*** 64,69
  
  /*
   * Define TZ if login must set timezone
   */
  
  #define	TZ	"TZ=CST6CDT"
--- 64,74 -----
  
  /*
   * 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" */
**************
*** 66,72
   * Define TZ if login must set timezone
   */
  
! #define	TZ	"TZ=CST6CDT"
  
  /*
   * Define the default PATH and SUPATH here.  PATH is for non-privileged
--- 71,78 -----
   * 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
**************
*** 131,136
   */
  
  #define	LASTLOG
  
  /*
   * Define TTYPERM to be the initial terminal permissions.  Defining
--- 137,150 -----
   */
  
  #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 ...
+  */
+ 
+ #define	FAILLOG
  
  /*
   * Define TTYPERM to be the initial terminal permissions.  Defining
*** dialup.c
--- new/dialup.c
**************
*** 2,8
  #include <string.h>
  #include "dialup.h"
  
! static	FILE	*dialpwd;
  
  void	setduent ()
  {
--- 2,10 -----
  #include <string.h>
  #include "dialup.h"
  
! #ifndef	lint
! static	char	_sccsid[] = "@(#)dialup.c	1.2	21:15:35	3/26/89";
! #endif
  
  static	FILE	*dialpwd;
  
**************
*** 4,9
  
  static	FILE	*dialpwd;
  
  void	setduent ()
  {
  	if (dialpwd)
--- 6,13 -----
  static	char	_sccsid[] = "@(#)dialup.c	1.2	21:15:35	3/26/89";
  #endif
  
+ static	FILE	*dialpwd;
+ 
  void	setduent ()
  {
  	if (dialpwd)
**************
*** 34,42
  	if (! dialpwd || feof (dialpwd))
  		return ((struct dialup *) 0);
  
! 	while (fgets (buf, BUFSIZ, dialpwd) == buf)
! 		if (buf[0] == '#')
! 			continue;
  
  	if (feof (dialpwd))
  		return ((struct dialup *) 0);
--- 38,45 -----
  	if (! dialpwd || feof (dialpwd))
  		return ((struct dialup *) 0);
  
! 	while (fgets (buf, BUFSIZ, dialpwd) == buf && buf[0] == '#')
! 		;
  
  	if (feof (dialpwd))
  		return ((struct dialup *) 0);
**************
*** 85,90
  		return (0);
  
  	while (fgets (buf, BUFSIZ, fp) == buf) {
  		buf[strlen (buf) - 1] = '\0';
  
  		if (strcmp (buf, tty) == 0) {
--- 88,96 -----
  		return (0);
  
  	while (fgets (buf, BUFSIZ, fp) == buf) {
+ 		if (buf[0] == '#')
+ 			continue;
+ 
  		buf[strlen (buf) - 1] = '\0';
  
  		if (strcmp (buf, tty) == 0) {
*** lmain.c
--- new/lmain.c
**************
*** 11,17
  #include "lastlog.h"
  
  #ifndef	lint
! static	char	_sccsid[] = "@(#)lmain.c	1.4	15:59:41	3/4/89";
  #endif
  
  #ifndef	ERASECHAR
--- 11,17 -----
  #include "lastlog.h"
  
  #ifndef	lint
! static	char	_sccsid[] = "@(#)lmain.c	1.5	21:15:37	3/26/89";
  #endif
  
  #ifndef	ERASECHAR
**************
*** 63,68
  void	mailcheck ();
  void	shell ();
  
  #ifndef	ALARM
  #define	ALARM	60
  #endif
--- 63,73 -----
  void	mailcheck ();
  void	shell ();
  
+ #ifdef	TZ
+ FILE	*tzfile;
+ char	tzbuf[16] = TZ;
+ #endif
+ 
  #ifndef	ALARM
  #define	ALARM	60
  #endif
**************
*** 95,101
  	 * Add your favorite terminal modes here ...
  	 */
  
! 	termio.c_cflag |= ISIG;
  
  	termio.c_cc[VERASE] = ERASECHAR;
  	termio.c_cc[VKILL] = KILLCHAR;
--- 100,106 -----
  	 * Add your favorite terminal modes here ...
  	 */
  
! 	termio.c_lflag |= ISIG;
  
  	termio.c_cc[VERASE] = ERASECHAR;
  	termio.c_cc[VKILL] = KILLCHAR;
**************
*** 111,117
  		addenv (*envp++);	/* some variables change later */
  
  #ifdef	TZ
! 	addenv (TZ);			/* set the default $TZ, if one */
  #endif
  #ifdef	HZ
  	addenv (HZ);			/* set the default $HZ, if one */
--- 116,132 -----
  		addenv (*envp++);	/* some variables change later */
  
  #ifdef	TZ
! 	if (tzbuf[0] == '/') {
! 		if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
! 			if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
! 				tzbuf[strlen (tzbuf) - 1] = '\0';
! 				addenv (tzbuf);
! 			}
! 			fclose (tzfile);
! 		}
! 	} else {
! 		addenv (tzbuf);
! 	}
  #endif
  #ifdef	HZ
  	addenv (HZ);			/* set the default $HZ, if one */
**************
*** 147,152
  					&& ! password ("Password:", pass))
  			continue;
  #endif
  		if (valid (pass, &pwent)) /* check encrypted passwords ... */
  			break;		/* ... encrypted passwords matched */
  
--- 162,170 -----
  					&& ! password ("Password:", pass))
  			continue;
  #endif
+ #ifdef	FAILLOG
+ 		if (valid (pass, &pwent) && failcheck (pwent.pw_uid))
+ #else
  		if (valid (pass, &pwent)) /* check encrypted passwords ... */
  #endif
  			break;
**************
*** 148,154
  			continue;
  #endif
  		if (valid (pass, &pwent)) /* check encrypted passwords ... */
! 			break;		/* ... encrypted passwords matched */
  
  		if (--retries <= 0)	/* only allow so many failures */
  			exit (1);
--- 166,173 -----
  		if (valid (pass, &pwent) && failcheck (pwent.pw_uid))
  #else
  		if (valid (pass, &pwent)) /* check encrypted passwords ... */
! #endif
! 			break;
  
  		if (--retries <= 0)	/* only allow so many failures */
  			exit (1);
**************
*** 155,160
  
  		puts ("Login incorrect");
  		(void) memset (name, '\0', sizeof name);
  	}
  #ifdef	DIALUP
  	if (! dialcheck (utent.ut_line,
--- 174,183 -----
  
  		puts ("Login incorrect");
  		(void) memset (name, '\0', sizeof name);
+ #ifdef	FAILLOG
+ 		if (pwent.pw_name)	/* don't log non-existent users */
+ 			faillog (pwent.pw_uid, utent.ut_line);
+ #endif
  	}
  #ifdef	DIALUP
  	if (! dialcheck (utent.ut_line,
*** pwconv.c
--- new/pwconv.c
**************
*** 20,26
  #include <fcntl.h>
  #include <pwd.h>
  #include "config.h"
- #include "lastlog.h"
  #include "shadow.h"
  
  #ifndef	lint
--- 20,25 -----
  #include <fcntl.h>
  #include <pwd.h>
  #include "config.h"
  #include "shadow.h"
  
  #ifndef	lint
**************
*** 24,30
  #include "shadow.h"
  
  #ifndef	lint
! static	char	_sccsidi[] = "@(#)pwconv.c	1.2	11:17:22	3/8/89";
  #endif
  
  char	buf[BUFSIZ];
--- 23,29 -----
  #include "shadow.h"
  
  #ifndef	lint
! static	char	_sccsid[] = "@(#)pwconv.c	1.3	21:15:40	3/26/89";
  #endif
  
  char	buf[BUFSIZ];
*** pwunconv.c
--- new/pwunconv.c
**************
*** 15,21
  #include <fcntl.h>
  #include <pwd.h>
  #include "config.h"
- #include "lastlog.h"
  #include "shadow.h"
  
  char	buf[BUFSIZ];
--- 15,20 -----
  #include <fcntl.h>
  #include <pwd.h>
  #include "config.h"
  #include "shadow.h"
  
  #ifndef	lint
**************
*** 17,22
  #include "config.h"
  #include "lastlog.h"
  #include "shadow.h"
  
  char	buf[BUFSIZ];
  char	*l64a ();
--- 16,25 -----
  #include <pwd.h>
  #include "config.h"
  #include "shadow.h"
+ 
+ #ifndef	lint
+ static	char	_sccsid[] = "@(#)pwunconv.c	1.2	21:15:42	3/26/89";
+ #endif
  
  char	buf[BUFSIZ];
  char	*l64a ();
*** setup.c
--- new/setup.c
**************
*** 5,11
  #include "config.h"
  
  #ifndef	lint
! static	char	_sccsid[] = "@(#)setup.c	1.3	08:41:10	2/22/89";
  #endif
  
  extern	char	home[];
--- 5,11 -----
  #include "config.h"
  
  #ifndef	lint
! static	char	_sccsid[] = "@(#)setup.c	1.4	21:15:45	3/26/89";
  #endif
  
  extern	char	home[];
**************
*** 44,50
  struct	passwd	*info;
  {
  	extern	int	errno;
- #ifndef	SU
  	char	logname[30];
  	char	tty[30];
  #endif
--- 44,49 -----
  struct	passwd	*info;
  {
  	extern	int	errno;
  	char	logname[30];
  #ifndef	SU
  	char	tty[30];
**************
*** 46,51
  	extern	int	errno;
  #ifndef	SU
  	char	logname[30];
  	char	tty[30];
  #endif
  	char	*cp;
--- 45,51 -----
  {
  	extern	int	errno;
  	char	logname[30];
+ #ifndef	SU
  	char	tty[30];
  #endif
  	char	*cp;
**************
*** 110,116
  	else
  		addenv (PATH);
  
- #ifndef	SU
  	(void) strcat (strcpy (logname, "LOGNAME="), name);
  	addenv (logname);
  #endif
--- 110,115 -----
  	else
  		addenv (PATH);
  
  	(void) strcat (strcpy (logname, "LOGNAME="), name);
  	addenv (logname);
  
**************
*** 113,119
  #ifndef	SU
  	(void) strcat (strcpy (logname, "LOGNAME="), name);
  	addenv (logname);
! #endif
  	(void) strcat (strcat (strcpy (mail, "MAIL="), MAILDIR), name);
  	addenv (mail);
  }
--- 112,118 -----
  
  	(void) strcat (strcpy (logname, "LOGNAME="), name);
  	addenv (logname);
! 
  	(void) strcat (strcat (strcpy (mail, "MAIL="), MAILDIR), name);
  	addenv (mail);
  }
*** shadow.c
--- new/shadow.c
**************
*** 2,8
  #include <stdio.h>
  #include <string.h>
  
! static	FILE	*shadow;
  
  void	setspent ()
  {
--- 2,10 -----
  #include <stdio.h>
  #include <string.h>
  
! #ifndef	lint
! static	char	_sccsid[] = "@(#)shadow.c	1.2	21:15:47	3/26/89";
! #endif
  
  static	FILE	*shadow;
  
**************
*** 4,9
  
  static	FILE	*shadow;
  
  void	setspent ()
  {
  	if (shadow)
--- 6,13 -----
  static	char	_sccsid[] = "@(#)shadow.c	1.2	21:15:47	3/26/89";
  #endif
  
+ static	FILE	*shadow;
+ 
  void	setspent ()
  {
  	if (shadow)
**************
*** 99,105
  	if (! fp)
  		return (0);
  
! 	return (fprintf (fp, "%s:%s:%ld:%d:%d\n",
  			spwd->sp_namp, spwd->sp_pwdp,
  			spwd->sp_lstchg, spwd->sp_min, spwd->sp_max) != EOF);
  }
--- 103,109 -----
  	if (! fp)
  		return (0);
  
! 	return (fprintf (fp, "%s:%s:%ld:%ld:%ld\n",
  			spwd->sp_namp, spwd->sp_pwdp,
  			spwd->sp_lstchg, spwd->sp_min, spwd->sp_max) != EOF);
  }
*** shell.c
--- new/shell.c
**************
*** 2,8
  #include <string.h>
  #include "config.h"
  
! extern	char	*newenvp[];
  
  void	shell (file)
  char	*file;
--- 2,10 -----
  #include <string.h>
  #include "config.h"
  
! #ifndef	lint
! static	char	_sccsid[] = "@(#)shell.c	1.2	21:15:49	3/26/89";
! #endif
  
  extern	char	*newenvp[];
  
**************
*** 4,9
  
  extern	char	*newenvp[];
  
  void	shell (file)
  char	*file;
  {
--- 6,13 -----
  static	char	_sccsid[] = "@(#)shell.c	1.2	21:15:49	3/26/89";
  #endif
  
+ extern	char	*newenvp[];
+ 
  void	shell (file)
  char	*file;
  {
**************
*** 8,14
  char	*file;
  {
  	char	arg0[BUFSIZ];
- #ifndef	SU
  	char	*path;
  #endif
  	char	*strrchr ();
--- 12,17 -----
  char	*file;
  {
  	char	arg0[BUFSIZ];
  	char	*path;
  	extern	int	errno;
  
**************
*** 10,17
  	char	arg0[BUFSIZ];
  #ifndef	SU
  	char	*path;
- #endif
- 	char	*strrchr ();
  	extern	int	errno;
  
  	if (file == (char *) 0)
--- 13,18 -----
  {
  	char	arg0[BUFSIZ];
  	char	*path;
  	extern	int	errno;
  
  	if (file == (char *) 0)
**************
*** 17,23
  	if (file == (char *) 0)
  		exit (1);
  
- #ifndef	SU
  	if (path = strrchr (file, '/'))
  		path++;
  	else
--- 18,23 -----
  	if (file == (char *) 0)
  		exit (1);
  
  	if (path = strrchr (file, '/'))
  		path++;
  	else
**************
*** 25,33
  
  	(void) strcpy (arg0 + 1, path);
  	arg0[0] = '-';
- #else
- 	(void) strcpy (arg0, "-su");
- #endif
  #ifndef	NDEBUG
  	printf ("Executing shell %s\n", file);
  #endif
--- 25,30 -----
  
  	(void) strcpy (arg0 + 1, path);
  	arg0[0] = '-';
  #ifndef	NDEBUG
  	printf ("Executing shell %s\n", file);
  #endif
*** smain.c
--- new/smain.c
**************
*** 7,13
  #include "lastlog.h"
  
  #ifndef	lint
! static	char	_sccsid[] = "@(#)smain.c	1.5	15:59:55	3/4/89";
  #endif
  
  #ifndef	MAXENV
--- 7,13 -----
  #include "lastlog.h"
  
  #ifndef	lint
! static	char	_sccsid[] = "@(#)smain.c	1.6	21:15:50	3/26/89";
  #endif
  
  #ifndef	MAXENV
**************
*** 38,43
  int	maxenv = MAXENV;
  struct	passwd	pwent;
  
  void	addenv ();
  void	entry ();
  void	sulog ();
--- 38,48 -----
  int	maxenv = MAXENV;
  struct	passwd	pwent;
  
+ #ifdef	TZ
+ FILE	*tzfile;
+ char	tzbuf[16] = TZ;
+ #endif
+ 
  void	addenv ();
  void	entry ();
  void	sulog ();
**************
*** 66,72
  		addenv (*envp++);	/* some variables change later */
  
  #ifdef	TZ
! 	addenv (TZ);			/* set the default $TZ, if one */
  #endif
  #ifdef	HZ
  	addenv (HZ);			/* set the default $HZ, if one */
--- 71,87 -----
  		addenv (*envp++);	/* some variables change later */
  
  #ifdef	TZ
! 	if (tzbuf[0] == '/') {
! 		if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
! 			if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
! 				tzbuf[strlen (tzbuf) - 1] = '\0';
! 				addenv (tzbuf);
! 			}
! 			fclose (tzfile);
! 		}
! 	} else {
! 		addenv (tzbuf);
! 	}
  #endif
  #ifdef	HZ
  	addenv (HZ);			/* set the default $HZ, if one */
*** sulogin.c
--- new/sulogin.c
**************
*** 4,10
  #include <utmp.h>
  #include <string.h>
  #include "config.h"
- #include "lastlog.h"
  
  #ifndef	lint
  static	char	_sccsid[] = "@(#)sulogin.c	1.2	15:59:59	3/4/89";
--- 4,9 -----
  #include <utmp.h>
  #include <string.h>
  #include "config.h"
  
  #ifndef	lint
  static	char	_sccsid[] = "@(#)sulogin.c	1.3	21:15:53	3/26/89";
**************
*** 7,13
  #include "lastlog.h"
  
  #ifndef	lint
! static	char	_sccsid[] = "@(#)sulogin.c	1.2	15:59:59	3/4/89";
  #endif
  
  char	name[BUFSIZ];
--- 6,12 -----
  #include "config.h"
  
  #ifndef	lint
! static	char	_sccsid[] = "@(#)sulogin.c	1.3	21:15:53	3/26/89";
  #endif
  
  char	name[BUFSIZ];
**************
*** 18,24
  
  struct	passwd	pwent;
  struct	utmp	utent;
- struct	lastlog	lastlog;
  
  #ifndef	MAXENV
  #define	MAXENV	64
--- 17,22 -----
  
  struct	passwd	pwent;
  struct	utmp	utent;
  
  #ifdef	TZ
  FILE	*tzfile;
**************
*** 20,25
  struct	utmp	utent;
  struct	lastlog	lastlog;
  
  #ifndef	MAXENV
  #define	MAXENV	64
  #endif
--- 18,28 -----
  struct	passwd	pwent;
  struct	utmp	utent;
  
+ #ifdef	TZ
+ FILE	*tzfile;
+ char	tzbuf[16] = TZ;
+ #endif
+ 
  #ifndef	MAXENV
  #define	MAXENV	64
  #endif
**************
*** 61,67
  		addenv (*envp++);	/* some variables change later */
  
  #ifdef	TZ
! 	addenv (TZ);			/* set the default $TZ, if one */
  #endif
  #ifdef	HZ
  	addenv (HZ);			/* set the default $HZ, if one */
--- 64,80 -----
  		addenv (*envp++);	/* some variables change later */
  
  #ifdef	TZ
! 	if (tzbuf[0] == '/') {
! 		if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
! 			if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
! 				tzbuf[strlen (tzbuf) - 1] = '\0';
! 				addenv (tzbuf);
! 			}
! 			fclose (tzfile);
! 		}
! 	} else {
! 		addenv (tzbuf);
! 	}
  #endif
  #ifdef	HZ
  	addenv (HZ);			/* set the default $HZ, if one */
SHAR_EOF
fi
if test -f 'faillog.c'
then
	echo shar: "will not over-write existing file 'faillog.c'"
else
cat << \SHAR_EOF > 'faillog.c'
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <pwd.h>
#include <time.h>
#include "config.h"
#include "faillog.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)faillog.c	1.1	20:42:41	3/26/89";
#endif

FILE	*fail;		/* failure file stream */
off_t	user;		/* one single user, specified on command line */
int	days;		/* number of days to consider for print command */
time_t	seconds;	/* that number of days in seconds */
int	max;		/* maximum failure count for fail_max */

int	mflg;		/* set fail_max for a given user */
int	rflg;		/* reset fail_cnt for user or all user's */
int	uflg;		/* set if user is a valid user id */
int	tflg;		/* print is restricted to most recent days */
struct	faillog	faillog; /* scratch structure to play with ... */
struct	stat	statbuf; /* fstat buffer for file size */

extern	int	optind;
extern	char	*optarg;
extern	char	*asctime ();
extern	struct	passwd	*getpwuid ();
extern	struct	passwd	*getpwnam ();
extern	struct	passwd	*getpwent ();
extern	struct	tm	*localtime ();

#define	DAY	(24L*3600L)
#define	NOW	(time ((time_t *) 0))

main (argc, argv)
int	argc;
char	**argv;
{
	char	*mode;
	int	uid = 0;
	int	c;
	struct	passwd	*pwent;

	if (getuid () == 0)	/* only root can update anything */
		mode = "r+";
	else			/* all others can only look */
		mode = "r";

	if ((fail = fopen (FAILFILE, mode)) == (FILE *) 0) {
		perror (FAILFILE);
		exit (1);
	}
	while ((c = getopt (argc, argv, "m:pru:t:")) != EOF) {
		switch (c) {
			case 'm':
				max = atoi (optarg);
				setmax ();
				break;
			case 'p':
				print ();
				break;
			case 'r':
				reset ();
				break;
			case 'u':
				pwent = getpwnam (optarg);
				if (! pwent) {
					fprintf (stderr, "Unknown User: %s\n", optarg);
					exit (1);
				}
				uflg++;
				user = pwent->pw_uid;
				break;
			case 't':
				days = atoi (optarg);
				seconds = days * DAY;
				tflg++;
				break;
		}
	}
	fclose (fail);
	exit (0);
}

print ()
{
	int	uid;
	off_t	offset;

	if (uflg) {
		offset = user * sizeof faillog;
		fstat (fileno (fail), &statbuf);
		if (offset >= statbuf.st_size)
			return;

		fseek (fail, (off_t) user * sizeof faillog, 0);
		if (fread ((char *) &faillog, sizeof faillog, 1, fail) == 1)
			print_one (&faillog, user);
		else
			perror (FAILFILE);
	} else {
		for (uid = 0;
			fread ((char *) &faillog, sizeof faillog, 1, fail) == 1;
				uid++) {

			if (faillog.fail_cnt == 0)
				continue;

			if (tflg && NOW - faillog.fail_time > seconds)
				continue;

			print_one (&faillog, uid);
		}
	}
}

print_one (faillog, uid)
struct	faillog	*faillog;
{
	static	int	once;
	char	*cp;
	struct	tm	*tm;
	struct	passwd	*pwent;

	if (! once) {
		printf ("Username        Failures    Maximum     Latest\n");
		once++;
	}
	pwent = getpwuid (uid);
	tm = localtime (&faillog->fail_time);
	cp = asctime (tm);
	cp[24] = '\0';

	if (pwent) {
		printf ("%-16s    %4d       %4d",
			pwent->pw_name, faillog->fail_cnt, faillog->fail_max);
		if (faillog->fail_time)
			printf ("     %s on %s\n", cp, faillog->fail_line);
		else
			putchar ('\n');
	}
}

reset ()
{
	int	uid = 0;

	if (uflg)
		reset_one (user);
	else
		for (uid = 0;reset_one (uid);uid++)
			;
}

reset_one (uid)
int	uid;
{
	off_t	offset;

	offset = uid * sizeof faillog;
	fstat (fileno (fail), &statbuf);
	if (offset >= statbuf.st_size)
		return (0);

	if (fseek (fail, offset, 0) != 0) {
		perror (FAILFILE);
		return (0);
	}
	if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
		if (! feof (fail))
			perror (FAILFILE);

		return (0);
	}
	if (faillog.fail_cnt == 0)
		return (1);	/* don't fill in no holes ... */

	faillog.fail_cnt = 0;

	if (fseek (fail, offset, 0) == 0
		&& fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) {
		fflush (fail);
		return (1);
	} else {
		perror (FAILFILE);
	}
	return (0);
}

setmax ()
{
	int	uid = 0;
	struct	passwd	*pwent;

	if (uflg) {
		setmax_one (user);
	} else {
		setpwent ();
		while (pwent = getpwent ())
			setmax_one (pwent->pw_uid);
	}
}

setmax_one (uid)
int	uid;
{
	off_t	offset;

	offset = uid * sizeof faillog;

	if (fseek (fail, offset, 0) != 0) {
		perror (FAILFILE);
		return;
	}
	if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
		if (! feof (fail))
			perror (FAILFILE);
	} else {
		memset ((char *) &faillog, '\0', sizeof faillog);
	}
	faillog.fail_max = max;

	if (fseek (fail, offset, 0) == 0
		&& fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1)
		fflush (fail);
	else
		perror (FAILFILE);
}
SHAR_EOF
fi
if test -f 'faillog.h'
then
	echo shar: "will not over-write existing file 'faillog.h'"
else
cat << \SHAR_EOF > 'faillog.h'
/*
 * faillog.h - login failure logging file format
 *
 *	@(#)faillog.h	1.1	20:43:01	3/26/89
 *
 * The login failure file is maintained by login(1) and fail(1L)
 * Each record in the file represents a separate UID and the file
 * is indexed in that fashion.
 */

#define	FAILFILE	"/usr/adm/faillog"

struct	faillog {
	short	fail_cnt;	/* failures since last success */
	short	fail_max;	/* failures before turning account off */
	char	fail_line[12];	/* last failure occured here */
	time_t	fail_time;	/* last failure occured then */
};
SHAR_EOF
fi
if test -f 'failure.c'
then
	echo shar: "will not over-write existing file 'failure.c'"
else
cat << \SHAR_EOF > 'failure.c'
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include "faillog.h"
#include "config.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)failure.c	1.1	21:06:32	3/26/89";
#endif

#ifdef	FAILLOG

#define	DAY	(24L*3600L)
#define	YEAR	(365L*DAY)
#define	NOW	(time ((time_t *) 0))

extern	struct	tm	*localtime ();
extern	char	*asctime;
extern	void	failprint ();

/*
 * faillog - make failure entry
 */

void
faillog (uid, tty)
int	uid;
char	*tty;
{
	int	fd;
	struct	faillog	faillog;

	if ((fd = open (FAILFILE, O_RDWR)) < 0)
		return;

	lseek (fd, (off_t) sizeof faillog * uid, 0);
	if (read (fd, (char *) &faillog, sizeof faillog)
			!= sizeof faillog)
		memset ((void *) &faillog, '\0', sizeof faillog);

	if (faillog.fail_max == 0 || faillog.fail_cnt < faillog.fail_max)
		faillog.fail_cnt++;

	strncpy (faillog.fail_line, tty, sizeof faillog.fail_line);
	faillog.fail_time = time ((time_t *) 0);

	lseek (fd, (off_t) sizeof faillog * uid, 0);
	write (fd, (char *) &faillog, sizeof faillog);
	close (fd);
	return;
}

/*
 * failcheck - check for failures > allowable, reset count if not
 *
 * failcheck() is called AFTER the password has been validated.
 */

int	failcheck (uid)
int	uid;
{
	int	fd;
	int	okay = 1;
	struct	faillog	faillog;

	if ((fd = open (FAILFILE, O_RDWR)) < 0)
		return (1);

	lseek (fd, (off_t) sizeof faillog * uid, 0);
	if (read (fd, (char *) &faillog, sizeof faillog) == sizeof faillog) {
		if (faillog.fail_max != 0
				&& faillog.fail_cnt >= faillog.fail_max)
			okay = 0;
		else {
			if (faillog.fail_cnt)
				failprint (&faillog);

			faillog.fail_cnt = 0;
			lseek (fd, (off_t) sizeof faillog * uid, 0);
			write (fd, (char *) &faillog, sizeof faillog);
		}
	}
	close (fd);
	return (okay);
}

/*
 * failprint - print line of failure information
 */

void	failprint (fail)
struct	faillog	*fail;
{
	struct	tm	*tp;
	char	*lasttime;

	if (fail->fail_cnt == 0)
		return;

	tp = localtime (&fail->fail_time);
	lasttime = asctime (tp);
	lasttime[24] = '\0';

	if (NOW - fail->fail_time < YEAR)
		lasttime[19] = '\0';
	if (NOW - fail->fail_time < DAY)
		lasttime = lasttime + 11;

	if (*lasttime == ' ')
		lasttime++;

	printf ("%d %s since last login.  Last was %s on %s.\n",
		fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure",
		lasttime, fail->fail_line);
}
#endif
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
John F. Haugh II                        +-Quote of the Week:-------------------
VoiceNet: (214) 250-3311   Data: -6272  | "Do not drink and bake"
InterNet: jfh@rpp386.Dallas.TX.US       |         -- Arnold Swartzenegger
UucpNet : <backbone>!killer!rpp386!jfh  +--------------------------------------