Shadow login release 2 (part 2 of 3)

John F. Haugh II jfh at rpp386.Dallas.TX.US
Tue Jun 20 16:50:33 AEST 1989


X-Archive-Name: shadow2/part2

Part 2 of second USENET release
--
#! /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:
#	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
# This archive created: Tue Jun 20 01:24:59 1989
# By:	John F. Haugh II (River Parishes Programming, Plano TX)
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'lastlog.h'
then
	echo shar: "will not over-write existing file 'lastlog.h'"
else
cat << \SHAR_EOF > 'lastlog.h'
/*
 * lastlog.h - structure of lastlog file
 *
 *	This file defines a lastlog file structure which should be sufficient
 *	to hold the information required by login.  It should only be used if
 *	there is no real lastlog.h file.
 */

struct	lastlog	{
	time_t	ll_time;
	char	ll_line[8];
};
SHAR_EOF
fi
if test -f 'login.c'
then
	echo shar: "will not over-write existing file 'login.c'"
else
cat << \SHAR_EOF > 'login.c'
#include <stdio.h>
#include <ctype.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif

void	setenv ();

void	login (name)
char	*name;
{
	char	buf[BUFSIZ];
	char	*envp[32];
	int	envc;
	char	*cp;
	int	i;

#ifndef	BSD
	(void) memset (buf, '\0', sizeof buf);
#else
	bzero (buf, sizeof buf);
#endif
	fputs ("login: ", stdout);

	if (fgets (buf, BUFSIZ, stdin) != buf)
		exit (1);

	buf[strlen (buf) - 1] = '\0';	/* remove \n [ must be there ] */

	for (cp = buf;*cp == ' ' || *cp == '\t';cp++)
		;

	for (i = 0;i < BUFSIZ - 1 && isgraph (*cp);name[i++] = *cp++)
		;

	if (*cp)
		cp++;

	name[i] = '\0';

	if (*cp != '\0') {		/* process new variables */
		for (envc = 0;envc < 32;envc++) {
			envp[envc] = strtok (envc == 0 ? cp:(char *) 0, " \t,");

			if (envp[envc] == (char *) 0)
				break;
		}
		setenv (envc, envp);
	}
}
SHAR_EOF
fi
if test -f 'motd.c'
then
	echo shar: "will not over-write existing file 'motd.c'"
else
cat << \SHAR_EOF > 'motd.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"

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

extern	char	home[];
#ifdef	HUSHLOGIN
extern	int	hushed;
#endif

#ifdef	MOTD
void	motd ()
{
	FILE	*fp;
	register int	c;

#ifdef	HUSHLOGIN
	if (hushed)
		return;
#endif
	if ((fp = fopen ("/etc/motd", "r")) == (FILE *) 0)
		return;

	while ((c = getc (fp)) != EOF)
		putchar (c);

	fclose (fp);
	fflush (stdout);
}
#endif
SHAR_EOF
fi
if test -f 'password.c'
then
	echo shar: "will not over-write existing file 'password.c'"
else
cat << \SHAR_EOF > 'password.c'
#include <stdio.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#ifndef	BSD
#include <termio.h>
#else
#include <sgtty.h>
#endif

#include <fcntl.h>

/*
 * password - prompt for password and return entry
 *
 *	Need to fake up getpass().  Returns TRUE if a password
 *	was successfully input, and FALSE otherwise, including
 *	EOF on input or ioctl() failure.  pass is not modified
 *	on failure.  The input length limit may be set by
 *	changing the value of PASSLIMIT.
 */

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

#define	PASSLIMIT	20

int	password (prompt, pass)
char	*prompt;
char	*pass;
{
	char	buf[BUFSIZ];
	char	*cp;
	int	eof;
	int	ttyopened = 0;
#ifndef	BSD
	struct	termio	termio;
	struct	termio	save;
#else
	struct	sgttyb	termio ;
	struct	sgttyb	save ;
#endif
	FILE	*fp;

	if ((fp = fopen ("/dev/tty", "r")) == (FILE *) 0)
		fp = stdin;
	else
		ttyopened = 1;

#ifndef	BSD
	if (ioctl (fileno (fp), TCGETA, &termio))
		return (0);
#else
	if ( gtty( fileno(fp), &termio ) )
		return (0);
#endif

	save = termio;
#ifndef	BSD
	termio.c_lflag &= ~(ECHO|ECHOE|ECHOK);
	ioctl (fileno (fp), TCSETAF, &termio);
#else
	termio.sg_flags &= ~ECHO ;
	stty( fileno( fp ), termio ) ;
#endif

	fputs (prompt, stdout);
	eof = fgets (buf, BUFSIZ, fp) == (char *) 0 || feof (fp) || ferror (fp);
	putchar ('\n');

#ifndef	BSD
	ioctl (fileno (fp), TCSETAF, &save);
#else
	stty( fileno( fp ), save ) ;
#endif

	if (! eof) {
		buf[PASSLIMIT] = '\0';
		if ((cp = strchr (buf, '\n')) || (cp = strchr (buf, '\r')))
			*cp = '\0'; 

		(void) strcpy (pass, buf);
	}
	if (ttyopened)
		fclose (fp);

	return (! eof);
}
SHAR_EOF
fi
if test -f 'shell.c'
then
	echo shar: "will not over-write existing file 'shell.c'"
else
cat << \SHAR_EOF > 'shell.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"

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

extern	char	*newenvp[];

void	shell (file)
char	*file;
{
	char	arg0[BUFSIZ];
	char	*path;
	extern	int	errno;

	if (file == (char *) 0)
		exit (1);

	if (path = strrchr (file, '/'))
		path++;
	else
		path = file;

	(void) strcpy (arg0 + 1, path);
	arg0[0] = '-';
#ifndef	NDEBUG
	printf ("Executing shell %s\n", file);
#endif
	execle (file, arg0, (char *) 0, newenvp);
	printf ("Can't execute %s\n", file);
	exit (errno);
}
SHAR_EOF
fi
if test -f 'utmp.c'
then
	echo shar: "will not over-write existing file 'utmp.c'"
