#! /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:
#	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
# This archive created: Tue Jun 20 01:28:03 1989
# By:	John F. Haugh II (River Parishes Programming, Plano TX)
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
This is the explanatory document for John F. Haugh II's login replacement.

This software is copyright 1989, John F. Haugh II.  All rights reserved.
Use, duplication and disclosure is permitted according to the guidelines
listed below.  At some point in the future this licence will be
modified to conform to the GNU General Public License.

This software is being provided as a freely redistributable login clone.
You may distribute this software provided you do not charge for other than
transmission costs.  You are free to transfer this software provided you
do not restrict the rights of the recipients to further transfer this 
software.

This software is being distributed AS-IS.  The author disclaims all
liability for any consequences of use.  The user is solely responsible
for the maintenance of this software package.  The author is under no
obligation to provide modifications or improvements.

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.  DO NOT MAIL ME DIFFERENCES FOR VARIOUS
INSTALLATION PROBLEMS.  If you must share your experiences, do so on the
net.  Login now runs on about 15 different varieties of UNIX that I have
been made aware of.

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
the authors machine.  [ The one exception is NOBLANK, that is turned off
because of anonymous UUCP logins. ]

Dialup Password Files -
	This option permits individual ports to have an additional
	password prompted for on a by-shell basis.  /etc/dialups
	contains a list of dialup ports, d_passwd contains the
	password for each shell requiring a dialup password.

	Select this option by defining the DIALUP macro.

Shadow [ unreadable ] Password Files -
	This option utilizes an alternate, non-readable file to
	contain the actual encrypted passwords.  This is presumed
	to increase system security by increasing the difficulty
	with which system crackers obtain encrypted passwords.

	Select this option by defining the SHADOWPWD macro.

Double Length Passwords -
	This option extends the maximum length of a user password
	to 16 characters from eight.

	Select this option by defining the DOUBLESIZE macro.
	Credit for this option is due Jonathan Bayer.

Obscure Password Testing -
	This option includes code to test user passwords for
	complexity.  The programmer is encouraged to edit the
	file obscure.c to add additional methods for detecting
	simplistic passwords.

	Select this option by defining the OBSCURE macro.

	Additionally, the PASSLENGTH macro must be defined to
	control the minimum length for a legal password.

Mandatory Password Prompting -
	This option requires all passwords, including null ones,
	to be prompted for.  Traditionally an account with a
	password field of '::' does not require prompting for.
	This option modifies this behavior to require even
	null passwords be prompted for.

	Select this option by defining the NOBLANK macro.

Password Aging Defaults -
	You may select the default number of days during which a
	password is valid.  The pwconv command adds aging
	information to accounts which do not include it already.

	The MINDAYS macro must be defined to be the minimum
	number of days which must pass before a password may be
	changed.  The MAXDAYS macro must be defined to be the
	maximum number of days which a password will remain
	valid during.

HZ Environmental Variable -
	This option pre-defines the HZ environmental variable.
	Certain systems require this variable be defined for
	system time reporting functions to work properly.

	Select this option by defining the HZ macro to have
	the desired environmental variable value.

TZ Environmental Variable -
	This option pre-defines the TZ environmental variable.
	This provides a default timezone variable for use by
	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.
	Password aging is presumed to increase system security
	by forcing users to change passwords on a regular
	basis.  The resolution on password age is in weeks for
	non-shadow password systems and in days otherwise.

	Select this option by defining the AGING macro.

Mailbox Checking -
	This option includes code to check the status of the
	user's mailbox.  One of three messages are produced
	depending on the status of the user's mailbox.

	Select this option by defining the MAILCHECK macro.

Console Restricted Root Logins -
	This option restricts the port which root may legally
	login on.  This option presumably increases system
	security by preventing outside attacks against the root
	account.

	Select this option by defining the CONSOLE macro to
	have the desired port name.  If this file is a regular
	file, it is considered to contain a list of legal port
	names, one per line.  Note that the port names DO NOT
	begin with "/dev/" and that a file name would have to
	be fully qualified.  See config.h for a pair of
	examples.

Restricted User Logins -
	This option permits you to specify a file which disables
	user logins.  This options permits you to keep normal
	users off of the system while performing maintenance
	functions.

	Select this option by defining NOLOGINS to be the name
	of the file to use.

Restricted Use Accounts -
	This option permits certain accounts to be used for
	identification purposes only.  This options associates
	login ID's with UID's, such as for disk space accounting
	or anonymous FTP accounts.  Passwords for these accounts
	may only be changed by root.

	Select this option by defining NOUSE to be the string
	to include in the password file in place of the user's
	shell.

Message of the Day Printing -
	This option causes the message of the day to be
	printed at login time.

	Select this option by defining the MOTD macro.

	If you wish this feature to be overriden on a per-user
	basis, define the macro HUSHLOGIN and users may then
	turn off the /etc/motd message by creating a file
	'.hushlogin' in their home directories.

Last Login Time Logging -
	This option causes a record to be made of successful
	logins in /usr/adm/lastlog.  The format of the
	structure is defined in lastlog.h.

	Select this option by defining the LASTLOG macro.

	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
	messages on user's terminals.

	Select this option by defining the TTYPERM macro as
	having the desired mode.

Terminal Type Setup -
	This option allows the terminal type to be set at
	login time.  The environmental variable TERM will be
	set from the specified terminal to port mapping
	file.

	Select this option by defining the TTYTYPE macro as
	having the value of the name of the type to port
	mapping file.  Credit for this option is due Chip
	Rosenthal.

File Size Setting -
	This option includes code to set the user's ulimit
	at login time.  Additional code to set the umask and
	nice value is also included.

	Select this option by defining the QUOTAS macro.

