#! /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:
#	pmain.c
#	port.c
#	lmain.c
#	mkpasswd.c
#	sulogin.c
#	pwpack.c
#	dialup.c
#	sulog.c
#	password.c
#	env.c
#	mail.c
#	dialchk.c
# This archive created: Wed Dec 12 12:36:45 1990
# By:	John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'pmain.c'" '(11779 characters)'
if test -f 'pmain.c'
then
	echo shar: "will not over-write existing file 'pmain.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pmain.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 
X#include 
X#include 
X#include 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#include 
X#else
X#include 
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X#include "lastlog.h"
X#include "shadow.h"
X
X#ifdef SHADOW
X#   ifndef AGING
X#	define AGING
X#   endif
X#endif
X
X#ifdef	DBM
X#include 
X#endif
X
X#ifndef	PASSLENGTH
X#define	PASSLENGTH	5
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)pmain.c	2.8	07:55:00	11/8/90";
X#endif
X
Xchar	name[BUFSIZ];
Xchar	orig[BUFSIZ];
Xchar	pass[BUFSIZ];
Xchar	pass2[BUFSIZ];
X
Xstruct	passwd	pwent;
X
X#ifndef	RETRIES
X#define	RETRIES	3
X#endif
X
Xchar	*l64a ();
Xchar	*crypt ();
Xextern	int	errno;
Xlong	a64l ();
Xvoid	entry ();
Xtime_t	time ();
X
Xvoid
Xusage ()
X{
X#ifdef	OBSCURE
X	fprintf (stderr, "usage: passwd { [ -f ] user | -g [ -r ] group }\n");
X#else
X	fprintf (stderr, "usage: passwd { user | -g [ -r ] group }\n");
X#endif
X	exit (1);
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	void	die ();
X	char	*cp;
X	char	*getlogin ();
X	int	amroot;
X	int	lockfd = -1;
X#ifdef	OBSCURE
X	int	force = 0;
X#endif
X	int	retries;
X#ifdef	AGING
X	long	week;
X	long	lastweek;
X	char	newage[5];
X#endif
X	long	salttime;
X	struct	passwd	*pw;
X	struct	passwd	*getpwuid ();
X	struct	passwd	*getpwnam ();
X	struct	passwd	*sgetpwent ();
X	FILE	*npwd;
X#ifdef	SHADOWPWD
X	struct	spwd	*spwd;
X	struct	spwd	tspwd;
X#else
X	FILE	*pwd;
X	char	buf[BUFSIZ];
X#endif
X	char	tmp[BUFSIZ];
X
X	argc--; argv++;			/* shift ... */
X
X	if (! isatty (0) || ! isatty (1))
X		exit (1);
X
X	die (0);			/* save tty modes */
X
X	signal (SIGHUP, die);		/* exit if SIGHUP */
X	signal (SIGINT, die);		/* exit if SIGINT */
X	signal (SIGQUIT, die);		/* exit if SIGQUIT */
X	signal (SIGTERM, die);		/* exit if SIGTERM */
X
X	if (argc > 0 && strcmp (argv[0], "-g") == 0) {
X		argv[0] = "gpasswd";
X		execv ("/bin/gpasswd", &argv[0]);
X		perror ("/bin/gpasswd");
X		fprintf (stderr, "Unable to change group passwords\n");
X		exit (-1);
X	}
X#ifdef	OBSCURE
X	if (argc > 0 && strcmp (argv[0], "-f") == 0) {
X		force = 1;
X		argc--; argv++;		/* shift ... */
X	}
X#endif
X	if (argc > 0 && argv[0][0] == '-')
X		usage ();
X
X	if (argc > 0)
X		(void) strcpy (name, argv[0]);
X	else if (cp = getlogin ())	/* need user name */
X		(void) strcpy (name, cp);
X	else {				/* can't find user name! */
X		fprintf (stderr, "unknown user: %s\n", argv[0]);
X		exit (1);
X	}
X	printf ("Changing password for %s\n", name);
X
X	if (! (pw = getpwnam (name)))
X		goto failure;		/* can't get my name ... */
X		
X	amroot = getuid () == 0;	/* currently am super user */
X#ifdef	OBSCURE
X	if (! amroot)
X		force = 0;
X#endif
X	if (! amroot && (getuid () != pw->pw_uid ||
X			 strcmp (name, getlogin ())))
X		goto failure;
X
X	entry (name, &pwent);		/* get password file entry */
X
X	if (! pwent.pw_name)		/* no entry for user??? */
X		goto failure;
X
X	if (! amroot) {
X		if (! password ("Old Password:", orig))
X			exit (1);
X
X		if (! valid (orig, &pwent)) {
X			puts ("Sorry.");
X			exit (1);
X		}
X	}
X#ifdef	AGING
X	if (! amroot && pwent.pw_age) {	/* check out the age */
X#ifdef	SHADOWPWD
X		(void) time (&week);
X		week /= (24L * 60L * 60L);	/* days since epoch */
X		if (spwd = getspnam (name)) {	/* use entries in shadow */
X			if (spwd->sp_min > spwd->sp_max) {
X				puts ("You may not change this password");
X				exit (1);
X			}
X			if (spwd->sp_lstchg + spwd->sp_min > week) {
X				printf ("Sorry, less than %d days since the last change\n", spwd->sp_min);
X				exit (1);
X			}
X		} else {
X#endif	/* SHADOWPWD */
X		(void) time (&week);
X		week /= (7L * 24L * 60L * 60L);	/* weeks since epoch */
X		lastweek = a64l (&pwent.pw_age[2]);
X
X		if (c64i (pwent.pw_age[0]) < c64i (pwent.pw_age[1])) {
X			puts ("You may not change this password");
X			exit (1);
X		}
X		if (c64i (pwent.pw_age[1]) + lastweek > week) {
X			printf ("Sorry, less than %d weeks since the last change\n", c64i (pwent.pw_age[1]));
X			exit (1);
X		}
X#ifdef	SHADOWPWD
X		}
X#endif
X	}
X#endif
X	printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
X#ifdef	OBSCURE
X	puts ("Please use a combination of upper and lowercase letters and numbers");
X#endif
X	retries = RETRIES;
Xretry:
X	if (! password ("New Password:", pass))
X		exit (1);
X
X#ifndef	OBSCURE
X	if (! obscure ()) {
X		puts ("Password not changed.");
X		exit (1);
X	}
X#else
X	if (! force && ! obscure ()) {
X		if (retries-- > 0) {
X			puts ("Please try again.");
X			goto retry;
X		} else
X			goto toomany;
X	}
X#endif
X	if (! password ("Re-enter new password:", pass2))
X		exit (1);
X
X	if (strcmp (pass, pass2) != 0) {
X		puts ("They don't match; try again");
X
X		if (retries-- > 0)
X			goto retry;
X		else
X			goto toomany;
X	}
X#ifdef	AGING
X	if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
X		strcpy (newage, pwent.pw_age);
X		pwent.pw_age = newage;
X
X		cp = l64a (week);
X
X		if (pwent.pw_age[0] == '.' && pwent.pw_age[1] == '.')
X			pwent.pw_age[0] = 'z';
X
X		pwent.pw_age[2] = cp[0];
X		pwent.pw_age[3] = cp[1];
X		pwent.pw_age[4] = '\0';
X	}
X#endif
X	(void) time (&salttime);
X	salttime = ((salttime & 07777) ^ ((salttime >> 14) & 07777)) & 07777;
X	pwent.pw_passwd = tmp;
X	strcpy (pwent.pw_passwd, crypt (pass, l64a (salttime)));
X#ifdef	DOUBLESIZE
X	if (strlen (pass) > 8) {
X		strcpy (pwent.pw_passwd + 13,
X			crypt (pass + 8, l64a (salttime)) + 2);
X	}
X#endif
X	/*
X	 * Now we get to race the bad guy.  I don't think he can get us.
X	 *
X	 * Ignore most reasonable signals.
X	 *	Maybe we should ignore more?  He can't hurt us until the end.
X	 *
X	 * Get a lock file.
X	 *
X	 * Copy first part of password file to new file.
X	 *	Illegal lines are copied verbatim.
X	 *	File permissions are r--r--r--, owner root, group root.
X	 *
X	 * Output the new entry.
X	 *	Only fields in struct passwd are output.
X	 *
X	 * Copy the rest of the file verbatim.
X	 *
X	 * Rename (link, unlink) password file to backup.
X	 *	Kill me now and nothing changes or no one gets in.
X	 *
X	 * Rename (link, unlink) temporary file to password file.
X	 *	Kill me now and no one gets in or lock is left.
X	 *
X	 * Remove locking file.
X	 *
X	 * That's all folks ...
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#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#ifdef	SHADOWPWD
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 (spwd = getspent ()) {
X		if (strcmp (spwd->sp_namp, name) == 0)
X			break;
X
X		if (putspent (spwd, npwd))
X			goto failure;
X	}
X	if (spwd == (struct spwd *) 0) { /* didn't find a match */
X		spwd = &tspwd;		/* use a local structure instead */
X		spwd->sp_namp = pwent.pw_name;
X		spwd->sp_max = 10000;	/* about as big as possible */
X		spwd->sp_min = 0;	/* about as small as possible */
X	}
X	spwd->sp_pwdp = pwent.pw_passwd; /* fixup the password */
X
X	(void) time (&lastweek);	/* get the current time ... */
X	lastweek /= (24L*60L*60L);	/* ... turn it into days. */
X	spwd->sp_lstchg = lastweek;	/* save it as date of last change */
X
X	if (spwd->sp_min == 0 && spwd->sp_max == 0)
X		spwd->sp_max = 10000;	/* don't force another passwd */
X
X	(void) putspent (spwd, npwd);	/* add the new entry */
X
X	while (spwd = getspent ())	/* finish the other ones off */
X		(void) putspent (spwd, 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	if (unlink (OSHADOW)) {
X		puts ("Can't remove backup file");
X		goto unlock;
X	}
X#else	/* ! SHADOWPWD */
X#ifdef	DBM
X	update_dbm (&pwent);
X#endif
X	if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1)
X		goto failure;
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		goto failure;
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		goto failure;
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 ? 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#endif	/* SHADOW */
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
Xtoomany:
X	puts ("Too many tries; try again later.");
X	exit (1);
X	/*NOTREACHED*/
X}
X
X/*
X * die - set or reset termio modes.
X *
X *	die() is called before processing begins.  signal() is then
X *	called with die() as the signal handler.  If signal later
X *	calls die() with a signal number, the terminal modes are
X *	then reset.
X */
X
Xvoid	die (killed)
Xint	killed;
X{
X#ifdef	BSD
X	static	struct	sgtty	sgtty;
X
X	if (killed)
X		stty (0, &sgtty);
X	else
X		gtty (0, &sgtty);
X#else
X	static	struct	termio	sgtty;
X
X	if (killed)
X		ioctl (0, TCSETA, &sgtty);
X	else
X		ioctl (0, TCGETA, &sgtty);
X#endif
X	if (killed) {
X		putchar ('\n');
X		fflush (stdout);
X		exit (killed);
X	}
X}
SHAR_EOF
if test 11779 -ne "`wc -c < 'pmain.c'`"
then
	echo shar: "error transmitting 'pmain.c'" '(should have been 11779 characters)'