else
cat << \SHAR_EOF > 'utmp.c'
#include <sys/types.h>
#include <utmp.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include <stdio.h>
#include "config.h"

extern	struct	utmp	utent;
extern	char	name[];

struct	utmp	*getutent ();
void	setutent ();
void	endutent ();
void	pututline ();
time_t	time ();

void	checkutmp ()
{
	struct	utmp	*ut;
#ifndef	NDEBUG
	int	pid = getppid ();
#else
	int	pid = getpid ();
#endif
	setutent ();

	while (ut = getutent ())
		if (ut->ut_pid == pid)
			break;

	if (ut)
		utent = *ut;

	endutent ();

	if (ut && utent.ut_pid == pid)
		return;

	puts ("No utmp entry.  You must exec \"login\" from the lowest level \"sh\"");
	exit (1);
}

void	setutmp ()
{
	FILE	*wtmp;
	char	tty[sizeof utent.ut_line + 1];
	char	*line;

	setutent ();

	(void) strncpy (utent.ut_user, name, sizeof utent.ut_user);

	utent.ut_type = USER_PROCESS;

	if (line = strrchr (utent.ut_line, '/')) {
		(void) strcpy (tty, line + 1);
#ifndef	BSD
		(void) memset (utent.ut_line, '\0', sizeof utent.ut_line);
#else
		bzero (utent.ut_line, sizeof utent.ut_line);
#endif
		(void) strcpy (utent.ut_line, tty);
	}
	(void) time (&utent.ut_time);

	pututline (&utent);
	endutent ();

	if ((wtmp = fopen (WTMP_FILE, "a+"))) {
		fwrite (&utent, sizeof utent, 1, wtmp);
		fclose (wtmp);
	}
}
SHAR_EOF
fi
if test -f 'age.c'
then
	echo shar: "will not over-write existing file 'age.c'"
else
cat << \SHAR_EOF > 'age.c'
#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#include "config.h"

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

#ifndef	PASSWD
extern	char	*newenvp[];
#endif

time_t	time ();

int	c64i (c)
char	c;
{
	if (c == '.')
		return (0);

	if (c == '/')
		return (1);

	if (c >= '0' && c <= '9')
		return (c - '0' + 2);

	if (c >= 'A' && c <= 'Z')
		return (c - 'A' + 12);

	if (c >= 'a' && c <= 'z')
		return (c - 'a' + 38);
	else
		return (-1);
}

#ifdef	AGING
#ifdef	PASSWD
#ifdef	NEED_AL64
char	*l64a (l)
long	l;
{
	static	char	buf[8];
	int	i = 0;

	if (i < 0L)
		return ((char *) 0);

	do {
		buf[i++] = i64c ((int) (l % 64));
		buf[i] = '\0';
	} while (l /= 64L, l > 0 && i < 6);

	return (buf);
}
#endif
#endif
int	i64c (i)
int	i;
{
	if (i < 0)
		return ('.');
	else if (i > 63)
		return ('z');

	if (i == 0)
		return ('.');

	if (i == 1)
		return ('/');

	if (i >= 2 && i <= 11)
		return ('0' - 2 + i);

	if (i >= 12 && i <= 37)
		return ('A' - 12 + i);

	if (i >= 38 && i <= 63)
		return ('a' - 38 + i);

	return ('\0');
}

#ifdef	NEED_AL64
long	a64l (s)
char	*s;
{
	int	i;
	long	value;
	long	shift = 0;

	for (i = 0, value = 0L;i < 6 && *s;s++) {
		value += (c64i (*s) << shift);
		shift += 6;
	}
	return (value);
}
#endif
#ifndef	PASSWD
void	expire (age)
char	*age;
{
	long	clock;
	long	week;
	extern	char	name[];
	extern	int	errno;

	(void) time (&clock);
	clock /= (7L * 24L * 60L * 60L);

	if (strlen (age) < 4)
		week = 0L;
	else
		week = a64l (age + 2);

	if (clock >= week + c64i (age[0])) {
		printf ("Your password has expired.");

		if (c64i (age[0]) < c64i (age[1])) {
			puts ("  Contact the system administrator.\n");
			exit (1);
		}
		puts ("  Choose a new one.\n");

		execl ("/bin/passwd", "-passwd", name, (char *) 0);
		puts ("Can't execute /bin/passwd");
		exit (errno);
	}
}
#endif
#endif
SHAR_EOF
fi
if test -f 'env.c'
then
	echo shar: "will not over-write existing file 'env.c'"
else
cat << \SHAR_EOF > 'env.c'
#include <stdio.h>
#ifndef	BSD
#include <string.h>
#else
#define	strchr	index
#define	strrchr	rindex
#include <strings.h>
#endif

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

extern	char	**environ;
extern	char	*newenvp[];
extern	int	newenvc;
extern	int	maxenv;

char	*strdup ();
void	free ();

static	char	*forbid[] = {
	"HOME",
	"IFS",
	"PATH",
	"SHELL",
	(char *) 0
};

void	addenv (entry)
char	*entry;
{
	char	*cp;
	int	i;
	int	len;

	if (cp = strchr (entry, '='))
		len = cp - entry;
	else
		return;

	for (i = 0;i < newenvc;i++)
		if (strncmp (entry, newenvp[i], len) == 0 &&
			(newenvp[i][len] == '=' || newenvp[i][len] == '\0'))
			break;

	if (i == maxenv) {
		puts ("Environment overflow");
		return;
	}
	if (i == newenvc) {
		newenvp[newenvc++] = strdup (entry);
	} else {
		free (newenvp[i]);
		newenvp[i] = strdup (entry);
	}
}