Switch-User Logging -
	This option causes su(1) to log attempts to switch
	users.  Su(1) will log all attempt, giving the old
	and new user ID's, tty port, and time.  It also
	indicates if the attempt was successful.

	Select this option by defining the SULOG macro to
	have the value of the name of the file you want
	attempts logged to.

Configurable Editing Keys -
	This options allows the erase and kill characters to
	be selected.  A default value is provided.  By default
	ERASE will be ^H and KILL will be ^U.

	Select this option by defining the ERASECHAR macro
	to be the desired erase character and the KILLCHAR 
	macro to be the desired KILL character.

Default ulimit and umask Values -
	This option allows you to select the default values
	for ulimit and umask, allowing you to avoid
	regenerating your system kernel.  These values may be
	overriden with appropriate entries in the GECOS field.

	Select the default ulimit by defining the ULIMIT
	macro, and the default umask by defining the UMASK
	macro.
	
	Warning: These values will not apply to processes
	executed by /etc/cron or any of their children.

BSD Notes:	Steve Simmons	s...@iti.org

The full port of the shadow package to BSD is not complete; but some
of the issues have been worked out.  These notes describe the current
state of things:

In order to make use of password aging under BSD, minor changes to
/usr/include/pwd.h and getpwent() are needed.  These changes are to
keep the password age from messing up the encrypted password when not
using shadow passwords, and involve placing a new field in the password
data structure.  To use this, you should apply the following two patches:
	pwd.h.patch
	getpwent.c.patch
to the BSD /usr/include/pwd.h and /usr/src/lib/libc/gen/getpwent.c,
respectively.  After applying the patches, rebuild your standard C
library with the new getpwent.  Programs which use the old getpwent
will fail on password checking if they do a strcmp rather than a strncmp.

These changes are based on BSD4.3, not Tahoe

ToDo BSD:

I'm working on this in my copious spare time (hah!); any help would
be appreciated.  If you decide to help, do these independantly rather
than rework BSD code!  Keep it redistributable!

No dbm functions have been put in place.  Dbm functionality is needed
for both /etc/password and /etc/shadow management.

The BSD GECOS field gets used for lots more stuff than the USG.  At a
minimum this functionality should be duplicated under BSD; better is to put
it into USG as well; still better would be to make the chfn command for
both systems; best would be site-configurable data to be put into GECOS/chfn.
SHAR_EOF
fi
if test -f 'log.c'
then
	echo shar: "will not over-write existing file 'log.c'"
else
cat << \SHAR_EOF > 'log.c'
#include <sys/types.h>
#include <utmp.h>
#include <pwd.h>
#include <fcntl.h>
#include <time.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "config.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)log.c	2.1	01:23:21	6/20/89";
#endif

#ifdef	LASTLOG

#include "lastlog.h"

extern	struct	utmp	utent;
extern	struct	passwd	pwent;
extern	struct	lastlog	lastlog;
extern	char	**environ;

long	lseek ();
time_t	time ();

void	log ()
{
	int	fd;
	off_t	offset;
	struct	lastlog	newlog;

	if ((fd = open ("/usr/adm/lastlog", O_RDWR)) == -1)
		return;

	offset = pwent.pw_uid * sizeof lastlog;

	if (lseek (fd, offset, 0) != offset) {
		(void) close (fd);
		return;
	}
	if (read (fd, (char *) &lastlog, sizeof lastlog) != sizeof lastlog)
#ifndef	BSD
		memset ((char *) &lastlog, sizeof lastlog, 0);
#else
		bzero ((char *) &lastlog, sizeof lastlog);
#endif
	newlog = lastlog;

	(void) time (&newlog.ll_time);
	(void) strncpy (newlog.ll_line, utent.ut_line, sizeof newlog.ll_line);
	(void) lseek (fd, offset, 0);
	(void) write (fd, (char *) &newlog, sizeof newlog);
	(void) close (fd);
}
#endif
SHAR_EOF
fi
if test -f 'mail.c'
then
	echo shar: "will not over-write existing file 'mail.c'"
else
cat << \SHAR_EOF > 'mail.c'
#include <sys/types.h>
#include <sys/stat.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "config.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)mail.c	2.1	01:23:26	6/20/89";
#endif

extern	char	mail[];

#ifdef	HUSHLOGIN
extern	int	hushed;
#endif

#ifdef	MAILCHECK
void	mailcheck ()
{
	struct	stat	statbuf;
	char	*mailbox;

#ifdef	HUSHLOGIN
	if (hushed)
		return;
#endif
	if (mailbox = strchr (mail, '='))
		mailbox++;
	else
		return;

	if (stat (mailbox, &statbuf) == -1 || statbuf.st_size == 0)
		puts ("No mail.");
	else if (statbuf.st_atime > statbuf.st_mtime)
		puts ("You have mail.");
	else
		puts ("You have new mail.");
}
#endif
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'
/*
 * This information is not derived from AT&T licensed sources.  Posted
 * to the USENET 11/88.
 *
 *	@(#)shadow.h	2.1	01:23:51	6/20/89
 */

/*
 * 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_max;		/* maximum number of days between changes */
	long	sp_min;		/* minimum number of days between changes */
};

/*
 * Shadow password security file functions.
 */

struct	spwd	*getspent ();
struct	spwd	*getspnam ();
void	setspent ();
void	endspent ();
struct	spwd	*fgetspent ();
int	putspent ();

#define  SHADOW "/etc/shadow"
SHAR_EOF
fi
if test -f 'sulog.c'
then
	echo shar: "will not over-write existing file 'sulog.c'"
else
cat << \SHAR_EOF > 'sulog.c'
#include <sys/types.h>
#include <stdio.h>
#include <time.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "config.h"