fi
fi
echo shar: "extracting 'port.c'" '(8322 characters)'
if test -f 'port.c'
then
	echo shar: "will not over-write existing file 'port.c'"
else
sed 's/^X//' << \SHAR_EOF > 'port.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 
X#include 
X#include 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "port.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)port.c	2.2	08:26:33	8/20/90";
X#endif
X
Xextern	int	errno;
X
Xstatic	FILE	*ports;
X
X/*
X * setttyent - open /etc/porttime file or rewind
X *
X *	the /etc/porttime file is rewound if already open, or
X *	opened for reading.
X */
X
Xvoid
Xsetttyent ()
X{
X	if (ports)
X		rewind (ports);
X	else 
X		ports = fopen (PORTS, "r");
X}
X
X/*
X * endttyent - close the /etc/porttime file
X *
X *	the /etc/porttime file is closed and the ports variable set
X *	to NULL to indicate that the /etc/porttime file is no longer
X *	open.
X */
X
Xvoid
Xendttyent ()
X{
X	if (ports)
X		fclose (ports);
X
X	ports = (FILE *) 0;
X}
X
X/*
X * getttyent - read a single entry from /etc/porttime
X *
X *	the next line in /etc/porttime is converted to a (struct port)
X *	and a pointer to a static (struct port) is returned to the
X *	invoker.  NULL is returned on either EOF or error.  errno is
X *	set to EINVAL on error to distinguish the two conditions.
X */
X
Xstruct port *
Xgetttyent ()
X{
X	static	struct	port	port;	/* static struct to point to         */
X	static	char	buf[BUFSIZ];	/* some space for stuff              */
X	static	char	*users[PORT_IDS]; /* some pointers to user ids       */
X	static	struct	pt_time	times[PORT_TIMES]; /* some time range things */
X	char	*cp;			/* pointer into line                 */
X	int	time;			/* scratch time of day               */
X	int	i, j;
X	int	saveerr = errno;	/* errno value on entry              */
X
X	/*
X	 * If the ports file is not open, open the file.  Do not rewind
X	 * since we want to search from the beginning each time.
X	 */
X
X	if (! ports)
X		setttyent ();
X
X	if (! ports) {
X		errno = saveerr;
X		return 0;
X	}
X
X	/*
X	 * Common point for beginning a new line -
X	 *
X	 *	- read a line, and NUL terminate
X	 *	- skip lines which begin with '#'
X	 *	- parse off the tty name
X	 *	- parse off a list of user names
X	 *	- parse off a list of days and times
X	 */
X
Xagain:
X
X	/*
X	 * Get the next line and remove the last character, which
X	 * is a '\n'.  Lines which begin with '#' are all ignored.
X	 */
X
X	if (fgets (buf, BUFSIZ, ports) == 0) {
X		errno = saveerr;
X		return 0;
X	}
X	if (buf[0] == '#')
X		goto again;
X
X	/*
X	 * Get the name of the TTY device.  It is the first colon
X	 * separated field, and is the name of the TTY with no
X	 * leading "/dev".  The entry '*' is used to specify all
X	 * TTY devices.
X	 */
X
X	buf[strlen (buf) - 1] = 0;
X
X	port.pt_name = buf;
X	if (! (cp = strchr (buf, ':')))
X		goto again;
X
X	*cp++ = 0;
X
X	/*
X	 * Get the list of user names.  It is the second colon
X	 * separated field, and is a comma separated list of user
X	 * names.  The entry '*' is used to specify all usernames.
X	 * The last entry in the list is a (char *) 0 pointer.
X	 */
X
X	if (*cp != ':') {
X		port.pt_users = users;
X		port.pt_users[0] = cp;
X
X		for (j = 1;*cp != ':';cp++) {
X			if (*cp == ',' && j < (PORT_IDS-1)) {
X				*cp++ = 0;
X				port.pt_users[j++] = cp;
X			}
X		}
X		port.pt_users[j] = 0;
X	} else
X		port.pt_users = 0;
X
X	if (*cp != ':')
X		goto again;
X
X	*cp++ = 0;
X
X	/*
X	 * Get the list of valid times.  The times field is the third
X	 * colon separated field and is a list of days of the week and
X	 * times during which this port may be used by this user.  The
X	 * valid days are 'Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', and 'Sa'.
X	 *
X	 * In addition, the value 'Al' represents all 7 days, and 'Wk'
X	 * represents the 5 weekdays.
X	 *
X	 * Times are given as HHMM-HHMM.  The ending time may be before
X	 * the starting time.  Days are presumed to wrap at 0000.
X	 */
X
X	if (*cp == '\0') {
X		port.pt_times = 0;
X		return &port;
X	}
X
X	port.pt_times = times;
X
X	/*
X	 * Get the next comma separated entry
X	 */
X
X	for (j = 0;*cp && j < (PORT_TIMES-1);j++) {
X
X		/*
X		 * Start off with no days of the week
X		 */
X
X		port.pt_times[j].t_days = 0;
X
X		/*
X		 * Check each two letter sequence to see if it is
X		 * one of the abbreviations for the days of the
X		 * week or the other two values.
X		 */
X
X		for (i = 0;cp[i] && cp[i + 1] && isalpha (cp[i]);i += 2) {
X			switch ((cp[i] << 8) | (cp[i + 1])) {
X				case ('S' << 8) | 'u':
X					port.pt_times[j].t_days |= 01;
X					break;
X				case ('M' << 8) | 'o':
X					port.pt_times[j].t_days |= 02;
X					break;
X				case ('T' << 8) | 'u':
X					port.pt_times[j].t_days |= 04;
X					break;
X				case ('W' << 8) | 'e':
X					port.pt_times[j].t_days |= 010;
X					break;
X				case ('T' << 8) | 'h':
X					port.pt_times[j].t_days |= 020;
X					break;
X				case ('F' << 8) | 'r':
X					port.pt_times[j].t_days |= 040;
X					break;
X				case ('S' << 8) | 'a':
X					port.pt_times[j].t_days |= 0100;
X					break;
X				case ('W' << 8) | 'k':
X					port.pt_times[j].t_days |= 076;
X					break;
X				case ('A' << 8) | 'l':
X					port.pt_times[j].t_days |= 0177;
X					break;
X				default:
X					errno = EINVAL;
X					return 0;
X			}
X		}
X
X		/*
X		 * The default is 'Al' if no days were seen.
X		 */
X
X		if (i == 0)
X			port.pt_times[j].t_days = 0177;
X
X		/*
X		 * The start and end times are separated from each
X		 * other by a '-'.  The times are four digit numbers
X		 * representing the times of day.
X		 */
X
X		for (time = 0;cp[i] && isdigit (cp[i]);i++)
X			time = time * 10 + cp[i] - '0';
X
X		if (cp[i] != '-' || time > 2400 || time % 100 > 59)
X			goto again;
X		port.pt_times[j].t_start = time;
X		cp = cp + i + 1;
X
X		for (time = i = 0;cp[i] && isdigit (cp[i]);i++)
X			time = time * 10 + cp[i] - '0';
X
X		if ((cp[i] != ',' && cp[i]) || time > 2400 || time % 100 > 59)
X			goto again;
X
X		port.pt_times[j].t_end = time;
X		cp = cp + i + 1;
X	}
X
X	/*
X	 * The end of the list is indicated by a pair of -1's for the
X	 * start and end times.
X	 */
X
X	port.pt_times[j].t_start = port.pt_times[j].t_end = -1;
X
X	return &port;
X}
X
X/*
X * getttyuser - get ports information for user and tty
X *
X *	getttyuser() searches the ports file for an entry with a TTY
X *	and user field both of which match the supplied TTY and
X *	user name.  The file is searched from the beginning, so the
X *	entries are treated as an ordered list.
X */
X
Xstruct port *
Xgetttyuser (tty, user)
Xchar	*tty;
Xchar	*user;
X{
X	int	i;
X	struct	port	*port;
X
X	setttyent ();
X
X	while (port = getttyent ()) {
X		if (strcmp (port->pt_name, tty) != 0 &&
X				strcmp (port->pt_name, "*") != 0)
X			continue;
X
X		if (strcmp (*port->pt_users, "*") == 0)
X			break;
X
X		for (i = 0;port->pt_users && port->pt_users[i];i++) {
X			if (strcmp (user, port->pt_users[i]) == 0)
X				break;
X		}
X		if (port->pt_users && port->pt_users[i])
X			break;
X	}
X	endttyent ();
X	return port;
X}
X
X/*
X * isttytime - tell if a given user may login at a particular time
X *
X *	isttytime searches the ports file for an entry which matches
X *	the user name and TTY given.
X */
X
Xint
Xisttytime (id, port, clock)
Xchar	*id;
Xchar	*port;
Xlong	clock;
X{
X	int	i;
X	int	time;
X	struct	port	*pp;
X	struct	tm	*tm,
X			*localtime();
X
X	/*
X	 * Try to find a matching entry for this user.  Default to
X	 * letting the user in - there are pleny of ways to have an
X	 * entry to match all users.
X	 */
X
X	if (! (pp = getttyuser (id, port)))
X		return 1;
X
X	/*
X	 * The entry is there, but has not time entries - don't
X	 * ever let them login.
X	 */
X
X	if (pp->pt_times == 0)
X		return 0;
X
X	/*
X	 * The current time is converted to HHMM format for
X	 * comparision against the time values in the TTY entry.
X	 */
X
X	tm = localtime (&clock);
X	time = tm->tm_hour * 100 + tm->tm_min;
X
X	/*
X	 * Each time entry is compared against the current
X	 * time.  For entries with the start after the end time,
X	 * the comparision is made so that the time is between
X	 * midnight and either the start or end time.
X	 */
X
X	for (i = 0;pp->pt_times[i].t_start != -1;i++) {
X		if (! (pp->pt_times[i].t_days & PORT_DAY(tm->tm_wday)))
X			continue;
X
X		if (pp->pt_times[i].t_start <= pp->pt_times[i].t_end) {
X			if (time >= pp->pt_times[i].t_start &&
X					time <= pp->pt_times[i].t_end)
X				return 1;
X		} else {
X			if (time >= pp->pt_times[i].t_start ||
X					time <= pp->pt_times[i].t_end)
X				return 1;
X		}
X	}
X
X	/*
X	 * No matching time entry was found, user shouldn't
X	 * be let in right now.
X	 */
X
X	return 0;
X}
SHAR_EOF
if test 8322 -ne "`wc -c < 'port.c'`"
then
	echo shar: "error transmitting 'port.c'" '(should have been 8322 characters)'