void	setenv (argc, argv)
int	argc;
char	**argv;
{
	int	i;
	int	n;
	int	noname = 1;
	char	variable[BUFSIZ];
	char	*cp;

	for (i = 0;i < argc;i++) {
		if ((n = strlen (argv[i])) >= BUFSIZ)
			continue;	/* ignore long entries */

		if (! (cp = strchr (argv[i], '='))) {
			(void) strcpy (variable, argv[i]);
		} else {
			(void) strncpy (variable, argv[i], cp - argv[i]);
			variable[cp - argv[i]] = '\0';
		}
		for (n = 0;forbid[n] != (char *) 0;n++)
			if (strcmp (variable, forbid[n]) == 0)
				break;

		if (forbid[n] != (char *) 0) {
			printf ("You may not change $%s\n", forbid[n]);
			continue;
		}
		if (cp) {
			addenv (argv[i]);
		} else {
			sprintf (variable, "L%d=%s", noname++, argv[i]);
			addenv (variable);
		}
	}
}
SHAR_EOF
fi
if test -f 'pwent.c'
then
	echo shar: "will not over-write existing file 'pwent.c'"
else
cat << \SHAR_EOF > 'pwent.c'
#include <stdio.h>
#include <pwd.h>
#include <string.h>
#include "config.h"

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

#define	SBUFSIZ	64
#define	NFIELDS	7

static	char	pwdbuf[BUFSIZ];
static	char	*pwdfields[NFIELDS];

struct	passwd	*sgetpwent (buf)
char	*buf;
{
	int	i;
	char	*cp;
	static	struct	passwd	pwent;

	strncpy (pwdbuf, buf, BUFSIZ);
	pwdbuf[BUFSIZ-1] = '\0';

	cp = pwdbuf;
	for (i = 0;i < NFIELDS && cp;i++) {
		pwdfields[i] = cp;
		if (cp = strchr (cp, ':'))
			*cp++ = 0;
	}
	if (i < (NFIELDS-1) || *pwdfields[2] == '\0' || *pwdfields[3] == '\0')
		return ((struct passwd *) 0);

	for (;i < NFIELDS;i++)
		pwdfields[i] = 0;

	pwent.pw_name = pwdfields[0];
	pwent.pw_passwd = pwdfields[1];
	pwent.pw_uid = atoi (pwdfields[2]);
	pwent.pw_gid = atoi (pwdfields[3]);

	if (cp = strchr (pwent.pw_passwd, ',')) {
		pwent.pw_age = cp + 1;
		*cp = '\0';
	}
	pwent.pw_gecos = pwdfields[4];
	pwent.pw_dir = pwdfields[5];
	pwent.pw_shell = pwdfields[6];

	return (&pwent);
}
#ifdef FGETPWENT
struct	passwd	*fgetpwent (fp)
FILE	*fp;
{
	char	buf[BUFSIZ];

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

		buf[strlen (buf) - 1] = '\0';
		return (sgetpwent (buf));
	}
	return ((struct passwd *) 0);
}
#endif
SHAR_EOF
fi
if test -f 'shadow.c'
then
	echo shar: "will not over-write existing file 'shadow.c'"
else
cat << \SHAR_EOF > 'shadow.c'
#include "shadow.h"
#include <stdio.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif

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

static	FILE	*shadow;

void	setspent ()
{
	if (shadow)
		rewind (shadow);
	else
		shadow = fopen (SHADOW, "r");
}

void	endspent ()
{
	if (shadow)
		(void) fclose (shadow);

	shadow = (FILE *) 0;
}

struct	spwd	*fgetspent (fp)
FILE	*fp;
{
	static	struct	spwd	spwd;
	static	char	name[32];
	static	char	pass[32];
	char	buf[BUFSIZ];
	char	*cp;
	int	atoi ();
	long	atol ();

	if (! fp)
		return (0);

	if (fgets (buf, BUFSIZ, fp) == (char *) 0)
		return (0);

	buf[strlen (buf) - 1] = '\0';

	if ((cp = strtok (buf, ":")) && *cp)
		(void) strcpy (name, cp);
	else
		return (0);

	if ((cp = strtok ((char *) 0, ":")) && *cp)
		(void) strcpy (pass, cp);
	else
		return (0);

	if ((cp = strtok ((char *) 0, ":")) && *cp)
		spwd.sp_lstchg = atol (cp);
	else
		return (0);

	if ((cp = strtok ((char *) 0, ":")) && *cp)
		spwd.sp_min = atoi (cp);
	else
		return (0);

	if ((cp = strtok ((char *) 0, ":")) && *cp)
		spwd.sp_max = atoi (cp);
	else
		return (0);

	spwd.sp_namp = name;
	spwd.sp_pwdp = pass;

	return (&spwd);
}

struct	spwd	*getspent ()
{
	if (! shadow)
		setspent ();

	return (fgetspent (shadow));
}

struct	spwd	*getspnam (name)
char	*name;
{
	struct	spwd	*spwd;

	setspent ();

	while ((spwd = getspent ()) != (struct spwd *) 0) {
		if (strcmp (name, spwd->sp_namp) == 0)
			return (spwd);
	}
	return (0);
}

int	putspent (spwd, fp)
struct	spwd	*spwd;
FILE	*fp;
{
	if (! fp)
		return (0);

	return (fprintf (fp, "%s:%s:%ld:%ld:%ld\n",
			spwd->sp_namp, spwd->sp_pwdp,
			spwd->sp_lstchg, spwd->sp_min, spwd->sp_max) != EOF);
}
SHAR_EOF
fi
if test -f 'valid.c'
then
	echo shar: "will not over-write existing file 'valid.c'"
else
cat << \SHAR_EOF > 'valid.c'
#include <stdio.h>
#include <pwd.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[] = "@(#)valid.c	2.1	01:24:08	6/20/89";
#endif

/*
 * valid - compare encrypted passwords
 *
 *	Valid() compares the DES encrypted password from the password file
 *	against the password which the user has entered after it has been
 *	encrypted using the same salt as the original.
 */

int	valid (password, entry)
char	*password;
struct	passwd	*entry;
{
	char	*encrypt;
	char	*salt;
	char	*crypt ();
#ifdef	DOUBLESIZE
	int	firsthalf;
	int	longpass;
#endif