extern	char	name[];
extern	char	oldname[];

time_t	time ();

void	sulog (success)
int	success;
{
#ifdef	SULOG
	char	*tty;
	char	*cp;
	char	*ttyname ();
	time_t	clock;
	struct	tm	*tm;
	struct	tm	*localtime ();
	FILE	*fp;

	if ((fp = fopen (SULOG, "a+")) == (FILE *) 0)
		return;			/* can't open or create logfile */

	(void) time (&clock);
	tm = localtime (&clock);

	if (isatty (0) && (cp = ttyname (0))) {
		if (tty = strrchr (cp, '/'))
			tty++;
		else
			tty = cp;
	} else
		tty = "???";

	(void) fprintf (fp, "SU %.02d/%0.2d %.02d:%.02d %c %.6s %s-%s\n",
		tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
		success ? '+':'-', tty, oldname, name);

	fflush (fp);
	fclose (fp);
#endif
}
SHAR_EOF
fi
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
#
#	%W%	%U%  - System V shadow password system
#
#	%W%	%U%	%G%
#
SHELL = /bin/sh

# 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 = -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
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

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 \
	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

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

POBJS = pmain.o password.o entry.o valid.o pwage.o pwent.o obscure.o shadow.o

PSRCS = pmain.c password.c entry.c valid.c age.c pwent.c obscure.c shadow.c

PWOBJS = pwconv.o pwent.o shadow.o pwage.o

PWSRCS = pwconv.c pwent.c shadow.c age.c

PWUNOBJS = pwunconv.o pwent.o shadow.o pwage.o

PWUNSRCS = pwunconv.c pwent.c shadow.c age.c

SULOGOBJS = sulogin.o entry.o env.o password.o pwage.o pwent.o setup.o \
	shadow.o shell.o valid.o

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

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 faillog.8 faillog.4

all:	su login pwconv pwunconv passwd sulogin faillog

libsec: shadow.o
	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

tags:	$(ALLSRCS)
	$(TAGS) $(ALLSRCS)

login:	$(LOBJS)
	$(CC) -o login $(LDFLAGS) $(LOBJS) $(LIBS)

login.L: $(LSRCS)
	lint $(LSRCS) > login.L

su:	$(SOBJS)
	$(CC) -o su $(LDFLAGS) $(SOBJS) $(LIBS)

su.L:	$(SSRCS)
	lint -DSU $(SSRCS) > su.L

passwd:	$(POBJS)
	$(CC) -o passwd $(LDFLAGS) $(POBJS) $(LIBS)

passwd.L: $(PSRCS)
	lint -DPASSWD $(PSRCS) > passwd.L

pwconv:	$(PWOBJS)
	$(CC) -o pwconv $(LDFLAGS) $(PWOBJS) $(LIBS)

pwconv.L: $(PWSRCS)
	lint -DPASSWD $(PWSRCS) > pwconv.L

pwunconv: $(PWUNOBJS)
	$(CC) -o pwunconv $(LDFLAGS) $(PWUNOBJS) $(LIBS)

pwunconv.L: $(PWUNSRCS)
	lint -DPASSWD $(PWUNSRCS) > pwunconv.L

sulogin: $(SULOGOBJS)
	$(CC) -o sulogin $(LDFLAGS) $(SULOGOBJS) $(LIBS)

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

susub.o: config.h sub.c
	$(CC) -c $(CFLAGS) -DSU sub.c
	mv sub.o susub.o

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

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

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

clean:
	-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

login.sh.1: $(FILES1)
	shar $(FILES1) > login.sh.1

login.sh.2: $(FILES2)
	shar $(FILES2) > login.sh.2

login.sh.3: $(DOCS)
	shar $(DOCS) > login.sh.3
SHAR_EOF
fi
if test -f 'entry.c'
then
	echo shar: "will not over-write existing file 'entry.c'"
else
cat << \SHAR_EOF > 'entry.c'
#include <stdio.h>
#include <pwd.h>
#ifndef	BSD
#include <string.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "config.h"
#ifdef	SHADOWPWD
#include "shadow.h"
#endif

#ifndef	lint
static	char	_sccsid[] = "@(#)entry.c	2.1	01:23:09	6/20/89";
#endif

struct	passwd	*fgetpwent ();
char	*malloc ();

char	*strdup (s)
char	*s;
{
	char	*cp;

	if (s == (char *) 0)
		return ((char *) 0);

	if (! (cp = malloc ((unsigned) strlen (s) + 1)))
		return ((char *) 0);

	return (strcpy (cp, s));
}

void	entry (name, pwent)
char	*name;
struct	passwd	*pwent;
{
	FILE	*pwd;
	struct	passwd	*passwd;
#ifdef	SHADOWPWD
	struct	spwd	*spwd;
	char	*l64a ();
#endif
	char	*cp;