fi
fi
echo shar: "extracting 'lmain.c'" '(8196 characters)'
if test -f 'lmain.c'
then
	echo shar: "will not over-write existing file 'lmain.c'"
else
sed 's/^X//' << \SHAR_EOF > 'lmain.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 
X#include 
X#include 
X#include 
X#include 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#ifndef	BSD
X#include 
X#else
X#include 
X#endif
X#include "config.h"
X#include "lastlog.h"
X#include "faillog.h"
X#ifdef	SHADOWPWD
X#include "shadow.h"
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)lmain.c	2.7	10:20:08	11/9/90";
X#endif
X
X#ifndef	ERASECHAR
X#define	ERASECHAR	'\b'		/* backspace */
X#endif
X
X#ifndef	KILLCHAR
X#define	KILLCHAR	'\025'		/* control U */
X#endif
X
Xchar	name[BUFSIZ];
Xchar	pass[BUFSIZ];
Xchar	home[BUFSIZ];
Xchar	prog[BUFSIZ];
Xchar	mail[BUFSIZ];
X#ifdef	HUSHLOGIN
Xchar	hush[BUFSIZ];
Xint	hushed;
X#endif
X
Xstruct	passwd	pwent;
Xstruct	utmp	utent;
Xstruct	lastlog	lastlog;
X#ifndef	BSD
Xstruct	termio	termio;
X#endif
X
X#ifndef	MAXENV
X#define	MAXENV	64
X#endif
X
Xchar	*newenvp[MAXENV];
Xint	newenvc = 0;
Xint	maxenv = MAXENV;
Xextern	char	**environ;
X
Xchar	*getenv ();
Xvoid	checkutmp ();
Xvoid	addenv ();
Xvoid	setenv ();
Xunsigned alarm ();
Xvoid	login ();
Xvoid	entry ();
Xvoid	setutmp ();
Xvoid	subsystem ();
Xvoid	log ();
Xvoid	setup ();
Xvoid	expire ();
Xvoid	motd ();
Xvoid	mailcheck ();
Xvoid	shell ();
Xlong	a64l ();
Xint	c64i ();
X
X#ifdef	TZ
XFILE	*tzfile;
Xchar	tzbuf[32] = TZ;
X#endif
X
X#ifndef	ALARM
X#define	ALARM	60
X#endif
X
X#ifndef	RETRIES
X#define	RETRIES	3
X#endif
X
X#ifdef	FAILLOG
Xstruct	faillog	faillog;
X#endif
X#ifdef	FTMP
Xstruct	utmp	failent;
X#endif
X#ifndef	WARNAGE
X#define	WARNAGE	0
X#endif
X
Xint	main (argc, argv, envp)
Xint	argc;
Xchar	**argv;
Xchar	**envp;
X{
X	int	retries = RETRIES;
X	int	failed;
X#ifdef	CONSOLE
X	int	conflag;
X	char	console[BUFSIZ];
X	FILE	*fp;
X	struct	stat	statbuf;
X#endif
X#ifdef	SHADOWPWD
X	struct	spwd	*spwd;
X	struct	spwd	*getspnam();
X#endif
X
X	checkutmp ();			/* must be lowest level shell */
X
X	if (! isatty (0))		/* must be a terminal */
X		exit (1);
X
X#ifndef	BSD
X	(void) ioctl (0, TCGETA, &termio); /* get terminal characteristics */
X
X	/*
X	 * Add your favorite terminal modes here ...
X	 */
X
X	termio.c_lflag |= ISIG;
X
X	termio.c_cc[VERASE] = ERASECHAR;
X	termio.c_cc[VKILL] = KILLCHAR;
X	(void) ioctl (0, TCSETAF, &termio); /* set erase and kill characters */
X#endif
X#ifdef	UMASK
X	umask (UMASK);			/* override the default umask */
X#endif
X#ifdef	ULIMIT
X	ulimit (2, (long) ULIMIT);	/* override the default ulimit */
X#endif
X	while (*envp)			/* add inherited environment, */
X		addenv (*envp++);	/* some variables change later */
X
X#ifdef	TZ
X	if (tzbuf[0] == '/') {
X		if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
X			if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
X				tzbuf[strlen (tzbuf) - 1] = '\0';
X				addenv (tzbuf);
X			}
X			fclose (tzfile);
X		}
X	} else {
X		addenv (tzbuf);
X	}
X#endif
X#ifdef	HZ
X	addenv (HZ);			/* set the default $HZ, if one */
X#endif
X	if (argc >= 2) {		/* now set command line variables */
X		setenv (argc - 2, &argv[2]);
X		(void) strncpy (name, argv[1], sizeof name);
X	}
X	(void) alarm (ALARM);		/* only allow ALARM sec. for login */
X
X	while (1) {		/* repeatedly get login/password pairs */
X		if (! name[0]) {	/* need to get a login id */
X			login (name);
X			continue;
X		}
X		entry (name, &pwent);	/* get entry from password file */
X		failed = 0;		/* hasn't failed validation yet */
X
X	/*
X	 * Here we have a sticky situation.  Some accounts may have no
X	 * password entry in the password file.  So, we don't ask for a
X	 * password.  Others, have a blank password entered - you be the
X	 * judge.  The conditional compilation NOBLANK requires even
X	 * blank passwords to be prompted for.  This may well break
X	 * quite a few systems.  Use with discretion.
X	 */
X
X#ifdef	NOBLANK
X					/* get a password from user */
X		if (! password ("Password:", pass))
X			continue;
X#else
X		if ((! pwent.pw_name ||
X			(pwent.pw_passwd && strlen (pwent.pw_passwd) > 0))
X					&& ! password ("Password:", pass))
X			continue;
X#endif
X		if (! valid (pass, &pwent)) /* check encrypted passwords ... */
X			failed = 1;
X
X#ifdef	DIALUP
X		alarm (30);
X		if (! dialcheck (utent.ut_line,
X				pwent.pw_shell ? pwent.pw_shell:"/bin/sh"))
X			failed = 1;
X#endif
X#ifdef	PORTTIME
X		if (pwent.pw_name &&
X			! isttytime (utent.ut_line, pwent.pw_name,
X				time ((long *) 0)))
X			failed = 1;
X#endif
X#ifdef	CONSOLE
X		if (pwent.pw_uid == 0 && stat (CONSOLE, &statbuf) == 0) {
X			if ((statbuf.st_mode & S_IFMT) == S_IFREG) {
X				fp = fopen (CONSOLE, "r");
X				while (fp && fgets (console, BUFSIZ, fp)
X						== console) {
X					console[strlen (console) - 1] = '\0';
X					if (! strcmp (console, utent.ut_line))
X						break;
X				}
X				if (! fp || feof (fp))
X					failed = 1;
X
X				fclose (fp);
X			} else {
X				if (strcmp (CONSOLE, utent.ut_line))
X					failed = 1;
X			}
X		}
X#endif
X#ifdef	FAILLOG
X		if (! failcheck (pwent.pw_uid, &faillog, failed))
X			failed = 1;
X#endif
X		if (! failed)
X			break;
X
X		puts ("Login incorrect");
X#ifdef	FAILLOG
X		if (pwent.pw_name)	/* don't log non-existent users */
X			failure (pwent.pw_uid, utent.ut_line, &faillog);
X#endif
X#ifdef FTMP
X		failent = utent;
X
X		if (pwent.pw_name)
X			strncpy (failent.ut_name,
X				pwent.pw_name, sizeof failent.ut_name);
X		else
X#ifdef	UNKNOWNS
X			strcpy (failent.ut_name, name);
X#else
X			strcpy (failent.ut_name, "UNKNOWN");
X#endif
X		failent.ut_time = time ((time_t *) 0);
X		failent.ut_type = USER_PROCESS;
X
X		failtmp (&failent);
X#endif /* FTMP */
X		if (--retries <= 0)	/* only allow so many failures */
X			exit (1);
X
X#ifndef	BSD
X		(void) memset (name, '\0', sizeof name);
X		(void) memset (pass, '\0', sizeof pass);
X#else
X		bzero (name, sizeof name);
X		bzero (pass, sizeof pass);
X#endif
X	}
X	(void) alarm (0);		/* turn off alarm clock */
X#ifdef	NOLOGINS
X	/*
X	 * Check to see if system is turned off for non-root users.
X	 * This would be useful to prevent users from logging in
X	 * during system maintenance.
X	 */
X
X	if (pwent.pw_uid != 0 && access (NOLOGINS, 0) == 0) {
X		printf ("\r\nSystem closed for routine maintenance\n");
X		exit (0);
X	}
X#endif
X	environ = newenvp;		/* make new environment active */
X
X	if (getenv ("IFS"))		/* don't export user IFS ... */
X		addenv ("IFS= \t\n");	/* ... instead, set a safe IFS */
X
X	setutmp ();			/* make entry in utmp & wtmp files */
X	if (pwent.pw_shell && pwent.pw_shell[0] == '*') /* subsystem root */
X		subsystem ();		/* figure out what to execute */
X
X#ifdef	LASTLOG
X	log ();				/* give last login and log this one */
X#endif
X#ifdef	SHADOWPWD
X	/*
X	 * Need to get expiration information before changing UID
X	 */
X
X	spwd = getspnam (pwent.pw_name);
X#endif
X	setup (&pwent);			/* set UID, GID, HOME, etc ... */
X#ifdef	AGING
X#ifdef	SHADOWPWD
X	if (spwd)
X		expire (spwd->sp_namp, spwd->sp_lstchg,
X			spwd->sp_min, spwd->sp_max);
X	else
X#endif
X	if (pwent.pw_age && pwent.pw_age[0]) { /* check for age of password */
X		expire (pwent.pw_name, (strlen (pwent.pw_age) == 4 ?
X			a64l (pwent.pw_age + 2):0L) * 7,
X			c64i (pwent.pw_age[1]) * 7,
X			c64i (pwent.pw_age[0]) * 7);
X	}
X#endif
X#ifdef	HUSHLOGIN
X	sprintf (hush, "%s/.hushlogin", strchr (home, '=') + 1);
X	hushed = access (hush, 0) != -1;
X#endif
X#ifdef	MOTD
X	motd ();			/* print the message of the day */
X#endif
X#ifdef	FAILLOG
X	if (faillog.fail_cnt != 0)
X		failprint (pwent.pw_uid, &faillog);
X#endif
X#ifdef	LASTLOG
X	if (lastlog.ll_time != 0 && ! hushed)
X		printf ("Last login: %.19s on %s\n",
X			ctime (&lastlog.ll_time), lastlog.ll_line);
X#endif
X#ifdef	AGING
X#ifdef	SHADOWPWD
X		if (spwd)
X			agecheck (spwd->sp_lstchg,
X				spwd->sp_min, spwd->sp_max, 1);
X		else
X#endif
X		agecheck (strlen (pwent.pw_age) == 4 ?
X				a64l (pwent.pw_age + 2):0L,
X			c64i (pwent.pw_age[1]), c64i (pwent.pw_age[0]), 7);
X#endif
X#ifdef	MAILCHECK
X	mailcheck ();			/* report on the status of mail */
X#endif
X#ifdef	TTYTYPE
X	ttytype (utent.ut_line);
X#endif
X	signal (SIGINT, SIG_DFL);	/* default interrupt signal */
X	signal (SIGQUIT, SIG_DFL);	/* default quit signal */
X	signal (SIGTERM, SIG_DFL);	/* default terminate signal */
X	signal (SIGALRM, SIG_DFL);	/* default alarm signal */
X
X	shell (pwent.pw_shell);		/* exec the shell finally. */
X	/*NOTREACHED*/
X}
SHAR_EOF
if test 8196 -ne "`wc -c < 'lmain.c'`"
then
	echo shar: "error transmitting 'lmain.c'" '(should have been 8196 characters)'