	/*
	 * Start with blank or empty password entries.  Always encrypt
	 * a password if no such user exists.  Only if the ID exists and
	 * the password is really empty do you return quickly.  This
	 * routine is meant to waste CPU time.
	 */

	if (entry->pw_name &&
			(entry->pw_passwd == (char *) 0 ||
			 strlen (entry->pw_passwd) == 0)) {
		if (strlen (password) == 0)
			return (1);	/* user entered nothing */
		else
			return (0);	/* user entered something! */
	}

#ifdef	DOUBLESIZE
	longpass = entry->pw_passwd && strlen (entry->pw_passwd) > 13;
#endif

	/*
	 *
	/*
	 * If there is no entry then we need a salt to use.
	 */

	if (entry->pw_passwd == (char *) 0 || entry->pw_passwd[0] == '\0')
		salt = "xx";
	else
		salt = entry->pw_passwd;

	/*
	 * Now, perform the encryption using the salt from before on
	 * the users input.  Since we always encrypt the string, it
	 * should be very difficult to determine if the user exists by
	 * looking at execution time.
	 */

	encrypt = crypt (password, salt);
#ifdef	DOUBLESIZE
	firsthalf = entry->pw_passwd
		&& strncmp (encrypt + 2, entry->pw_passwd + 2, 11) == 0;

	if (strlen (password) > 8)
		encrypt = crypt (password + 8, salt);
	else {
		(void) crypt (password, salt);	/* waste time ... */
		encrypt = "";
	}
#endif
	/*
	 * One last time we must deal with there being no password file
	 * entry for the user.  We use the pw_passwd == NULL idiom to
	 * cause non-existent users to not be validated.  Even still,
	 * we are safe because if the string were == "", any encrypted
	 * string is not going to match - the output of crypt() begins
	 * with the salt, which is "xx", not "".
	 */

#ifdef	NOUSE
	if (entry->pw_shell && strcmp ("NO_USE", entry->pw_shell) == 0)
		return (0);
#endif
#ifndef	DOUBLESIZE
	if (entry->pw_passwd && strcmp (encrypt, entry->pw_passwd) == 0)
		return (1);
	else
		return (0);
#else
	if (! longpass)
		return (firsthalf);

	if (entry->pw_passwd && firsthalf
			&& strncmp (encrypt + 2, entry->pw_passwd + 13) == 0)
		return (1);
	else
		return (0);
#endif
}
SHAR_EOF
fi
if test -f 'lmain.c'
then
	echo shar: "will not over-write existing file 'lmain.c'"
else
cat << \SHAR_EOF > 'lmain.c'
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <pwd.h>
#include <utmp.h>
#include <time.h>
#include <signal.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#ifndef	BSD
#include <termio.h>
#else
#include <sgtty.h>
#endif
#include "config.h"
#include "lastlog.h"
#include "faillog.h"

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

#ifndef	ERASECHAR
#define	ERASECHAR	'\b'		/* backspace */
#endif

#ifndef	KILLCHAR
#define	KILLCHAR	'\025'		/* control U */
#endif

char	name[BUFSIZ];
char	pass[BUFSIZ];
char	home[BUFSIZ];
char	prog[BUFSIZ];
char	mail[BUFSIZ];
#ifdef	HUSHLOGIN
char	hush[BUFSIZ];
int	hushed;
#endif

struct	passwd	pwent;
struct	utmp	utent;
struct	lastlog	lastlog;
#ifndef	BSD
struct	termio	termio;
#endif

#ifndef	MAXENV
#define	MAXENV	64
#endif

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

char	*getenv ();
void	checkutmp ();
void	addenv ();
void	setenv ();
unsigned alarm ();
void	login ();
void	entry ();
void	setutmp ();
void	subsystem ();
void	log ();
void	setup ();
void	expire ();
void	motd ();
void	mailcheck ();
void	shell ();

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

#ifndef	ALARM
#define	ALARM	60
#endif

#ifndef	RETRIES
#define	RETRIES	3
#endif

#ifdef	FAILLOG
struct	faillog	faillog;
#endif

