#! /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
# This archive created: Sun Jan 22 22:24:55 1989
# By:	John F. Haugh II (River Parishes Programming, Dallas 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>
#include <string.h>

void	setenv ();

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

	memset (buf, 0, BUFSIZ);

	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>
#include <string.h>
#include "config.h"

extern	char	home[];

void	motd ()
{
#ifdef	MOTD
	FILE	*fp;
	register int	c;
#ifdef	HUSHLOGIN
	char	hush[BUFSIZ];

	(void) strcat (strcpy (hush, home + 5), "/.hushlogin");

	if (access (hush, 0) == 0)
		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>
#include <string.h>
#include <termio.h>
#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.
 */

int	password (prompt, pass)
char	*prompt;
char	*pass;
{
	char	buf[BUFSIZ];
	int	eof;
	int	ttyopened = 0;
	struct	termio	termio;
	struct	termio	save;
	FILE	*fp;

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

	if (ioctl (fileno (fp), TCGETA, &termio))
		return (0);

	save = termio;
	termio.c_lflag &= ~ECHO;
	ioctl (fileno (fp), TCSETAF, &termio);

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

	ioctl (fileno (fp), TCSETAF, &save);

	if (! eof) {
		buf[8] = '\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>
#include <string.h>
#include "config.h"

extern	char	*newenvp[];

void	shell (file)
char	*file;
{
	char	arg0[BUFSIZ];
#ifndef	SU
	char	*path;
#endif
	char	*strrchr ();
	extern	int	errno;

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

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

	(void) strcpy (arg0 + 1, path);
	arg0[0] = '-';
#else
	(void) strcpy (arg0, "-su");
#endif
#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>
#include <string.h>
#include <stdio.h>
#include "config.h"

extern	struct	utmp	utent;
extern	char	name[];

struct	utmp	*getutent ();
void	setutent ();
void	endutent ();
void	pututline ();
char	*memset ();
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);
		(void) memset (utent.ut_line, '\0', sizeof utent.ut_line);
		(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	PASSWD
extern	char	*newenvp[];
#endif

time_t	time ();

#ifdef	AGING
#ifdef	PASSWD
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
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');
}

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);
}

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);
}
#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>
#include <string.h>

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
		len = strlen (entry);

	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;
	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;
		}
		addenv (argv[i]);
	}
}
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>

#define	SBUFSIZ	64

static	char	*tokcpy (buf, token)
char	*buf;
char	*token;
{
	static	char	*cp;
	char	*start;

	if (buf == (char *) 0)
		buf = cp;
	else
		cp = buf;

	start = cp;

	if (*buf == '\0')
		return ((char *) 0);

	while (*buf && *buf != ':')
		*token++ = *buf++;

	*token = '\0';

	if (*buf)
		cp = buf + 1;

	return (start);
}