	if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) {
		pwent->pw_passwd = (char *) 0;
		return;
	}
	while (passwd = fgetpwent (pwd)) {
		if (strcmp (name, passwd->pw_name) == 0)
			break;
	}
	fclose (pwd);

	if (passwd == (struct passwd *) 0) {
		pwent->pw_name = (char *) 0;
		pwent->pw_passwd = (char *) 0;
	} else  {
		pwent->pw_name = strdup (passwd->pw_name);
		pwent->pw_uid = passwd->pw_uid;
		pwent->pw_gid = passwd->pw_gid;
		pwent->pw_comment = (char *) 0;
		pwent->pw_gecos = strdup (passwd->pw_gecos);
		pwent->pw_dir = strdup (passwd->pw_dir);
		pwent->pw_shell = strdup (passwd->pw_shell);
#ifdef	SHADOWPWD
		setspent ();
		if (spwd = getspnam (name)) {
			pwent->pw_passwd = strdup (spwd->sp_pwdp);
			if (spwd->sp_lstchg != 0) {
				pwent->pw_age = (char *) 0;
			} else {
				pwent->pw_age = malloc (5);
				pwent->pw_age[0] = i64c (spwd->sp_max / 7);
				pwent->pw_age[1] = i64c (spwd->sp_min / 7);
				cp = l64a (spwd->sp_lstchg / 7);
				pwent->pw_age[2] = cp[0];
				pwent->pw_age[3] = cp[1];
				pwent->pw_age[4] = '\0';
			}
			endspent ();
			return;
		}
		endspent ();
		passwd->pw_age = pwent->pw_age = (char *) 0;
#endif
		if (passwd->pw_passwd)
			pwent->pw_passwd = strdup (passwd->pw_passwd);
		else
			pwent->pw_passwd = (char *) 0;

		if (passwd->pw_age) {
			pwent->pw_age = malloc (5);	/* longest legal time */
			(void) strncpy (pwent->pw_age, passwd->pw_age, 5);
		} else
			pwent->pw_age = (char *) 0;
	}
}
SHAR_EOF
fi
if test -f 'obscure.c'
then
	echo shar: "will not over-write existing file 'obscure.c'"
else
cat << \SHAR_EOF > 'obscure.c'
#include <ctype.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "config.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)obscure.c	2.1	01:23:29	6/20/89";
#endif

/*
 * Obscure - see if password is obscure enough.
 *
 *	The programmer is encouraged to add as much complexity to this
 *	routine as desired.  Included are some of my favorite ways to
 *	check passwords.
 */

extern	char	pass[];			/* the new password */
extern	char	orig[];			/* the original password */
#ifdef	OBSCURE
char	mono[32];			/* a monocase version of pass */
#endif
int	obscure ()
{
#ifdef	OBSCURE
	int	i;
#endif
	if (orig[0] == '\0')
		return (1);

	if (strlen (pass) < PASSLENGTH) { /* too short */
		printf ("Too short.  ");
		return (0);
	}
#ifdef	OBSCURE
	for (i = 0;pass[i];i++)
		mono[i] = tolower (pass[i]);

	if (strcmp (pass, orig) == 0)	/* the same */
		return (0);

	if (palindrome ())		/* a palindrome */
		return (0);

	if (caseshift ())		/* upper/lower case changes only */
		return (0);

	if (similiar ())		/* jumbled version of original */
		return (0);
#endif
	return (1);
}

#ifdef	OBSCURE

/*
 * can't be a palindrome - like `R A D A R' or `M A D A M'
 */

int	palindrome ()
{
	int	i, j;

	i = strlen (pass);

	for (j = 0;j < i;j++)
		if (pass[i - j - 1] != pass[j])
			return (0);

	printf ("No palindromes.  ");
	return (1);
}

/*
 * may not be a shifted version of original
 */

int	caseshift ()
{
	int	i;

	for (i = 0;pass[i] && orig[i];i++) {
		if (tolower (pass[i]) == tolower (orig[i]))
			continue;
		else
			return (0);
	}
	printf ("May not be case-shifted.  ");
	return (1);
}

/*
 * more than half of the characters are different ones.
 */

int	similiar ()
{
	int	i, j;
	char	*strchr ();

	for (i = j = 0;pass[i] && orig[i];i++)
		if (strchr (mono, tolower (orig[i])))
			j++;

	if (i - j > 2)
		return (0);

	printf ("Too similiar.  ");
	return (1);
}
#endif
SHAR_EOF
fi
if test -f 'setup.c'
then
	echo shar: "will not over-write existing file 'setup.c'"
else
cat << \SHAR_EOF > 'setup.c'
#include <sys/types.h>
#include <pwd.h>
#include <utmp.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "config.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)setup.c	2.1	01:23:45	6/20/89";
#endif

extern	char	home[];
extern	char	prog[];
extern	char	name[];
extern	char	mail[];

#ifndef	PATH
#define	PATH	":/bin:/usr/bin"
#endif

#ifndef	SUPATH
#define	SUPATH	":/bin:/usr/bin:/etc"
#endif

#ifndef	MAILDIR
#define	MAILDIR	"/usr/spool/mail"
#endif

#ifndef	TTYPERM
#define	TTYPERM	0622
#endif

#ifndef	SU
extern	struct	utmp	utent;
#endif

#ifdef	QUOTAS
long	strtol ();
#ifdef	ULIMIT
long	ulimit ();
#endif
#endif

void	addenv ();

void	setup (info)
struct	passwd	*info;
{
	extern	int	errno;
	char	logname[30];
#ifndef	SU
	char	tty[30];
#endif
	char	*cp;
	int	i;
	long	l;

#ifndef	SU
	(void) strcat (strcpy (tty, "/dev/"), utent.ut_line);
	if (chown (tty, info->pw_uid, info->pw_gid) ||
					chmod (tty, TTYPERM))
		perror (tty);
#endif
	if (chdir (info->pw_dir) == -1) {
		(void) printf ("Unable to change directory to \"%s\"\n", info->pw_dir);
		exit (errno);
	}
#ifdef	QUOTAS
	for (cp = info->pw_gecos;cp != (char *) 0;cp = strchr (cp, ',')) {
		if (*cp == ',')
			cp++;

		if (strncmp (cp, "pri=", 4) == 0) {
			i = atoi (cp + 4);
			if (i >= -20 && i <= 20)
				(void) nice (i);

			continue;
		}
#ifdef	ULIMIT
		if (strncmp (cp, "ulimit=", 7) == 0) {
			l = strtol (cp + 7, (char **) 0, 10);
			(void) ulimit (2, l);

			continue;
		}
#endif
		if (strncmp (cp, "umask=", 6) == 0) {
			i = strtol (cp + 6, (char **) 0, 8) & 0777;
			(void) umask (i);

			continue;
		}
	}
#endif
	if (setgid (info->pw_gid) == -1) {
		puts ("Bad group id");
		exit (errno);
	}
#ifndef	BSD
	if (setuid (info->pw_uid))
#else
	if (setreuid (info->pw_uid, info->pw_uid))
#endif
	{
		puts ("Bad user id");
		exit (errno);
	}
	(void) strcat (strcpy (home, "HOME="), info->pw_dir);
	addenv (home);