int	main (argc, argv, envp)
int	argc;
char	**argv;
char	**envp;
{
	int	retries = RETRIES;
	int	failed;
#ifdef	CONSOLE
	int	conflag;
	char	console[BUFSIZ];
	FILE	*fp;
	struct	stat	statbuf;
#endif

	checkutmp ();			/* must be lowest level shell */

	if (! isatty (0))		/* must be a terminal */
		exit (1);

#ifndef	BSD
	(void) ioctl (0, TCGETA, &termio); /* get terminal characteristics */

	/*
	 * Add your favorite terminal modes here ...
	 */

	termio.c_lflag |= ISIG;

	termio.c_cc[VERASE] = ERASECHAR;
	termio.c_cc[VKILL] = KILLCHAR;
	(void) ioctl (0, TCSETAF, &termio); /* set erase and kill characters */
#endif
#ifdef	UMASK
	umask (UMASK);			/* override the default umask */
#endif
#ifdef	ULIMIT
	ulimit (2, (long) ULIMIT);	/* override the default ulimit */
#endif
	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
	if (argc >= 2) {		/* now set command line variables */
		setenv (argc - 2, &argv[2]);
		(void) strncpy (name, argv[1], sizeof name);
	}
	(void) alarm (ALARM);		/* only allow ALARM sec. for login */

	while (1) {		/* repeatedly get login/password pairs */
		if (! name[0]) {	/* need to get a login id */
			login (name);
			continue;
		}
		entry (name, &pwent);	/* get entry from password file */
		failed = 0;		/* hasn't failed validation yet */

	/*
	 * Here we have a sticky situation.  Some accounts may have no
	 * password entry in the password file.  So, we don't ask for a
	 * password.  Others, have a blank password entered - you be the
	 * judge.  The conditional compilation NOBLANK requires even
	 * blank passwords to be prompted for.  This may well break
	 * quite a few systems.  Use with discretion.
	 */

#ifdef	NOBLANK
					/* get a password from user */
		if (! password ("Password:", pass))
			continue;
#else
		if ((! pwent.pw_name || pwent.pw_passwd)
					&& ! password ("Password:", pass))
			continue;
#endif
		if (! valid (pass, &pwent)) /* check encrypted passwords ... */
			failed = 1;

#ifdef	DIALUP
		alarm (30);
		if (! dialcheck (utent.ut_line,
				pwent.pw_shell ? pwent.pw_shell:"/bin/sh"))
			failed = 1;
#endif
#ifdef	CONSOLE
		if (pwent.pw_uid == 0 && stat (CONSOLE, &statbuf) == 0) {
			if ((statbuf.st_mode & S_IFMT) == S_IFREG) {
				fp = fopen (CONSOLE, "r");
				while (fp && fgets (console, BUFSIZ, fp)
						== console) {
					console[strlen (console) - 1] = '\0';
					if (! strcmp (console, utent.ut_line))
						break;
				}
				if (! fp || feof (fp))
					failed = 1;

				fclose (fp);
			} else {
				if (strcmp (CONSOLE, utent.ut_line))
					failed = 1;
			}
		}
#endif
#ifdef	FAILLOG
		if (! failcheck (pwent.pw_uid, &faillog, failed))
			failed = 1;
#endif
		if (! failed)
			break;

		puts ("Login incorrect");
#ifdef	FAILLOG
		if (pwent.pw_name)	/* don't log non-existent users */
			failure (pwent.pw_uid, utent.ut_line, &faillog);
#endif
		if (--retries <= 0)	/* only allow so many failures */
			exit (1);

#ifndef	BSD
		(void) memset (name, '\0', sizeof name);
		(void) memset (pass, '\0', sizeof pass);
#else
		bzero (name, sizeof name);
		bzero (pass, sizeof pass);
#endif
	}
	(void) alarm (0);		/* turn off alarm clock */
#ifdef	NOLOGINS
	/*
	 * Check to see if system is turned off for non-root users.
	 * This would be useful to prevent users from logging in
	 * during system maintenance.
	 */

	if (pwent.pw_uid != 0 && access (NOLOGINS, 0) == 0) {
		printf ("\r\nSystem closed for routine maintenance\n");
		exit (0);
	}
#endif
	environ = newenvp;		/* make new environment active */

	if (getenv ("IFS"))		/* don't export user IFS ... */
		addenv ("IFS= \t\n");	/* ... instead, set a safe IFS */

	setutmp ();			/* make entry in utmp & wtmp files */
	if (pwent.pw_shell && pwent.pw_shell[0] == '*') /* subsystem root */
		subsystem ();		/* figure out what to execute */

#ifdef	LASTLOG
	log ();				/* give last login and log this one */
#endif
	setup (&pwent);			/* set UID, GID, HOME, etc ... */
#ifdef	AGING
	if (pwent.pw_age)		/* check for age of password ... */
		expire (pwent.pw_age);	/* ... ask for new one if expired */
#endif
#ifdef	HUSHLOGIN
	sprintf (hush, "%s/.hushlogin", strchr (home, '=') + 1);
	hushed = access (hush, 0) != -1;
#endif
#ifdef	MOTD
	motd ();			/* print the message of the day */
#endif
#ifdef	FAILLOG
	if (faillog.fail_cnt != 0)
		failprint (pwent.pw_uid, &faillog);
#endif
#ifdef	LASTLOG
	if (lastlog.ll_time != 0 && ! hushed)
		printf ("Last login: %.19s on %s\n",
			ctime (&lastlog.ll_time), lastlog.ll_line);
#endif
#ifdef	MAILCHECK
	mailcheck ();			/* report on the status of mail */
#endif
#ifdef	TTYTYPE
	ttytype (utent.ut_line);
#endif
	signal (SIGINT, SIG_DFL);	/* default interrupt signal */
	signal (SIGQUIT, SIG_DFL);	/* default quit signal */
	signal (SIGTERM, SIG_DFL);	/* default terminate signal */
	signal (SIGALRM, SIG_DFL);	/* default alarm signal */

	shell (pwent.pw_shell);		/* exec the shell finally. */
	/*NOTREACHED*/
}
SHAR_EOF
fi
if test -f 'smain.c'
then
	echo shar: "will not over-write existing file 'smain.c'"
else
cat << \SHAR_EOF > 'smain.c'
#include <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#include <termio.h>
#else
#include <strings.h>
#include <sgtty.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include <signal.h>
#include "config.h"
#include "lastlog.h"

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

#ifndef	MAXENV
#define	MAXENV	64
#endif

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

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

#ifdef	HUSHLOGIN
char	hush[BUFSIZ];
int	hushed;
#endif

char	name[BUFSIZ];
char	pass[BUFSIZ];
char	home[BUFSIZ];
char	prog[BUFSIZ];
char	mail[BUFSIZ];
char	oldname[BUFSIZ];
char	*newenvp[MAXENV];
int	newenvc = 0;
int	maxenv = MAXENV;
struct	passwd	pwent;

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

void	addenv ();
void	entry ();
void	sulog ();
void	subsystem ();
void	setup ();
void	motd ();
void	mailcheck ();
void	shell ();

extern	char	**environ;