fi
fi
echo shar: "extracting 'mkpasswd.c'" '(6587 characters)'
if test -f 'mkpasswd.c'
then
	echo shar: "will not over-write existing file 'mkpasswd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mkpasswd.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 "config.h"
X#include 
X#include 
X#include 
X#ifdef	BSD
X#include 
X#else
X#include 
X#endif
X
X#if !defined(DBM)
X#error "What you are trying to do?  You have to have a DBM of some kind ..."
X#endif
X
X#ifdef	DBM
X#include 
X#endif
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)mkpasswd.c	2.3	08:56:25	11/5/90";
Xstatic	char	copyright[] = "Copyright 1990, John F. Haugh II";
X#endif
X
Xchar	*CANT_OPEN =	"%s: cannot open file %s\n";
Xchar	*CANT_OVERWRITE = "%s: cannot overwrite file %s\n";
Xchar	*CANT_CREATE =	"%s: cannot create %s\n";
Xchar	*DBM_OPEN_ERR =	"%s: cannot open DBM files for %s\n";
Xchar	*PARSE_ERR =	"%s: error parsing line\n\"%s\"\n";
Xchar	*LINE_TOO_LONG = "%s: the beginning with \"%.16s ...\" is too long\n";
Xchar	*ADD_NAME =	"adding key for name \"%s\"\n";
Xchar	*ADD_NAME_ERR =	"%s: error adding entry for \"%s\"\n";
Xchar	*ADD_UID =	"adding key for uid %d, name \"%s\"\n";
Xchar	*ADD_UID_ERR =	"%s: error adding entry for uid %d, name \"%s\"\n";
Xchar	*INFO =		"added %d entries, longest was %d\n";
Xchar	*USAGE =	"Usage: %s [ -v ] [ -f ] file\n";
X
Xchar	*Progname;
Xint	vflg = 0;
Xint	fflg = 0;
X
Xvoid	usage();
X
Xextern	char	*malloc();
Xextern	struct	passwd	*sgetpwent();
X
X/*
X * mkpasswd - create DBM files for /etc/passwd-like input file
X *
X * mkpasswd takes an an argument the name of a file in /etc/passwd format
X * and creates a DBM file keyed by user ID and name.  The output files have
X * the same name as the input file, with .dir and .pag appended.
X */
X
Xint
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	extern	int	optind;
X	extern	char	*optarg;
X	FILE	*pwfp;			/* File pointer for password file     */
X	char	*pwfile;		/* Name of password file              */
X	char	*pwdir;			/* Name of .dir file                  */
X	char	*pwpag;			/* Name of .pag file                  */
X	char	*cp;			/* Temporary character pointer        */
X	int	flag;			/* Flag for command line option       */
X	int	fd;			/* File descriptor of open DBM file   */
X	int	cnt = 0;		/* Number of entries in database      */
X	int	longest = 0;		/* Longest entry in database          */
X	int	errors = 0;		/* Count of errors processing file    */
X	char	buf[BUFSIZ];		/* Input line from password file      */
X	char	dbmbuf[BUFSIZ];		/* Place to build DBM record          */
X	struct	passwd	*passwd;	/* Pointer to password file entry     */
X	datum	key;			/* Info for DBM key data              */
X	datum	content;		/* Info for DBM record data           */
X
X	/*
X	 * Figure out what my name is.  I will use this later ...
X	 */
X
X	if (Progname = strrchr (argv[0], '/'))
X		Progname++;
X	else
X		Progname = argv[0];
X
X	/*
X	 * Figure out what the flags might be ...
X	 */
X
X	while ((flag = getopt (argc, argv, "fv")) != EOF) {
X		switch (flag) {
X			case 'v':
X				vflg++;
X				break;
X			case 'f':
X				fflg++;
X				break;
X			default:
X				usage ();
X		}
X	}
X
X	/*
X	 * The last and only remaining argument must be the file name
X	 */
X
X	if (argc - 1 != optind)
X		usage ();
X
X	pwfile = argv[optind];
X
X	if (! (pwfp = fopen (pwfile, "r"))) {
X		fprintf (stderr, CANT_OPEN, Progname, pwfile);
X		exit (1);
X	}
X
X	/*
X	 * Make the filenames for the two DBM files.
X	 */
X
X	pwdir = malloc (strlen (pwfile) + 5);	/* space for .dir file */
X	strcat (strcpy (pwdir, pwfile), ".dir");
X
X	pwpag = malloc (strlen (pwfile) + 5);	/* space for .pag file */
X	strcat (strcpy (pwpag, pwfile), ".pag");
X
X	/*
X	 * Remove existing files if requested.
X	 */
X
X	if (fflg) {
X		(void) unlink (pwdir);
X		(void) unlink (pwpag);
X	}
X
X	/*
X	 * Create the two DBM files - it is an error for these files
X	 * to have existed already.
X	 */
X
X	if (access (pwdir, 0) == 0) {
X		fprintf (stderr, CANT_OVERWRITE, Progname, pwdir);
X		exit (1);
X	}
X	if (access (pwpag, 0) == 0) {
X		fprintf (stderr, CANT_OVERWRITE, Progname, pwpag);
X		exit (1);
X	}
X
X	umask (0);
X	if ((fd = open (pwdir, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
X		fprintf (stderr, CANT_CREATE, Progname, pwdir);
X		exit (1);
X	} else
X		close (fd);
X
X	if ((fd = open (pwpag, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
X		fprintf (stderr, CANT_CREATE, Progname, pwpag);
X		unlink (pwdir);
X		exit (1);
X	} else
X		close (fd);
X
X	/*
X	 * Now the DBM database gets initialized
X	 */
X
X#ifdef	DBM
X	if (dbminit (pwfile) == -1) {
X		fprintf (stderr, DBM_OPEN_ERR, Progname, pwfile);
X		exit (1);
X	}
X#endif
X
X	/*
X	 * Read every line in the password file and convert it into a
X	 * data structure to be put in the DBM database files.
X	 */
X
X	while (fgets (buf, BUFSIZ, pwfp) != NULL) {
X
X		/*
X		 * Get the next line and strip off the trailing newline
X		 * character.  Very long lines are fatal errors.
X		 */
X
X		buf[BUFSIZ-1] = '\0';
X		if (! (cp = strchr (buf, '\n'))) {
X			fprintf (stderr, LINE_TOO_LONG, Progname, buf);
X			exit (1);
X		}
X		*cp = '\0';
X
X		/*
X		 * Parse the password file line into a (struct passwd).
X		 * Erroneous lines cause error messages, but that's
X		 * all.  YP lines are ignored completely.
X		 */
X
X		if (buf[0] == '-' || buf[0] == '+')
X			continue;
X
X		if (! (passwd = sgetpwent (buf))) {
X			fprintf (stderr, PARSE_ERR, Progname, buf);
X			errors++;
X			continue;
X		}
X
X		/*
X		 * Pack the (struct passwd) into a buffer and build
X		 * the content structure for the DBM.
X		 */
X
X		content.dsize = pw_pack (passwd, dbmbuf);
X		content.dptr = dbmbuf;
X
X		/*
X		 * Store the record using the name as the key
X		 */
X
X		key.dsize = strlen (passwd->pw_name);
X		key.dptr = passwd->pw_name;
X		if (vflg)
X			printf (ADD_NAME, passwd->pw_name);
X#ifdef	DBM
X		if (store (key, content)) {
X			fprintf (stderr, ADD_NAME_ERR, Progname,
X					passwd->pw_name);
X			errors++;
X		}
X#endif
X
X		/*
X		 * Store the record using the UID as the key
X		 */
X
X		key.dsize = sizeof passwd->pw_uid;
X		key.dptr = (char *) &passwd->pw_uid;
X		if (vflg)
X			printf (ADD_UID, passwd->pw_uid, passwd->pw_name);
X#ifdef	DBM
X		if (store (key, content)) {
X			fprintf (stderr, ADD_UID_ERR, Progname,
X					passwd->pw_uid, passwd->pw_name);
X			errors++;
X		}
X#endif
X		/*
X		 * Update the longest record and record count
X		 */
X
X		if (content.dsize > longest)
X			longest = content.dsize;
X		cnt++;
X	}
X
X	/*
X	 * Tell the user how things went ...
X	 */
X
X	if (vflg)
X		printf (INFO, cnt, longest);
X
X	exit (errors);
X	/*NOTREACHED*/
X}
X
X/*
X * usage - print error message and exit
X */
X
Xvoid
Xusage ()
X{
X	fprintf (stderr, USAGE, Progname);
X	exit (1);
X	/*NOTREACHED*/
X}
SHAR_EOF
if test 6587 -ne "`wc -c < 'mkpasswd.c'`"
then
	echo shar: "error transmitting 'mkpasswd.c'" '(should have been 6587 characters)'
fi
fi
echo shar: "extracting 'sulogin.c'" '(3193 characters)'
if test -f 'sulogin.c'
then
	echo shar: "will not over-write existing file 'sulogin.c'"
else
sed 's/^X//' << \SHAR_EOF > 'sulogin.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 
X#include 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)sulogin.c	2.3.1.1	08:28:36	12/5/90";
X#endif
X
Xchar	name[BUFSIZ];
Xchar	pass[BUFSIZ];
Xchar	home[BUFSIZ];
Xchar	prog[BUFSIZ];
Xchar	mail[BUFSIZ];
X
Xstruct	passwd	pwent;
Xstruct	utmp	utent;
X
X#ifdef	TZ
XFILE	*tzfile;
Xchar	tzbuf[16] = TZ;
X#endif
X
X#ifndef	MAXENV
X#define	MAXENV	64
X#endif
X
Xchar	*newenvp[MAXENV];
Xint	newenvc = 0;
Xint	maxenv = MAXENV;
Xextern	char	**environ;
X
X#ifndef	ALARM
X#define	ALARM	60
X#endif
X
X#ifndef	RETRIES
X#define	RETRIES	3
X#endif
X
Xint	main (argc, argv, envp)
Xint	argc;
Xchar	**argv;
Xchar	**envp;
X{
X	char	*getenv ();
X	char	*ttyname ();
X	char	*cp;
X
X	if (access (PWDFILE, 0) == -1) { /* must be a password file! */
X		printf ("No password file\n");
X		exit (1);
X	}
X#ifdef	NDEBUG
X	if (getppid () != 1)		/* parent must be INIT */
X		exit (1);
X#endif
X	if (! isatty (0))		/* must be a terminal */
X		exit (1);
X
X	while (*envp)			/* add inherited environment, */
X		addenv (*envp++);	/* some variables change later */
X
X#ifdef	TZ
X	if (tzbuf[0] == '/') {
X		if ((tzfile = fopen (tzbuf, "r")) != (FILE *) 0) {
X			if (fgets (tzbuf, sizeof tzbuf, tzfile)) {
X				tzbuf[strlen (tzbuf) - 1] = '\0';
X				addenv (tzbuf);
X			}
X			fclose (tzfile);
X		}
X	} else {
X		addenv (tzbuf);
X	}
X#endif
X#ifdef	HZ
X	addenv (HZ);			/* set the default $HZ, if one */
X#endif
X	(void) strcpy (name, "root");	/* KLUDGE!!! */
X
X	alarm (ALARM);
X	while (1) {		/* repeatedly get login/password pairs */
X		entry (name, &pwent);	/* get entry from password file */
X		if (pwent.pw_name == (char *) 0) {
X			printf ("No password entry for 'root'\n");
X			exit (1);
X		}
X
X	/*
X	 * Here we prompt for the root password, or if no password is
X	 * given we just exit.
X	 */
X
X					/* get a password for root */
X		if (! password ("Type control-d for normal startup,\n\
X(or give root password for system maintenance):", pass))
X			exit (0);
X
X		if (valid (pass, &pwent)) /* check encrypted passwords ... */
X			break;		/* ... encrypted passwords matched */
X
X		puts ("Login incorrect");
X	}
X	alarm (0);
X	environ = newenvp;		/* make new environment active */
X
X	puts ("Entering System Maintenance Mode");
X
X	/*
X	 * Normally there would be a utmp entry for login to mung on
X	 * to get the tty name, date, etc. from.  We don't need all that
X	 * stuff because we won't update the utmp or wtmp files.  BUT!,
X	 * we do need the tty name so we can set the permissions and
X	 * ownership.
X	 */
X
X	if (cp = ttyname (0)) {		/* found entry in /dev/ */
X		if (strrchr (cp, '/') != (char *) 0)
X			strcpy (utent.ut_line, strrchr (cp, '/') + 1);
X		else
X			strcpy (utent.ut_line, cp);
X	}
X	if (getenv ("IFS"))		/* don't export user IFS ... */
X		addenv ("IFS= \t\n");	/* ... instead, set a safe IFS */
X
X	setup (&pwent);			/* set UID, GID, HOME, etc ... */
X
X	shell (pwent.pw_shell);		/* exec the shell finally. */
X	/*NOTREACHED*/
X}
SHAR_EOF
if test 3193 -ne "`wc -c < 'sulogin.c'`"
then
	echo shar: "error transmitting 'sulogin.c'" '(should have been 3193 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 
X#include 
X#ifdef	BSD
X#include 
X#else
X#include 
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 'dialup.c'" '(2171 characters)'
if test -f 'dialup.c'
then
	echo shar: "will not over-write existing file 'dialup.c'"
else
sed 's/^X//' << \SHAR_EOF > 'dialup.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 
X#ifndef	BSD
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "dialup.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)dialup.c	2.2	19:23:38	7/29/90";
X#endif
X
Xstatic	FILE	*dialpwd;
X
Xvoid	setduent ()
X{
X	if (dialpwd)
X		rewind (dialpwd);
X	else
X		dialpwd = fopen (DIALPWD, "r");
X}
X
Xvoid	endduent ()
X{
X	if (dialpwd)
X		fclose (dialpwd);
X
X	dialpwd = (FILE *) 0;
X}
X
Xstruct	dialup	*getduent ()
X{
X	static	struct	dialup	dialup;	/* static structure to point to */
X	static	char	shell[64];	/* some space for a login shell */
X	static	char	passwd[16];	/* some space for dialup password */
X	char	buf[BUFSIZ];
X	char	*cp;
X
X	if (! dialpwd)
X		setduent ();
X
X	if (! dialpwd || feof (dialpwd))
X		return ((struct dialup *) 0);
X
X	while (fgets (buf, BUFSIZ, dialpwd) == buf && buf[0] == '#')
X		;
X
X	if (feof (dialpwd))
X		return ((struct dialup *) 0);
X
X	cp = strchr (buf, ':');
X	if (cp - buf > sizeof shell)	/* something is fishy ... */
X		return ((struct dialup *) 0);
X
X	(void) strncpy (shell, buf, cp - buf);
X	shell[cp - buf] = '\0';
X
X	if (strlen (cp + 1) > sizeof passwd) /* something is REALLY fishy */
X		return ((struct dialup *) 0);
X
X	(void) strcpy (passwd, cp + 1);
X	passwd[strlen (passwd) - 1] = '\0';
X	if (cp = strchr (passwd, ':'))
X		*cp = '\0';
X
X	dialup.du_shell = shell;
X	dialup.du_passwd = passwd;
X
X	return (&dialup);
X}
X
Xstruct	dialup	*getdushell (shell)
Xchar	*shell;
X{
X	struct	dialup	*dialup;
X
X	while (dialup = getduent ()) {
X		if (strcmp (shell, dialup->du_shell) == 0)
X			return (dialup);
X
X		if (strcmp (dialup->du_shell, "*") == 0)
X			return (dialup);
X	}
X	return ((struct dialup *) 0);
X}
X
Xint	isadialup (tty)
Xchar	*tty;
X{
X	FILE	*fp;
X	char	buf[BUFSIZ];
X	int	dialup = 0;
X
X	if (! (fp = fopen (DIALUPS, "r")))
X		return (0);
X
X	while (fgets (buf, BUFSIZ, fp) == buf) {
X		if (buf[0] == '#')
X			continue;
X
X		buf[strlen (buf) - 1] = '\0';
X
X		if (strcmp (buf, tty) == 0) {
X			dialup = 1;
X			break;
X		}
X	}
X	fclose (fp);
X
X	return (dialup);
X}
SHAR_EOF
if test 2171 -ne "`wc -c < 'dialup.c'`"
then
	echo shar: "error transmitting 'dialup.c'" '(should have been 2171 characters)'
fi
fi
echo shar: "extracting 'sulog.c'" '(1172 characters)'
if test -f 'sulog.c'
then
	echo shar: "will not over-write existing file 'sulog.c'"
else
sed 's/^X//' << \SHAR_EOF > 'sulog.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 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)sulog.c	2.2.1.1	09:09:55	11/26/90";
X#endif
X
Xextern	char	name[];
Xextern	char	oldname[];
X
Xtime_t	time ();
X
Xvoid	sulog (success)
Xint	success;
X{
X#ifdef	SULOG
X	char	*tty;
X	char	*cp;
X	char	*ttyname ();
X	time_t	clock;
X	struct	tm	*tm;
X	struct	tm	*localtime ();
X	FILE	*fp;
X
X	if ((fp = fopen (SULOG, "a+")) == (FILE *) 0)
X		return;			/* can't open or create logfile */
X
X	(void) time (&clock);
X	tm = localtime (&clock);
X
X	if (isatty (0) && (cp = ttyname (0))) {
X		if (tty = strrchr (cp, '/'))
X			tty++;
X		else
X			tty = cp;
X	} else
X		tty = "???";
X
X	(void) fprintf (fp, "SU %.02d/%0.2d %.02d:%.02d %c %.6s %s-%s\n",
X		tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min,
X		success ? '+':'-', tty, oldname, name);
X
X	fflush (fp);
X	fclose (fp);
X#endif
X}
SHAR_EOF
if test 1172 -ne "`wc -c < 'sulog.c'`"
then
	echo shar: "error transmitting 'sulog.c'" '(should have been 1172 characters)'
fi
fi
echo shar: "extracting 'password.c'" '(1939 characters)'
if test -f 'password.c'
then
	echo shar: "will not over-write existing file 'password.c'"
else
sed 's/^X//' << \SHAR_EOF > 'password.c'
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
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#ifndef	BSD
X#include 
X#else
X#include 
X#endif
X
X#include 
X
X/*
X * password - prompt for password and return entry
X *
X *	Need to fake up getpass().  Returns TRUE if a password
X *	was successfully input, and FALSE otherwise, including
X *	EOF on input or ioctl() failure.  pass is not modified
X *	on failure.  The input length limit may be set by
X *	changing the value of PASSLIMIT.
X */
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)password.c	2.2	09:38:59	6/22/90";
X#endif
X
X#define	PASSLIMIT	20
X
Xint	password (prompt, pass)
Xchar	*prompt;
Xchar	*pass;
X{
X	char	buf[BUFSIZ];
X	char	*cp;
X	int	eof;
X	int	ttyopened = 0;
X#ifndef	BSD
X	struct	termio	termio;
X	struct	termio	save;
X#else
X	struct	sgttyb	termio ;
X	struct	sgttyb	save ;
X#endif
X	FILE	*fp;
X
X	if ((fp = fopen ("/dev/tty", "r")) == (FILE *) 0)
X		fp = stdin;
X	else
X		ttyopened = 1;
X
X#ifndef	BSD
X	if (ioctl (fileno (fp), TCGETA, &termio))
X		return (0);
X#else
X	if ( gtty( fileno(fp), &termio ) )
X		return (0);
X#endif
X
X	save = termio;
X#ifndef	BSD
X	termio.c_lflag &= ~(ECHO|ECHOE|ECHOK);
X	ioctl (fileno (fp), TCSETAF, &termio);
X#else
X	termio.sg_flags &= ~ECHO ;
X	stty( fileno( fp ), termio ) ;
X#endif
X
X	fputs (prompt, stdout);
X	eof = fgets (buf, BUFSIZ, fp) == (char *) 0 || feof (fp) || ferror (fp);
X	putchar ('\n');
X
X#ifndef	BSD
X	ioctl (fileno (fp), TCSETAF, &save);
X#else
X	stty( fileno( fp ), save ) ;
X#endif
X
X	if (! eof) {
X		buf[PASSLIMIT] = '\0';
X		if ((cp = strchr (buf, '\n')) || (cp = strchr (buf, '\r')))
X			*cp = '\0'; 
X
X		(void) strcpy (pass, buf);
X	}
X	if (ttyopened)
X		fclose (fp);
X
X	return (! eof);
X}
SHAR_EOF
if test 1939 -ne "`wc -c < 'password.c'`"
then
	echo shar: "error transmitting 'password.c'" '(should have been 1939 characters)'
fi
fi
echo shar: "extracting 'env.c'" '(1788 characters)'
if test -f 'env.c'
then
	echo shar: "will not over-write existing file 'env.c'"
else
sed 's/^X//' << \SHAR_EOF > 'env.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 
X#ifndef	BSD
X#include 
X#else
X#define	strchr	index
X#define	strrchr	rindex
X#include 
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)env.c	2.2	19:23:43	7/29/90";
X#endif
X
Xextern	char	**environ;
Xextern	char	*newenvp[];
Xextern	int	newenvc;
Xextern	int	maxenv;
X
Xchar	*strdup ();
Xvoid	free ();
X
Xstatic	char	*forbid[] = {
X	"HOME",
X	"IFS",
X	"PATH",
X	"SHELL",
X	(char *) 0
X};
X
Xvoid	addenv (entry)
Xchar	*entry;
X{
X	char	*cp;
X	int	i;
X	int	len;
X
X	if (cp = strchr (entry, '='))
X		len = cp - entry;
X	else
X		return;
X
X	for (i = 0;i < newenvc;i++)
X		if (strncmp (entry, newenvp[i], len) == 0 &&
X			(newenvp[i][len] == '=' || newenvp[i][len] == '\0'))
X			break;
X
X	if (i == maxenv) {
X		puts ("Environment overflow");
X		return;
X	}
X	if (i == newenvc) {
X		newenvp[newenvc++] = strdup (entry);
X	} else {
X		free (newenvp[i]);
X		newenvp[i] = strdup (entry);
X	}
X}
X
Xvoid	setenv (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	int	i;
X	int	n;
X	int	noname = 1;
X	char	variable[BUFSIZ];
X	char	*cp;
X
X	for (i = 0;i < argc;i++) {
X		if ((n = strlen (argv[i])) >= BUFSIZ)
X			continue;	/* ignore long entries */
X
X		if (! (cp = strchr (argv[i], '='))) {
X			(void) strcpy (variable, argv[i]);
X		} else {
X			(void) strncpy (variable, argv[i], cp - argv[i]);
X			variable[cp - argv[i]] = '\0';
X		}
X		for (n = 0;forbid[n] != (char *) 0;n++)
X			if (strcmp (variable, forbid[n]) == 0)
X				break;
X
X		if (forbid[n] != (char *) 0) {
X			printf ("You may not change $%s\n", forbid[n]);
X			continue;
X		}
X		if (cp) {
X			addenv (argv[i]);
X		} else {
X			sprintf (variable, "L%d=%s", noname++, argv[i]);
X			addenv (variable);
X		}
X	}
X}
SHAR_EOF
if test 1788 -ne "`wc -c < 'env.c'`"
then
	echo shar: "error transmitting 'env.c'" '(should have been 1788 characters)'
fi
fi
echo shar: "extracting 'mail.c'" '(912 characters)'
if test -f 'mail.c'
then
	echo shar: "will not over-write existing file 'mail.c'"
else
sed 's/^X//' << \SHAR_EOF > 'mail.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 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)mail.c	2.2	19:23:56	7/29/90";
X#endif
X
Xextern	char	mail[];
X
X#ifdef	HUSHLOGIN
Xextern	int	hushed;
X#endif
X
X#ifdef	MAILCHECK
Xvoid	mailcheck ()
X{
X	struct	stat	statbuf;
X	char	*mailbox;
X
X#ifdef	HUSHLOGIN
X	if (hushed)
X		return;
X#endif
X	if (mailbox = strchr (mail, '='))
X		mailbox++;
X	else
X		return;
X
X	if (stat (mailbox, &statbuf) == -1 || statbuf.st_size == 0)
X		puts ("No mail.");
X	else if (statbuf.st_atime > statbuf.st_mtime)
X		puts ("You have mail.");
X	else
X		puts ("You have new mail.");
X}
X#endif
SHAR_EOF
if test 912 -ne "`wc -c < 'mail.c'`"
then
	echo shar: "error transmitting 'mail.c'" '(should have been 912 characters)'
fi
fi
echo shar: "extracting 'dialchk.c'" '(1008 characters)'
if test -f 'dialchk.c'
then
	echo shar: "will not over-write existing file 'dialchk.c'"
else
sed 's/^X//' << \SHAR_EOF > 'dialchk.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 
X#include "config.h"
X#include "dialup.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)dialchk.c	2.2	19:23:36	7/29/90";
X#endif
X
X/*
X * Check for dialup password
X *
X *	dialcheck tests to see if tty is listed as being a dialup
X *	line.  If so, a dialup password may be required if the shell
X *	is listed as one which requires a second password.
X */
X
X#ifdef	DIALUP
Xint	dialcheck (tty, shell)
Xchar	*tty;
Xchar	*shell;
X{
X	char	*crypt ();
X	char	*getpass ();
X	struct	dialup	*dialup;
X	char	*pass;
X	char	*cp;
X
X	if (! isadialup (tty))
X		return (1);
X
X	if (! (dialup = getdushell (shell)))
X		return (1);
X
X	endduent ();
X
X	if (dialup->du_passwd[0] == '\0')
X		return (1);
X
X	if (! (pass = getpass ("Dialup Password:")))
X		return (0);
X
X	cp = crypt (pass, dialup->du_passwd);
X	return (strcmp (cp, dialup->du_passwd) == 0);
X}
X#endif
SHAR_EOF
if test 1008 -ne "`wc -c < 'dialchk.c'`"
then
	echo shar: "error transmitting 'dialchk.c'" '(should have been 1008 characters)'
fi
fi
exit 0
#	End of shell archive