	if (info->pw_shell == (char *) 0)
		info->pw_shell = "/bin/sh";

	(void) strcat (strcpy (prog, "SHELL="), info->pw_shell);
	addenv (prog);

	if (info->pw_uid == 0)
		addenv (SUPATH);
	else
		addenv (PATH);

	(void) strcat (strcpy (logname, "LOGNAME="), name);
	addenv (logname);

	(void) strcat (strcat (strcpy (mail, "MAIL="), MAILDIR), name);
	addenv (mail);
}
SHAR_EOF
fi
if test -f 'sub.c'
then
	echo shar: "will not over-write existing file 'sub.c'"
else
cat << \SHAR_EOF > 'sub.c'
#include <sys/types.h>
#include <pwd.h>
#include <utmp.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[] = "@(#)sub.c	2.1	01:23:58	6/20/89";
#endif

extern	struct	passwd	pwent;
#ifndef	SU
extern	struct	utmp	utent;
#endif

void	setutmp ();

/*
 * I have heard of two different types of behavior with subsystem roots.
 * One has you execute login no matter what.  The other has you execute
 * the command [ if one exists ] after the '*' in the shell name.  The
 * macro SUBLOGIN says to execute /bin/login [ followed by /etc/login ]
 * regardless.  Otherwise, pwent.pw_shell is fixed up and that command
 * is executed [ by returning to the caller ].  I prefer the latter since
 * it doesn't require having a "login" on the new root filesystem.
 */