int	main (argc, argv, envp)
int	argc;
char	**argv;
char	**envp;
{
	void	die ();
	char	*getenv ();
	char	*cp;
	int	doshell;
	int	fakelogin = 0;
	int	amroot;
	struct	passwd	*pw;
	struct	passwd	*getpwuid ();

	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
	argc--; argv++;			/* shift out command name */

	if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') {
		fakelogin = 1;
		argc--; argv++;		/* shift ... */
	}
	if (argc > 0 && argv[0][0] != '-') {
		(void) strcpy (name, argv[0]);	/* use this login id */
		argc--; argv++;		/* shift ... */
	}
	doshell = argc == 0;		/* any arguments remaining? */

	if (pw = getpwuid (getuid ()))	/* need old user name */
		(void) strcpy (oldname, pw->pw_name);
	else				/* user ID MUST exist */
		goto failure;

	amroot = getuid () == 0;	/* currently am super user */

	if (! name[0]) 			/* use default user ID */
		(void) strcpy (name, "root");

	entry (name, &pwent);		/* get password file entry */
	if (pwent.pw_shell == (char *) 0)
		pwent.pw_shell = "/bin/sh";

	if (pwent.pw_name == (char *) 0) { /* unknown user */
		(void) fprintf (stderr, "Unknown id: %s\n", name);
		exit (1);
	}

	/*
	 * Here we have a sticky situation.  Some accounts may have no
	 * password entry in the password file.  So, we don't ask for a
	 * password.  Others, have a blank password entered - you be the
	 * judge.  The conditional compilation NOBLANK requires even
	 * blank passwords to be prompted for.  This may well break
	 * quite a few systems.  Use with discretion.
	 */

	die (0);

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

#ifdef	NOBLANK
	if (! amroot && ! password ("Password:", pass))
		goto failure;
#else
	if (! amroot && (pwent.pw_name == (char *) 0 || pwent.pw_passwd)
			&& ! password ("Password:", pass))
		goto failure;
#endif
					/* check encrypted passwords ... */
	if (! amroot && ! valid (pass, &pwent)) {
failure:	sulog (0);		/* log failed attempt */
		puts ("Sorry.");
		exit (1);
	}
	signal (SIGHUP, SIG_DFL);
	signal (SIGINT, SIG_DFL);
	signal (SIGQUIT, SIG_DFL);
	signal (SIGTERM, SIG_DFL);

#ifdef	SULOG
	sulog (1);			/* save SU information */
#endif
	if (pwent.pw_uid == 0)
		addenv (SUPATH);
	else
		addenv (PATH);

	environ = newenvp;		/* make new environment active */

	if (getenv ("IFS"))		/* don't export user IFS ... */
		addenv ("IFS= \t\n");	/* ... instead, set a safe IFS */

	if (doshell && pwent.pw_shell[0] == '*') /* subsystem root required */
		subsystem ();		/* figure out what to execute */

	if (fakelogin)
		setup (&pwent);		/* set UID, GID, HOME, etc ... */
	else {
		if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid))  {
			perror ("Can't set ID");
			exit (1);
		}
	}
	if (! doshell) {		/* execute arguments as command */
		if (cp = getenv ("SHELL"))
			pwent.pw_shell = cp;
		argv[-1] = pwent.pw_shell;
		(void) execv (pwent.pw_shell, &argv[-1]);
		(void) fprintf (stderr, "No shell\n");
		exit (1);
	}
	if (fakelogin) {
#ifdef	HUSHLOGIN
		sprintf (hush, "%s/.hushlogin", strchr (home, '=') + 1);
		hushed = access (hush, 0) != -1;
#endif
#ifdef	MOTD
		motd ();		/* print the message of the day */
#endif
#ifdef	MAILCHECK
		mailcheck ();		/* report on the status of mail */
#endif
		shell (pwent.pw_shell);	/* exec the shell finally. */
	} else {
		if (cp = strrchr (pwent.pw_shell, '/'))
			cp++;
		else
			cp = pwent.pw_shell;

		execl (pwent.pw_shell, cp, (char *) 0);
		perror (pwent.pw_shell);
		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 'pwconv.c'
then
	echo shar: "will not over-write existing file 'pwconv.c'"
else
cat << \SHAR_EOF > 'pwconv.c'
/*
 * pwconv - convert and update shadow password files
 *
 *	Pwconv copies the old password file information to a new shadow
 *	password file, merging entries from an optional existing shadow
 *	file.
 *
 *	The new password file is left in npasswd, the new shadow file is
 *	left in nshadow.  Existing shadow entries are copied as is.
 *	New entries are created with passwords which expire in MAXDAYS days,
 *	with a last changed date of today, unless password aging
 *	information was already present.  Likewise, the minimum number of
 *	days before which the password may be changed is controlled by
 *	MINDAYS.  Entries with blank passwordsare not copied to the shadow
 *	file at all.
 */

#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <pwd.h>
#include "config.h"
#include "shadow.h"

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

char	buf[BUFSIZ];

long	time ();
long	a64l ();

int	main ()
{
	long	today;
	struct	passwd	*pw;
	struct	passwd	*sgetpwent ();
	FILE	*pwd;
	FILE	*npwd;
	FILE	*shadow;
	struct	spwd	*spwd;
	struct	spwd	tspwd;
	int	fd;

	if (! (pwd = fopen (PWDFILE, "r"))) {
		perror (PWDFILE);
		return (1);
	}
	unlink ("npasswd");
	if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
			! (npwd = fdopen (fd, "w"))) {
		perror ("npasswd");
		return (1);
	}
	unlink  ("nshadow");
	if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
			! (shadow = fdopen (fd, "w"))) {
		perror ("nshadow");
		return (1);
	}

	(void) time (&today);
	today /= (24L * 60L * 60L);

	while (fgets (buf, BUFSIZ, pwd) == buf) {
		buf[strlen (buf) - 1] = '\0'; /* remove '\n' character */

		if (buf[0] == '#') {	/* comment line */
			(void) fprintf (npwd, "%s\n", buf);
			continue;
		}
		if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */
			(void) fprintf (npwd, "%s\n", buf);
			continue;
		}
		if (pw->pw_passwd == (char *) 0) { /* no password, skip */
			(void) fprintf (npwd, "%s\n", buf);
			continue;
		}
		setspent ();		/* rewind old shadow file */

		if (spwd = getspnam (pw->pw_name)) {
			if (! putspent (spwd, shadow)) { /* copy old entry */
				perror ("nshadow");
				return (1);
			}
		} else {		/* need a new entry. */
			tspwd.sp_namp = pw->pw_name;
			tspwd.sp_pwdp = pw->pw_passwd;
			pw->pw_passwd = "x";

			if (pw->pw_age) { /* copy old password age stuff */
				tspwd.sp_min = c64i (pw->pw_age[1]);
				tspwd.sp_max = c64i (pw->pw_age[0]);
				if (strlen (pw->pw_age) == 4)
					tspwd.sp_lstchg = a64l (&pw->pw_age[2]);
				else
					tspwd.sp_lstchg = 0L;

				/*
				 * Convert weeks to days
				 */

				tspwd.sp_min *= 7;
				tspwd.sp_max *= 7;
				tspwd.sp_lstchg *= 7;
			} else {	/* fake up new password age stuff */
				tspwd.sp_max = MAXDAYS;
				tspwd.sp_min = MINDAYS;
				tspwd.sp_lstchg = today;
			}
			if (! putspent (&tspwd, shadow)) { /* output entry */
				perror ("nshadow");
				return (1);
			}
		}
		(void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:",
				pw->pw_name, pw->pw_passwd ? pw->pw_passwd:"",
				pw->pw_uid, pw->pw_gid,
				pw->pw_gecos, pw->pw_dir);

		if (fprintf (npwd, "%s\n",
				pw->pw_shell ? pw->pw_shell:"") == EOF) {
			perror ("npasswd");
			return (1);
		}
	}
	endspent ();

	if (ferror (npwd) || ferror (shadow)) {
		perror ("pwconv");
		(void) unlink ("npasswd");
		(void) unlink ("nshadow");
	}
	(void) fclose (pwd);
	(void) fclose (npwd);
	(void) fclose (shadow);

	return (0);
}
SHAR_EOF
fi
if test -f 'dialup.c'
then
	echo shar: "will not over-write existing file 'dialup.c'"