struct	passwd	*sgetpwent (buf)
char	*buf;
{
	static	struct	passwd	pwent;
	static	char	name[SBUFSIZ];
	static	char	password[SBUFSIZ];
	static	char	gecos[SBUFSIZ];
	static	char	home[SBUFSIZ];
	static	char	shell[SBUFSIZ];
	static	char	age[SBUFSIZ];
	char	tmp[BUFSIZ];
	char	*cp;

	pwent.pw_name = name;
	pwent.pw_passwd = password;
	pwent.pw_uid = -1;
	pwent.pw_gid = -1;
	pwent.pw_age = age;
	pwent.pw_comment = (char *) 0;
	pwent.pw_gecos = gecos;
	pwent.pw_dir = home;
	pwent.pw_shell = shell;

	(void) strcpy (tmp, buf);

	if (! tokcpy (tmp, name) || ! name[0])
		return ((struct passwd *) 0);

	if (! tokcpy ((char *) 0, password))
		return ((struct passwd *) 0);

	if (tokcpy ((char *) 0, tmp) && *tmp)
		pwent.pw_uid = atoi (tmp);
	else
		return ((struct passwd *) 0);

	if (tokcpy ((char *) 0, tmp) && *tmp)
		pwent.pw_gid = atoi (tmp);
	else
		return ((struct passwd *) 0);

	if (cp = strchr (password, ',')) {
		(void) strcpy (age, cp + 1);
		*cp = '\0';
	} else
		pwent.pw_age = (char *) 0;

	if (! tokcpy ((char *) 0, gecos))
		return ((struct passwd *) 0);

	if (! tokcpy ((char *) 0, home))
		return ((struct passwd *) 0);

	if (! tokcpy ((char *) 0, shell) && *shell)
		pwent.pw_shell = (char *) 0;

	if (pwent.pw_passwd && pwent.pw_passwd[0] == '\0')
		pwent.pw_passwd = (char *) 0;

	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>
#include <string.h>

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:%d:%d\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 <pwd.h>

/*
 * 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 ();

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

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

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

	if (entry->pw_passwd && strcmp (encrypt, entry->pw_passwd) == 0)
		return (1);
	else
		return (0);
}
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 <stdio.h>
#include <pwd.h>
#include <utmp.h>
#include <time.h>
#include <string.h>
#include <signal.h>
#include "config.h"
#include "lastlog.h"

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

struct	passwd	pwent;
struct	utmp	utent;
struct	lastlog	lastlog;

#ifndef	MAXENV
#define	MAXENV	64
#endif

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

char	*getenv ();
char	*memset ();
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 ();

#ifndef	ALARM
#define	ALARM	60
#endif

#ifndef	RETRIES
#define	RETRIES	3
#endif

int	main (argc, argv, envp)
int	argc;
char	**argv;
char	**envp;
{
	int	retries = RETRIES;

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

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

	while (*envp)			/* add inherited environment, */
		addenv (*envp++);	/* some variables change later */

#ifdef	TZ
	addenv (TZ);			/* set the default $TZ, if one */
#endif
#ifdef	HZ
	addenv (HZ);			/* set the default $HZ, if one */
#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 */

	/*
	 * 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 ... */
			break;		/* ... encrypted passwords matched */

		if (--retries <= 0)	/* only allow so many failures */
			exit (1);

		puts ("Login incorrect");
		(void) memset (name, '\0', sizeof name);
	}
#ifdef	DIALUP
	if (! dialcheck (utent.ut_line,
			pwent.pw_shell ? pwent.pw_shell:"/bin/sh")) {
		puts ("Dialup password incorrect");
		exit (1);
	}
#endif
	(void) alarm (0);		/* turn off alarm clock */
	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 */
#ifdef	CONSOLE
	if (pwent.pw_uid == 0 &&	/* root no logging in on console ? */
			strncmp (CONSOLE, utent.ut_line, sizeof utent.ut_line))
		exit (1);		/* then exit! */
#endif
	if (pwent.pw_shell[0] == '*')	/* subsystem root required */
		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	MOTD
	motd ();			/* print the message of the day */
#endif
#ifdef	LASTLOG
	if (lastlog.ll_time != 0)
		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
	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>
#include <string.h>
#include <signal.h>
#include "config.h"
#include "lastlog.h"

#ifndef	MAXENV
#define	MAXENV	64
#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;

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;
{
	char	*getenv ();
	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
	addenv (TZ);			/* set the default $TZ, if one */
#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_name == (char *) 0) { /* unknown user */
		(void) fprintf (stderr, "Unknown id: %s\n", pwent.pw_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.
	 */

#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);
	}
#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 (! pwent.pw_shell)
			pwent.pw_shell = "/bin/sh";

		argv[-1] = pwent.pw_shell;
		(void) execv (pwent.pw_shell, &argv[-1]);
		(void) fprintf (stderr, "No shell\n");
		exit (1);
	}
	if (fakelogin) {
#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 (pwent.pw_shell == (char *) 0)
			pwent.pw_shell = "/bin/sh";

		execl (pwent.pw_shell, "su", (char *) 0);
		perror (pwent.pw_shell);
		exit (1);
	}
	/*NOTREACHED*/
}
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 10000 days,
 *	with a last changed date of today, unless password aging
 *	information was already present.  Entries with blank passwords
 *	are 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 "lastlog.h"
#include "shadow.h"

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 = 10000;
				tspwd.sp_min = 0;
				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>
#include <string.h>
#include "dialup.h"

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)
		if (buf[0] == '#')
			continue;

	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);

	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) {
		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"

/*
 * 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 "lastlog.h"
#include "shadow.h"

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
exit 0
#	End of shell archive