void	subsystem ()
{
	char	*strdup ();

	if (pwent.pw_dir[0] != '/')
		exit (1);

	if (chdir (pwent.pw_dir) || chroot (pwent.pw_dir)) {
		printf ("Can't change to \"%s\"\n", pwent.pw_dir);
		exit (1);
	}
#ifndef	SU
	(void) strcpy (utent.ut_line, "<!sublogin>");

	setutmp ();
#endif
#ifdef	SUBLOGIN
	execl ("/bin/login", "login", name, (char *) 0);
	execl ("/etc/login", "login", name, (char *) 0);
	puts ("No /bin/login or /etc/login on root");
	exit (1);
#else
	if (! pwent.pw_shell || strlen (pwent.pw_shell) == 1)
		pwent.pw_shell = "/bin/sh";	/* default shell */
	else
		pwent.pw_shell++;		/* skip over '*' */
#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'
/*
 * Configuration file for login.
 *
 *	@(#)config.h	2.1	01:23:03	6/20/89
 */

/*
 * Define DIALUP to use dialup password files
 */

#define	DIALUP

/*
 * 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	AGING

/*
 * 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	NOUSE	"NOUSE"

/*
 * 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 ...
 */

#define	FAILLOG

/*
 * 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

/*
 * 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	PWDFILE	"/etc/passwd"
#define	OPWDFILE "/etc/-passwd"
#define	NPWDFILE "/etc/npasswd"
#define	OSHADOW "/etc/-shadow"
#define	NSHADOW "/etc/nshadow"

/*
 * Define PWDLOCK to be a locking semaphore for updating the password
 * file.
 */

#define	PWDLOCK	"/etc/.pwdlock"

/*
 * 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	NEED_AL64	/* Define if library does not include a64l() */
SHAR_EOF
fi
if test -f 'pmain.c'
then
	echo shar: "will not over-write existing file 'pmain.c'"
else
cat << \SHAR_EOF > 'pmain.c'
#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#ifndef	BSD
#include <termio.h>
#include <string.h>
#include <memory.h>
#else
#include <sgtty.h>
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "config.h"
#include "lastlog.h"
#include "shadow.h"

#ifndef	PASSLENGTH
#define	PASSLENGTH	5
#endif

#ifndef	lint
static	char	_sccsid[] = "@(#)pmain.c	2.1	01:23:35	6/20/89";
#endif

char	name[BUFSIZ];
char	orig[BUFSIZ];
char	pass[BUFSIZ];
char	pass2[BUFSIZ];

struct	passwd	pwent;

#ifndef	RETRIES
#define	RETRIES	3
#endif

char	*l64a ();
char	*crypt ();
extern	int	errno;
long	a64l ();
void	entry ();
time_t	time ();

int
main (argc, argv)
int	argc;
char	**argv;
{
	void	die ();
	char	*cp;
	char	*getlogin ();
	int	amroot;
	int	lockfd = -1;
#ifdef	OBSCURE
	int	force = 0;
#endif
	int	retries;
#ifdef	AGING
	long	week;
	long	lastweek;
#endif
	long	salttime;
	struct	passwd	*pw;
	struct	passwd	*getpwuid ();
	struct	passwd	*sgetpwent ();
	FILE	*npwd;
#ifdef	SHADOWPWD
	struct	spwd	*spwd;
	struct	spwd	tspwd;
#else
	FILE	*pwd;
	char	buf[BUFSIZ];
#endif
	char	tmp[BUFSIZ];

	argc--; argv++;			/* shift ... */

	if (! isatty (0) || ! isatty (1))
		exit (1);

	die (0);			/* save tty modes */

	signal (SIGHUP, die);		/* exit if SIGHUP */
	signal (SIGINT, die);		/* exit if SIGINT */
	signal (SIGQUIT, die);		/* exit if SIGQUIT */
	signal (SIGTERM, die);		/* exit if SIGTERM */

	if (! (pw = getpwuid (getuid ())))
		goto failure;		/* can't get my name ... */
		
#ifdef	OBSCURE
	if (argc > 0 && strcmp (argv[0], "-f") == 0) {
		force = 1;
		argc--; argv++;		/* shift ... */
	}
#endif
	if (argc > 0)
		(void) strcpy (name, argv[0]);
	else if (cp = getlogin ())	/* need user name */
		(void) strcpy (name, cp);
	else				/* can't find user name! */
		goto failure;

	printf ("Changing password for %s\n", name);

	amroot = getuid () == 0;	/* currently am super user */
#ifdef	OBSCURE
	if (! amroot)
		force = 0;
#endif
	if (! amroot && strcmp (name, pw->pw_name) != 0)
		goto failure;

	entry (name, &pwent);		/* get password file entry */

	if (! pwent.pw_name)		/* no entry for user??? */
		goto failure;

	if (! amroot) {
		if (! password ("Old Password:", orig))
			exit (1);

		if (! valid (orig, &pwent)) {
			puts ("Sorry.");
			exit (1);
		}
	}
#ifdef	AGING
	if (! amroot && pwent.pw_age) {	/* check out the age */
#ifdef	SHADOWPWD
		(void) time (&week);
		week /= (24L * 60L * 60L);	/* days since epoch */
		if (spwd = getspnam (name)) {	/* use entries in shadow */
			if (spwd->sp_min > spwd->sp_max) {
				puts ("You may not change this password");
				exit (1);
			}
			if (spwd->sp_lstchg + spwd->sp_min > week) {
				printf ("Sorry, less than %d days since the last change\n", spwd->sp_min);
				exit (1);
			}
		} else {
#endif	/* SHADOWPWD */
		(void) time (&week);
		week /= (7L * 24L * 60L * 60L);	/* weeks since epoch */
		lastweek = a64l (&pwent.pw_age[2]);

		if (c64i (pwent.pw_age[0]) < c64i (pwent.pw_age[1])) {
			puts ("You may not change this password");
			exit (1);
		}
		if (c64i (pwent.pw_age[1]) + lastweek > week) {
			printf ("Sorry, less than %d weeks since the last change\n", c64i (pwent.pw_age[1]));
			exit (1);
		}
#ifdef	SHADOWPWD
		}
#endif
	}
#endif
	printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
#ifdef	OBSCURE
	puts ("Please use a combination of upper and lowercase letters and numbers");
#endif
	retries = RETRIES;
retry:
	if (! password ("New Password:", pass))
		exit (1);

#ifndef	OBSCURE
	if (! obscure ()) {
		puts ("Password not changed.");
		exit (1);
	}
#else
	if (! force && ! obscure ()) {
		if (retries-- > 0) {
			puts ("Please try again.");
			goto retry;
		} else
			goto toomany;
	}
#endif
	if (! password ("Re-enter new password:", pass2))
		exit (1);

	if (strcmp (pass, pass2) != 0) {
		puts ("They don't match; try again");

		if (retries-- > 0)
			goto retry;
		else
			goto toomany;
	}
#ifdef	AGING
	if (pwent.pw_age) {
		cp = l64a (week);

		pwent.pw_age[2] = cp[0];
		pwent.pw_age[3] = cp[1];
		pwent.pw_age[4] = '\0';
	}
#endif
	(void) time (&salttime);
	salttime = ((salttime & 07777) ^ ((salttime >> 14) & 07777)) & 07777;
	pwent.pw_passwd = tmp;
	strcpy (pwent.pw_passwd, crypt (pass, l64a (salttime)));
#ifdef	DOUBLESIZE
	if (strlen (pass) > 8) {
		strcpy (pwent.pw_passwd + 13,
			crypt (pass + 8, l64a (salttime)) + 2);
	}
#endif
	/*
	 * Now we get to race the bad guy.  I don't think he can get us.
	 *
	 * Ignore most reasonable signals.
	 *	Maybe we should ignore more?  He can't hurt us until the end.
	 *
	 * Get a lock file.
	 *
	 * Copy first part of password file to new file.
	 *	Illegal lines are copied verbatim.
	 *	File permissions are r--r--r--, owner root, group root.
	 *
	 * Output the new entry.
	 *	Only fields in struct passwd are output.
	 *
	 * Copy the rest of the file verbatim.
	 *
	 * Rename (link, unlink) password file to backup.
	 *	Kill me now and nothing changes or no one gets in.
	 *
	 * Rename (link, unlink) temporary file to password file.
	 *	Kill me now and no one gets in or lock is left.
	 *
	 * Remove locking file.
	 *
	 * That's all folks ...
	 */

	signal (SIGHUP, SIG_IGN);
	signal (SIGINT, SIG_IGN);
	signal (SIGQUIT, SIG_IGN);
	signal (SIGTERM, SIG_IGN);

	umask (0);			/* get new files modes correct */
#ifndef	NDEBUG
	if ((lockfd = open (".pwdlock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
#else
	if ((lockfd = open (PWDLOCK, O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
#endif	/* NDEBUG */
	{
		puts ("Can't get lock");
		exit (1);
	}
	umask (077);			/* close security holes to come ... */
#ifdef	SHADOWPWD
	if (access (NSHADOW, 0) == 0 && unlink (NSHADOW) == -1)
		goto failure;

	if ((npwd = fopen (NSHADOW, "w")) == (FILE *) 0)
		goto failure;

	if (chmod (NSHADOW, 0400) || chown (NSHADOW, 0, 0))
		goto failure;

	setspent ();

	while (spwd = getspent ()) {
		if (strcmp (spwd->sp_namp, name) == 0)
			break;

		if (putspent (spwd, npwd))
			goto failure;
	}
	if (spwd == (struct spwd *) 0) { /* didn't find a match */
		spwd = &tspwd;		/* use a local structure instead */
		spwd->sp_namp = pwent.pw_name;
		spwd->sp_max = 10000;	/* about as big as possible */
		spwd->sp_min = 0;	/* about as small as possible */
	}
	spwd->sp_pwdp = pwent.pw_passwd; /* fixup the password */

	(void) time (&lastweek);	/* get the current time ... */
	lastweek /= (24L*60L*60L);	/* ... turn it into days. */
	spwd->sp_lstchg = lastweek;	/* save it as date of last change */

	(void) putspent (spwd, npwd);	/* add the new entry */

	while (spwd = getspent ())	/* finish the other ones off */
		(void) putspent (spwd, npwd);

	endspent ();

	if (ferror (npwd)) {
		perror (NSHADOW);
		if (unlink (NPWDFILE) || unlink (PWDLOCK))
			fputs ("Help!\n", stderr);

		exit (1);
	}
	fflush (npwd);
	fclose (npwd);

	if (access (OSHADOW, 0) == 0) {
		if (unlink (OSHADOW)) {
			puts ("Can't remove backup file");
			goto unlock;
		}
	}
	if (link (SHADOW, OSHADOW) || unlink (SHADOW)) {
		puts ("Can't save backup file");
		goto unlock;
	}
#ifndef	BSD
	if (link (NSHADOW, SHADOW) || unlink (NSHADOW))
#else
	if (rename (NSHADOW, SHADOW))
#endif
	{
		(void) unlink (OSHADOW);
		puts ("Can't rename new file");
		goto unlock;
	}
	if (unlink (OSHADOW)) {
		puts ("Can't remove backup file");
		goto unlock;
	}
#else	/* ! SHADOWPWD */
	if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1)
		goto failure;

#ifndef	NDEBUG
	if ((npwd = fopen ("npasswd", "w")) == (FILE *) 0)
#else
	umask (077);		/* no permissions for non-roots */

	if ((npwd = fopen (NPWDFILE, "w")) == (FILE *) 0)
#endif	/* NDEBUG */
		goto failure;

#ifndef	NDEBUG
	chmod (NPWDFILE, 0444);		/* lets have some security here ... */
	chown (NPWDFILE, 0, 0);		/* ... and keep the bad guy away */
#endif	/* NDEBUG */
	if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0)
		goto failure;

	while (fgets (buf, BUFSIZ, pwd) != (char *) 0) {
		if (buf[0] == '#' || ! (pw = sgetpwent (buf))) {
			fputs (buf, npwd);
		} else if (strcmp (pw->pw_name, pwent.pw_name) != 0)
			fputs (buf, npwd);
		else
			break;
	}
	(void) fprintf (npwd, "%s:", pw->pw_name);
	if (pwent.pw_age)
		(void) fprintf (npwd, "%s,%s:", pwent.pw_passwd, pwent.pw_age);
	else
		(void) fprintf (npwd, "%s:", pwent.pw_passwd);

	(void) fprintf (npwd, "%d:%d:%s:%s:%s\n",
		pwent.pw_uid, pwent.pw_gid, pwent.pw_gecos, pwent.pw_dir,
		pwent.pw_shell ? pwent.pw_shell:"");

	while (fgets (buf, BUFSIZ, pwd) != (char *) 0)
		fputs (buf, npwd);

	if (ferror (npwd)) {
		perror (NPWDFILE);
		if (unlink (NPWDFILE) || unlink (PWDLOCK))
			fputs ("Help!\n", stderr);

		exit (1);
	}
	fflush (npwd);
	fclose (npwd);
#ifdef	NDEBUG
	chmod (NPWDFILE, 0644);
	if (unlink (OPWDFILE) == -1) {
		if (errno != ENOENT) {
			puts ("Can't unlink backup file");
			goto unlock;
		}
	}
	if (link (PWDFILE, OPWDFILE) || unlink (PWDFILE)) {
		puts ("Can't save backup file");
		goto unlock;
	}
#ifndef	BSD
	if (link (NPWDFILE, PWDFILE) || unlink (NPWDFILE))
#else
	if (rename (NPWDFILE, PWDFILE))
#endif
	{
		puts ("Can't rename new file");
		goto unlock;
	}
#endif	/* NDEBUG */
#endif	/* SHADOW */
#ifndef	NDEBUG
	(void) unlink (".pwdlock");
#else
	(void) unlink (PWDLOCK);
#endif
	exit (0);
	/*NOTREACHED*/

failure:
	puts ("Permission denied.");
unlock:
	if (lockfd >= 0)
		(void) unlink (PWDLOCK);

	(void) unlink (NPWDFILE);
	exit (1);
	/*NOTREACHED*/

toomany:
	puts ("Too many tries; try again later.");
	exit (1);
	/*NOTREACHED*/
}

/*
 * die - set or reset termio modes.
 *
 *	die() is called before processing begins.  signal() is then
 *	called with die() as the signal handler.  If signal later
 *	calls die() with a signal number, the terminal modes are
 *	then reset.
 */

void	die (killed)
int	killed;
{
#ifdef	BSD
	static	struct	sgtty	sgtty;

	if (killed)
		stty (0, &sgtty);
	else
		gtty (0, &sgtty);
#else
	struct	termio	sgtty;

	if (killed)
		ioctl (0, TCSETA, &sgtty);
	else
		ioctl (0, TCGETA, &sgtty);
#endif
	if (killed)
		exit (killed);
}
SHAR_EOF
fi
if test -f 'sulogin.c'
then
	echo shar: "will not over-write existing file 'sulogin.c'"
else
cat << \SHAR_EOF > 'sulogin.c'
#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#include <utmp.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "config.h"

#ifndef	lint
static	char	_sccsid[] = "@(#)sulogin.c	2.1	01:24:02	6/20/89";
#endif

char	name[BUFSIZ];
char	pass[BUFSIZ];
char	home[BUFSIZ];
char	prog[BUFSIZ];
char	mail[BUFSIZ];

struct	passwd	pwent;
struct	utmp	utent;

#ifdef	TZ
FILE	*tzfile;
char	tzbuf[16] = TZ;
#endif

#ifndef	MAXENV
#define	MAXENV	64
#endif

char	*newenvp[MAXENV];
int	newenvc = 0;
int	maxenv = MAXENV;
extern	char	**environ;

#ifndef	ALARM
#define	ALARM	60
#endif

#ifndef	RETRIES
#define	RETRIES	3
#endif

int	main (argc, argv, envp)
int	argc;
char	**argv;
char	**envp;
{
	char	*getenv ();
	char	*ttyname ();
	char	*cp;

	if (access (PWDFILE, 0) == -1) { /* must be a password file! */
		printf ("No password file\n");
		exit (1);
	}
#ifndef	DEBUG
	if (getppid () != 1)		/* parent must be INIT */
		exit (1);
#endif
	if (! isatty (0))		/* must be a terminal */
		exit (1);

	while (*envp)			/* add inherited environment, */
		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 */
#endif
	(void) strcpy (name, "root");	/* KLUDGE!!! */

	while (1) {		/* repeatedly get login/password pairs */
		entry (name, &pwent);	/* get entry from password file */
		if (pwent.pw_name == (char *) 0) {
			printf ("No password entry for 'root'\n");
			exit (1);
		}

	/*
	 * Here we prompt for the root password, or if no password is
	 * given we just exit.
	 */

					/* get a password for root */
		if (! password ("Type control-d for normal startup,\n(or give root password for system maintenance):", pass))
			exit (0);

		if (valid (pass, &pwent)) /* check encrypted passwords ... */
			break;		/* ... encrypted passwords matched */

		puts ("Login incorrect");
	}
	environ = newenvp;		/* make new environment active */

	puts ("Entering System Maintenance Mode");

	/*
	 * Normally there would be a utmp entry for login to mung on
	 * to get the tty name, date, etc. from.  We don't need all that
	 * stuff because we won't update the utmp or wtmp files.  BUT!,
	 * we do need the tty name so we can set the permissions and
	 * ownership.
	 */

	if (cp = ttyname (0)) {		/* found entry in /dev/ */
		if (strrchr (cp, '/') != (char *) 0)
			strcpy (utent.ut_line, strrchr (cp, '/') + 1);
		else
			strcpy (utent.ut_line, cp);
	}
	if (getenv ("IFS"))		/* don't export user IFS ... */
		addenv ("IFS= \t\n");	/* ... instead, set a safe IFS */

	setup (&pwent);			/* set UID, GID, HOME, etc ... */

	shell (pwent.pw_shell);		/* exec the shell finally. */
	/*NOTREACHED*/
}
SHAR_EOF
fi
if test -f 'dialup.h'
then
	echo shar: "will not over-write existing file 'dialup.h'"
else
cat << \SHAR_EOF > 'dialup.h'
/*
 * Structure of d_passwd file
 *
 *	The d_passwd file contains the names of login shells which require
 *	dialup passwords.  Each line contains the fully qualified path name
 *	for the shell, followed by an optional password.  Each field is
 *	separated by a ':'.
 *
 * Structure of the dialups file
 *
 *	The dialups file contains the names of ports which may be dialup
 *	lines.  Each line consists of the last component of the path
 *	name.  Any leading directory names are removed.
 *
 *	@(#)dialup.h	2.1	01:23:08	6/20/89
 */

struct	dialup {
	char	*du_shell;
	char	*du_passwd;
};

void	setduent ();
void	endduent ();
struct	dialup	*getduent ();
struct	dialup	*getdushell ();

#define	DIALPWD	"/etc/d_passwd"
#define	DIALUPS	"/etc/dialups"
SHAR_EOF
fi
if test -f 'ttytype.c'
then
	echo shar: "will not over-write existing file 'ttytype.c'"
else
cat << \SHAR_EOF > 'ttytype.c'
#include <stdio.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "config.h"

#ifdef	TTYTYPE
#ifndef	lint
static	char	_sccsid[] = "@(#)ttytype.c	2.1	01:24:04	6/20/89";
#endif

/*
 * ttytype - set ttytype from port to terminal type mapping database
 */

void	ttytype (line)
char	*line;
{
	FILE	*fp;
	char	buf[BUFSIZ];
	char	termvar[BUFSIZ];
	char	*cp;
	char	*type;
	char	*port;
	char	*getenv ();

	if (getenv ("TERM"))
		return;

	if (! (fp = fopen (TTYTYPE, "r")))
		return;

	while (fgets (buf, BUFSIZ, fp)) {
		if (buf[0] == '#')
			continue;

		if (cp = strchr (buf, '\n'))
			*cp = '\0';

		if ((type = strtok (buf, " \t"))
				&& (port = strtok ((char *) 0, " \t"))) {
			if (strcmp (line, port) == 0)
				break;
		}
	}
	if (! feof (fp) && ! ferror (fp)) {
		strcat (strcpy (termvar, "TERM="), type);
		addenv (termvar);
	}
	fclose (fp);
}
#endif
SHAR_EOF
fi
exit 0
#	End of shell archive