else
cat << \SHAR_EOF > 'dialup.c'
#include <stdio.h>
#ifndef	BSD
#include <string.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "dialup.h"

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

static	FILE	*dialpwd;

void	setduent ()
{
	if (dialpwd)
		rewind (dialpwd);
	else
		dialpwd = fopen (DIALPWD, "r");
}

void	endduent ()
{
	if (dialpwd)
		fclose (dialpwd);

	dialpwd = (FILE *) 0;
}

struct	dialup	*getduent ()
{
	static	struct	dialup	dialup;	/* static structure to point to */
	static	char	shell[64];	/* some space for a login shell */
	static	char	passwd[16];	/* some space for dialup password */
	char	buf[BUFSIZ];
	char	*cp;

	if (! dialpwd)
		setduent ();

	if (! dialpwd || feof (dialpwd))
		return ((struct dialup *) 0);

	while (fgets (buf, BUFSIZ, dialpwd) == buf && buf[0] == '#')
		;

	if (feof (dialpwd))
		return ((struct dialup *) 0);

	cp = strchr (buf, ':');
	if (cp - buf > sizeof shell)	/* something is fishy ... */
		return ((struct dialup *) 0);

	(void) strncpy (shell, buf, cp - buf);
	shell[cp - buf] = '\0';

	if (strlen (cp + 1) > sizeof passwd) /* something is REALLY fishy */
		return ((struct dialup *) 0);

	(void) strcpy (passwd, cp + 1);
	passwd[strlen (passwd) - 1] = '\0';
	if (cp = strchr (passwd, ':'))
		*cp = '\0';

	dialup.du_shell = shell;
	dialup.du_passwd = passwd;

	return (&dialup);
}

struct	dialup	*getdushell (shell)
char	*shell;
{
	struct	dialup	*dialup;

	while (dialup = getduent ()) {
		if (strcmp (shell, dialup->du_shell) == 0)
			return (dialup);

		if (strcmp (dialup->du_shell, "*") == 0)
			return (dialup);
	}
	return ((struct dialup *) 0);
}

int	isadialup (tty)
char	*tty;
{
	FILE	*fp;
	char	buf[BUFSIZ];
	int	dialup = 0;

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

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

		buf[strlen (buf) - 1] = '\0';

		if (strcmp (buf, tty) == 0) {
			dialup = 1;
			break;
		}
	}
	fclose (fp);

	return (dialup);
}
SHAR_EOF
fi
if test -f 'dialchk.c'
then
	echo shar: "will not over-write existing file 'dialchk.c'"
else
cat << \SHAR_EOF > 'dialchk.c'
#include <stdio.h>
#include "config.h"
#include "dialup.h"

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

/*
 * Check for dialup password
 *
 *	dialcheck tests to see if tty is listed as being a dialup
 *	line.  If so, a dialup password may be required if the shell
 *	is listed as one which requires a second password.
 */

#ifdef	DIALUP
int	dialcheck (tty, shell)
char	*tty;
char	*shell;
{
	char	*crypt ();
	char	*getpass ();
	struct	dialup	*dialup;
	char	*pass;
	char	*cp;

	if (! isadialup (tty))
		return (1);

	if (! (dialup = getdushell (shell)))
		return (1);

	endduent ();

	if (dialup->du_passwd[0] == '\0')
		return (1);

	if (! (pass = getpass ("Dialup Password:")))
		return (0);

	cp = crypt (pass, dialup->du_passwd);
	return (strcmp (cp, dialup->du_passwd) == 0);
}
#endif
SHAR_EOF
fi
if test -f 'pwunconv.c'
then
	echo shar: "will not over-write existing file 'pwunconv.c'"
else
cat << \SHAR_EOF > 'pwunconv.c'
/*
 * pwunconv - restore old password file from shadow password file.
 *
 *	Pwunconv copies the password file information from the shadow
 *	password file, merging entries from an optional existing shadow
 *	file.
 *
 *	The new password file is left in npasswd.  There is no new
 *	shadow file.  Password aging information is translated where
 *	possible.
 */

#include <sys/types.h>
#include <stdio.h>
#include <fcntl.h>
#include <pwd.h>
#include "config.h"
#include "shadow.h"

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

char	buf[BUFSIZ];
char	*l64a ();

int	main ()
{
	struct	passwd	*pw;
	struct	passwd	*sgetpwent ();
	FILE	*pwd;
	FILE	*npwd;
	struct	spwd	*spwd;
	int	fd;

	if (! (pwd = fopen (PWDFILE, "r"))) {
		perror (PWDFILE);
		return (1);
	}
	unlink ("npasswd");
	if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
			! (npwd = fdopen (fd, "w"))) {
		perror ("npasswd");
		return (1);
	}
	while (fgets (buf, BUFSIZ, pwd) == buf) {
		buf[strlen (buf) - 1] = '\0'; /* remove '\n' character */

		if (buf[0] == '#') {	/* comment line */
			(void) fprintf (npwd, "%s\n", buf);
			continue;
		}
		if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */
			(void) fprintf (npwd, "%s\n", buf);
			continue;
		}
		setspent ();		/* rewind shadow file */

		if (! (spwd = getspnam (pw->pw_name))) {
			(void) fprintf (npwd, "%s\n", buf);
			continue;
		}
		pw->pw_passwd = spwd->sp_pwdp;

	/*
	 * Password aging works differently in the two different systems.
	 * With shadow password files you apparently must have some aging
	 * information.  The maxweeks or minweeks may not map exactly.
	 * In pwconv we set max == 10000, which is about 30 years.  Here
	 * we have to undo that kludge.  So, if maxdays == 10000, no aging
	 * information is put into the new file.  Otherwise, the days are
	 * converted to weeks and so on.
	 */

		if (spwd->sp_max > (63*7) && spwd->sp_max < 10000)
			spwd->sp_max = (63*7); /* 10000 is infinity this week */

		if (spwd->sp_min >= 0 && spwd->sp_min <= 63*7 &&
				spwd->sp_max >= 0 && spwd->sp_max <= 63*7) {
			spwd->sp_max /= 7;	/* turn it into weeks */
			spwd->sp_min /= 7;
			spwd->sp_lstchg /= 7;
			pw->pw_age = l64a ((long) spwd->sp_lstchg * (64L*64L) +
						  spwd->sp_min * (64L) +
						  spwd->sp_max);
		} else
			pw->pw_age = (char *) 0;

		if (pw->pw_age)
			(void) fprintf (npwd, "%s:%s,%s:%d:%d:%s:%s:%s\n",
				pw->pw_name, pw->pw_passwd ? pw->pw_passwd:"",
				pw->pw_age, pw->pw_uid, pw->pw_gid,
				pw->pw_gecos, pw->pw_dir,
				pw->pw_shell ? pw->pw_shell:"");
		else
			(void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:%s\n",
				pw->pw_name, pw->pw_passwd ? pw->pw_passwd:"",
				pw->pw_uid, pw->pw_gid,
				pw->pw_gecos, pw->pw_dir,
				pw->pw_shell ? pw->pw_shell:"");
	}
	endspent ();

	if (ferror (npwd)) {
		perror ("pwunconv");
		(void) unlink ("npasswd");
	}
	(void) fclose (npwd);
	(void) fclose (pwd);
	return (0);
}
SHAR_EOF
fi
if test -f 'failure.c'
then
	echo shar: "will not over-write existing file 'failure.c'"
else
cat << \SHAR_EOF > 'failure.c'
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#ifndef	BSD
#include <string.h>
#include <memory.h>
#else
#include <strings.h>
#define	strchr	index
#define	strrchr	rindex
#endif
#include "faillog.h"
#include "config.h"

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

#ifdef	FAILLOG

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

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

/*
 * failure - make failure entry
 */

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

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

	lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
	if (read (fd, (char *) faillog, sizeof *faillog)
			!= sizeof *faillog)
#ifndef	BSD
		memset ((void *) faillog, '\0', sizeof *faillog);
#else
		bzero ((char *) faillog, sizeof *faillog);
#endif

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

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

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

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

int
failcheck (uid, faillog, failed)
int	uid;
struct	faillog	*faillog;
{
	int	fd;
	int	okay = 1;
	struct	faillog	fail;

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

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

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

	return (okay);
}

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

void
failprint (uid, fail)
struct	faillog	*fail;
{
	int	fd;
	struct	tm	*tp;
	char	*lasttime;

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

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

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

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

	printf ("%d %s since last login.  Last was %s on %s.\n",
		fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure",
		lasttime, fail->fail_line);
}
#endif
SHAR_EOF
fi
if test -f 'faillog.h'
then
	echo shar: "will not over-write existing file 'faillog.h'"
else
cat << \SHAR_EOF > 'faillog.h'
/*
 * faillog.h - login failure logging file format
 *
 *	@(#)faillog.h	2.1	01:23:15	6/20/89
 *
 * The login failure file is maintained by login(1) and fail(1L)
 * Each record in the file represents a separate UID and the file
 * is indexed in that fashion.
 */

#define	FAILFILE	"/usr/adm/faillog"

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

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

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

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

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

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

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

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

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

print ()
{
	int	uid;
	off_t	offset;

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

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

			if (faillog.fail_cnt == 0)
				continue;

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

			print_one (&faillog, uid);
		}
	}
}

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

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

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

reset ()
{
	int	uid = 0;

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

reset_one (uid)
int	uid;
{
	off_t	offset;

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

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

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

	faillog.fail_cnt = 0;

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

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

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

setmax_one (uid)
int	uid;
{
	off_t	offset;

	offset = uid * sizeof faillog;

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

	if (fseek (fail, offset, 0) == 0
		&& fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1)
		fflush (fail);
	else
		perror (FAILFILE);
}
SHAR_EOF
fi
exit 0
#	End of shell archive
-- 
John F. Haugh II                        +-Button of the Week Club:-------------
VoiceNet: (512) 832-8832   Data: -8835  | "AIX is a three letter word,
InterNet: jfh at rpp386.Cactus.Org         |  and it's BLUE."
UucpNet : <backbone>!bigtex!rpp386!jfh  +--------------------------------------



More information about the Alt.sources mailing list