[alt.sources] Shadow Password Suite

jfh@rpp386.cactus.org (John F Haugh II) (12/13/90)

#! /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 <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <errno.h>
X#ifndef	BSD
X#include <termio.h>
X#include <string.h>
X#include <memory.h>
X#else
X#include <sgtty.h>
X#include <strings.h>
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 <dbm.h>
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 <stdio.h>
X#include <time.h>
X#include <sys/types.h>
X#include <ctype.h>
X#include <errno.h>
X#ifndef	BSD
X#include <string.h>
X#else
X#include <strings.h>
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 <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <utmp.h>
X#include <time.h>
X#include <signal.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#ifndef	BSD
X#include <termio.h>
X#else
X#include <sgtty.h>
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 <stdio.h>
X#include <fcntl.h>
X#include <pwd.h>
X#ifdef	BSD
X#include <strings.h>
X#else
X#include <string.h>
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 <dbm.h>
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 <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <utmp.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
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 <stdio.h>
X#include <pwd.h>
X#ifdef	BSD
X#include <strings.h>
X#else
X#include <string.h>
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 <stdio.h>
X#ifndef	BSD
X#include <string.h>
X#else
X#include <strings.h>
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 <sys/types.h>
X#include <stdio.h>
X#include <time.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
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 <stdio.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#ifndef	BSD
X#include <termio.h>
X#else
X#include <sgtty.h>
X#endif
X
X#include <fcntl.h>
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 <stdio.h>
X#ifndef	BSD
X#include <string.h>
X#else
X#define	strchr	index
X#define	strrchr	rindex
X#include <strings.h>
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 <sys/types.h>
X#include <sys/stat.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
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 <stdio.h>
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
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org

jfh@rpp386.cactus.org (John F Haugh II) (12/13/90)

#! /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:
#	chfn.c
#	chsh.c
#	smain.c
#	faillog.c
#	pwconv.c
#	failure.c
#	utmp.c
#	shadow.c
#	log.c
#	shadow.h
#	faillog.h
# This archive created: Wed Dec 12 12:36:59 1990
# By:	John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'chfn.c'" '(10514 characters)'
if test -f 'chfn.c'
then
	echo shar: "will not over-write existing file 'chfn.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chfn.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 <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <errno.h>
X#include <ctype.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifdef	DBM
X#include <dbm.h>
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)chfn.c	2.2	19:17:28	8/4/90";
X#endif
X
Xchar	*myname;
X
Xchar	user[BUFSIZ];
Xchar	fullnm[BUFSIZ];
Xchar	roomno[BUFSIZ];
Xchar	workph[BUFSIZ];
Xchar	homeph[BUFSIZ];
Xchar	slop[BUFSIZ];
Xint	fflg;
Xint	rflg;
Xint	wflg;
Xint	hflg;
Xint	oflg;
X
Xstruct	passwd	pwent;
X
Xextern	int	errno;
X
Xchar	Usage[] =
X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ] [ -h home_ph ]\n";
X
Xchar	Usage_root[] =
X"Usage: %s [ -f full_name ] [ -r room_no ] [ -w work_ph ]\n\
X       [ -h home_ph ] [ -o other ] [ user ]\n";
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X	fprintf (stderr, getuid () == 0 ? Usage_root:Usage, myname);
X	exit (1);
X}
X
X/*
X * valid_field - insure that a field contains all legal characters
X *
X * The supplied field is scanned for non-printing and other illegal
X * characters.  If any illegal characters are found, valid_field
X * prints a message and exits.
X */
X
Xvoid
Xvalid_field (field, illegal)
Xchar	*field;
Xchar	*illegal;
X{
X	char	*cp;
X
X	for (cp = field;*cp && isprint (*cp) && ! strchr (illegal, *cp);cp++)
X		;
X
X	if (*cp) {
X		fprintf (stderr, "%s: invalid field: %s\n", myname, field);
X		exit (1);
X	}
X}
X
X/*
X * change_field - change a single field if a new value is given.
X *
X * prompt the user with the name of the field being changed and the
X * current value.
X */
X
Xvoid
Xchange_field (buf, prompt)
Xchar	*buf;
Xchar	*prompt;
X{
X	char	new[BUFSIZ];
X	char	*cp;
X
X	printf ("\t%s [%s]: ", prompt, buf);
X	fgets (new, BUFSIZ, stdin);
X
X	if (cp = strchr (new, '\n'))
X		*cp = '\0';
X	else
X		return;
X
X	if (new[0])
X		strcpy (buf, new);
X}
X
X/*
X * new_fields - change the user's GECOS information interactively
X *
X * prompt the user for each of the four fields and fill in the fields
X * from the user's response, or leave alone if nothing was entered.
X */
X
Xnew_fields ()
X{
X	printf ("Enter the new value, or press return for the default\n\n");
X
X	change_field (fullnm, "Full Name");
X	change_field (roomno, "Room Number");
X	change_field (workph, "Work Phone");
X	change_field (homeph, "Home Phone");
X
X	if (getuid () == 0)
X		change_field (slop, "Other");
X}
X
X/*
X * copy_field - get the next field from the gecos field
X *
X * copy_field copies the next field from the gecos field, returning a
X * pointer to the field which follows, or NULL if there are no more
X * fields.
X */
X
Xchar *
Xcopy_field (in, out, extra)
Xchar	*in;			/* the current GECOS field */
Xchar	*out;			/* where to copy the field to */
Xchar	*extra;			/* fields with '=' get copied here */
X{
X	char	*cp;
X
X	while (in) {
X		if (cp = strchr (in, ','))
X			*cp++ = '\0';
X
X		if (! strchr (in, '='))
X			break;
X
X		if (extra) {
X			if (extra[0])
X				strcat (extra, ",");
X
X			strcat (extra, in);
X		}
X		in = cp;
X	}
X	if (in && out)
X		strcpy (out, in);
X
X	return cp;
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	extern	int	optind;
X	extern	char	*optarg;
X	void	die ();
X	char	*cp;
X	char	*getlogin ();
X	int	amroot;
X	int	lockfd = -1;
X	int	flag;
X	struct	passwd	*pw;
X	struct	passwd	*getpwuid ();
X	struct	passwd	*getpwnam ();
X	struct	passwd	*sgetpwent ();
X	FILE	*npwd;
X	FILE	*pwd;
X	char	buf[BUFSIZ];
X	char	tmp[BUFSIZ];
X
X	amroot = getuid () == 0;
X	if (myname = strchr (argv[0], '/'))
X		myname++;
X	else
X		myname = argv[0];
X
X	while ((flag = getopt (argc, argv, "f:r:w:h:o:")) != EOF) {
X		switch (flag) {
X			case 'f':
X				fflg++;
X				strcpy (fullnm, optarg);
X				break;
X			case 'r':
X				rflg++;
X				strcpy (roomno, optarg);
X				break;
X			case 'w':
X				wflg++;
X				strcpy (workph, optarg);
X				break;
X			case 'h':
X				hflg++;
X				strcpy (homeph, optarg);
X				break;
X			case 'o':
X				if (getuid () == 0) {
X					oflg++;
X					strcpy (slop, optarg);
X					break;
X				}
X				fprintf (stderr, "%s: permission denied\n",
X					myname);
X				exit (1);
X			default:
X				usage ();
X		}
X	}
X	if (argc > optind) {
X		if (argc > optind + 1)
X			usage ();
X
X		if (! (pw = getpwnam (argv[optind]))) {
X			fprintf (stderr, "%s: unknown user: %s\n",
X				myname, argv[optind]);
X			exit (1);
X		}
X	} else {
X		if (cp = getlogin ()) {
X			if (! (pw = getpwnam (cp))) {
X				fprintf (stderr, "%s: unknown user: %s\n",
X					myname, cp);
X				exit (1);
X			}
X		} else if (! (pw = getpwuid (getuid ()))) {
X			fprintf (stderr, "%s: who are you?\n",
X				myname);
X			exit (1);
X		}
X	}
X	if (! amroot && pw->pw_uid != getuid ()) {
X		fprintf (stderr, "%s: permission denied\n",
X			myname);
X		exit (1);
X	}
X	strcpy (user, pw->pw_name);
X
X	pwent = *pw;
X	pwent.pw_name = strdup (pw->pw_name);
X	pwent.pw_passwd = strdup (pw->pw_passwd);
X	pwent.pw_dir = strdup (pw->pw_dir);
X	pwent.pw_shell = strdup (pw->pw_shell);
X
X	/*
X	 * Now get the full name.  It is the first comma separated field
X	 * in the GECOS field.
X	 */
X
X	strcpy (buf, pw->pw_gecos);
X	cp = copy_field (buf, fflg ? (char *) 0:fullnm, slop);
X
X	/*
X	 * Now get the room number.  It is the next comma separated field,
X	 * if there is indeed one.
X	 */
X
X	if (cp)
X		cp = copy_field (cp, rflg ? (char *) 0:roomno, slop);
X
X	/*
X	 * Now get the work phone number.  It is the third field.
X	 */
X
X	if (cp)
X		cp = copy_field (cp, wflg ? (char *) 0:workph, slop);
X
X	/*
X	 * Now get the home phone number.  It is the fourth field.
X	 */
X
X	if (cp)
X		cp = copy_field (cp, hflg ? (char *) 0:homeph, slop);
X
X	/*
X	 * Anything left over is "slop".
X	 */
X
X	if (cp) {
X		if (slop[0])
X			strcat (slop, ",");
X
X		strcat (slop, cp);
X	}
X
X	/*
X	 * If none of the fields were changed from the command line,
X	 * let the user interactively change them.
X	 */
X
X	if (! fflg && ! rflg && ! wflg && ! hflg && ! oflg) {
X		printf ("Changing the user information for %s\n", user);
X		new_fields ();
X	}
X
X	/*
X	 * Check all of the fields for valid information
X	 */
X
X	valid_field (fullnm, ":,=");
X	valid_field (roomno, ":,=");
X	valid_field (workph, ":,=");
X	valid_field (homeph, ":,=");
X	valid_field (slop, ":");
X
X	/*
X	 * Build the new GECOS field by plastering all the pieces together,
X	 * if they will fit ...
X	 */
X
X	if (strlen (fullnm) + strlen (roomno) + strlen (workph) +
X			strlen (homeph) + strlen (slop) > 80) {
X		fprintf (stderr, "%s: fields too long\n", myname);
X		exit (1);
X	}
X	sprintf (tmp, "%s,%s,%s,%s", fullnm, roomno, workph, homeph);
X	if (slop[0]) {
X		strcat (tmp, ",");
X		strcat (tmp, slop);
X	}
X	pwent.pw_gecos = tmp;
X
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
X#ifdef	DBM
X	update_dbm (&pwent);
X#endif
X	if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) {
X		perror (NPWDFILE);
X		exit (1);
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	{
X		perror (NPWDFILE);
X		exit (1);
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		perror (NPWDFILE);
X		exit (1);
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)
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#ifndef	NDEBUG
X	(void) unlink (".pwdlock");
X#else
X	(void) unlink (PWDLOCK);
X#endif
X	exit (0);
X	/*NOTREACHED*/
X
Xunlock:
X	if (lockfd >= 0)
X		(void) unlink (PWDLOCK);
X
X	(void) unlink (NPWDFILE);
X	exit (1);
X	/*NOTREACHED*/
X}
SHAR_EOF
if test 10514 -ne "`wc -c < 'chfn.c'`"
then
	echo shar: "error transmitting 'chfn.c'" '(should have been 10514 characters)'
fi
fi
echo shar: "extracting 'chsh.c'" '(9052 characters)'
if test -f 'chsh.c'
then
	echo shar: "will not over-write existing file 'chsh.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chsh.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 <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <errno.h>
X#include <ctype.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifdef	DBM
X#include <dbm.h>
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)chsh.c	2.2	12:54:39	10/22/90";
X#endif
X
Xchar	*myname;
Xint	amroot;
X
Xchar	user[BUFSIZ];
Xchar	loginsh[BUFSIZ];
Xint	sflg;
X
Xstruct	passwd	pwent;
X
Xextern	int	errno;
X
Xchar	Usage[] =
X"Usage: %s [ -s login_shell ] [ user_name ]\n";
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X	fprintf (stderr, Usage, myname);
X	exit (1);
X}
X
X/*
X * valid_field - insure that a field contains all legal characters
X *
X * The supplied field is scanned for non-printing and other illegal
X * characters.  If any illegal characters are found, valid_field
X * prints a message and exits.
X */
X
Xvoid
Xvalid_field (field, illegal)
Xchar	*field;
Xchar	*illegal;
X{
X	char	*cp;
X
X	for (cp = field;*cp && isprint (*cp) && ! strchr (illegal, *cp);cp++)
X		;
X
X	if (*cp) {
X		fprintf (stderr, "%s: invalid field: %s\n", myname, field);
X		exit (1);
X	}
X}
X
X/*
X * change_field - change a single field if a new value is given.
X *
X * prompt the user with the name of the field being changed and the
X * current value.
X */
X
Xvoid
Xchange_field (buf, prompt)
Xchar	*buf;
Xchar	*prompt;
X{
X	char	new[BUFSIZ];
X	char	*cp;
X
X	printf ("\t%s [%s]: ", prompt, buf);
X	fgets (new, BUFSIZ, stdin);
X
X	if (cp = strchr (new, '\n'))
X		*cp = '\0';
X	else
X		return;
X
X	if (new[0])
X		strcpy (buf, new);
X}
X
X/*
X * new_fields - change the user's login shell information interactively
X *
X * prompt the user for the login shell and change it according to the
X * response, or leave it alone if nothing was entered.
X */
X
Xnew_fields ()
X{
X	printf ("Enter the new value, or press return for the default\n\n");
X
X	change_field (loginsh, "Login Shell");
X}
X
X/*
X * check_shell - see if the user's login shell is listed in /etc/shells
X *
X * The /etc/shells file is read for valid names of login shells.  If the
X * /etc/shells file does not exist the user cannot set any shell unless
X * they are root.
X */
X
Xcheck_shell (shell)
Xchar	*shell;
X{
X	char	buf[BUFSIZ];
X	char	*cp;
X	int	found = 0;
X	FILE	*fp;
X
X	if (amroot)
X		return 1;
X
X	if ((fp = fopen ("/etc/shells", "r")) == (FILE *) 0)
X		return 0;
X
X	while (fgets (buf, BUFSIZ, fp) && ! found) {
X		if (cp = strrchr (buf, '\n'))
X			*cp = '\0';
X
X		if (strcmp (buf, shell) == 0)
X			found = 1;
X	}
X	fclose (fp);
X
X	return found;
X}
X
X/*
X * restricted_shell - return true if the named shell begins with 'r' or 'R'
X *
X * If the first letter of the filename is 'r' or 'R', the shell is
X * considered to be restricted.
X */
X
Xint
Xrestricted_shell (shell)
Xchar	*shell;
X{
X	char	*cp;
X
X	if (cp = strrchr (shell, '/'))
X		cp++;
X	else
X		cp = shell;
X
X	return *cp == 'r' || *cp == 'R';
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	extern	int	optind;
X	extern	char	*optarg;
X	void	die ();
X	char	*cp;
X	char	*getlogin ();
X	int	lockfd = -1;
X	int	flag;
X	struct	passwd	*pw;
X	struct	passwd	*getpwuid ();
X	struct	passwd	*getpwnam ();
X	struct	passwd	*sgetpwent ();
X	FILE	*npwd;
X	FILE	*pwd;
X	char	buf[BUFSIZ];
X	char	tmp[BUFSIZ];
X
X	amroot = getuid () == 0;
X	if (myname = strchr (argv[0], '/'))
X		myname++;
X	else
X		myname = argv[0];
X
X	while ((flag = getopt (argc, argv, "s:")) != EOF) {
X		switch (flag) {
X			case 's':
X				sflg++;
X				strcpy (loginsh, optarg);
X				break;
X			default:
X				usage ();
X		}
X	}
X	if (argc > optind) {
X		if (argc > optind + 1)
X			usage ();
X
X		if (! (pw = getpwnam (argv[optind]))) {
X			fprintf (stderr, "%s: unknown user: %s\n",
X				myname, argv[optind]);
X			exit (1);
X		}
X	} else {
X		if (cp = getlogin ()) {
X			if (! (pw = getpwnam (cp))) {
X				fprintf (stderr, "%s: unknown user: %s\n",
X					myname, cp);
X				exit (1);
X			}
X		} else if (! (pw = getpwuid (getuid ()))) {
X			fprintf (stderr, "%s: who are you?\n",
X				myname);
X			exit (1);
X		}
X	}
X	if (! amroot && pw->pw_uid != getuid ()) {
X		fprintf (stderr, "%s: permission denied\n",
X			myname);
X		exit (1);
X	}
X	if (! amroot && restricted_shell (pw->pw_shell)) {
X		fprintf (stderr, "%s: permission denied\n",
X			myname);
X		exit (1);
X	}
X	strcpy (user, pw->pw_name);
X
X	pwent = *pw;
X	pwent.pw_name = strdup (pw->pw_name);
X	pwent.pw_passwd = strdup (pw->pw_passwd);
X	pwent.pw_dir = strdup (pw->pw_dir);
X	pwent.pw_gecos = strdup (pw->pw_gecos);
X
X	/*
X	 * Now get the login shell.  Either get it from the password
X	 * file, or use the value from the command line.
X	 */
X
X	if (! sflg)
X		strcpy (loginsh, pw->pw_shell);
X
X	/*
X	 * If the login shell was not set on the command line,
X	 * let the user interactively change it.
X	 */
X
X	if (! sflg) {
X		printf ("Changing the login shell for %s\n", user);
X		new_fields ();
X	}
X
X	/*
X	 * Check all of the fields for valid information
X	 */
X
X	valid_field (loginsh, ":,=");
X	if (! check_shell (loginsh)) {
X		fprintf (stderr, "%s: %s is an invalid shell\n",
X			myname, loginsh);
X		exit (1);
X	}
X	pwent.pw_shell = loginsh;
X
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
X#ifdef	DBM
X	update_dbm (&pwent);
X#endif
X	if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) {
X		perror (NPWDFILE);
X		exit (1);
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	{
X		perror (NPWDFILE);
X		exit (1);
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		perror (NPWDFILE);
X		exit (1);
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);
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#ifndef	NDEBUG
X	(void) unlink (".pwdlock");
X#else
X	(void) unlink (PWDLOCK);
X#endif
X	exit (0);
X	/*NOTREACHED*/
X
Xunlock:
X	if (lockfd >= 0)
X		(void) unlink (PWDLOCK);
X
X	(void) unlink (NPWDFILE);
X	exit (1);
X	/*NOTREACHED*/
X}
SHAR_EOF
if test 9052 -ne "`wc -c < 'chsh.c'`"
then
	echo shar: "error transmitting 'chsh.c'" '(should have been 9052 characters)'
fi
fi
echo shar: "extracting 'smain.c'" '(6591 characters)'
if test -f 'smain.c'
then
	echo shar: "will not over-write existing file 'smain.c'"
else
sed 's/^X//' << \SHAR_EOF > 'smain.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 <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#include <termio.h>
X#else
X#include <strings.h>
X#include <sgtty.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include <signal.h>
X#include "config.h"
X#include "lastlog.h"
X
X#ifdef	SHADOWPWD
X#include "shadow.h"
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)smain.c	2.7	10:20:06	11/9/90";
X#endif
X
X#ifndef	MAXENV
X#define	MAXENV	64
X#endif
X
X#ifndef	PATH
X#define	PATH	":/bin:/usr/bin"
X#endif
X
X#ifndef	SUPATH
X#define	SUPATH	":/bin:/usr/bin:/etc"
X#endif
X
X#ifdef	HUSHLOGIN
Xchar	hush[BUFSIZ];
Xint	hushed;
X#endif
X
Xchar	name[BUFSIZ];
Xchar	pass[BUFSIZ];
Xchar	home[BUFSIZ];
Xchar	prog[BUFSIZ];
Xchar	mail[BUFSIZ];
Xchar	oldname[BUFSIZ];
Xchar	*newenvp[MAXENV];
Xint	newenvc = 0;
Xint	maxenv = MAXENV;
Xstruct	passwd	pwent;
X
X#ifdef	TZ
XFILE	*tzfile;
Xchar	tzbuf[16] = TZ;
X#endif
X
Xvoid	addenv ();
Xvoid	entry ();
Xvoid	sulog ();
Xvoid	subsystem ();
Xvoid	setup ();
Xvoid	motd ();
Xvoid	mailcheck ();
Xvoid	shell ();
Xvoid	expire ();
X
Xextern	char	**environ;
X
Xint	main (argc, argv, envp)
Xint	argc;
Xchar	**argv;
Xchar	**envp;
X{
X	void	die ();
X	char	*getenv ();
X	char	*cp;
X	int	doshell;
X	int	fakelogin = 0;
X	int	amroot;
X	struct	passwd	*pw;
X	struct	passwd	*getpwuid ();
X#ifdef	SHADOWPWD
X	struct	spwd	*spwd;
X	struct	spwd	*getspnam();
X#endif
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	argc--; argv++;			/* shift out command name */
X
X	if (argc > 0 && argv[0][0] == '-' && argv[0][1] == '\0') {
X		fakelogin = 1;
X		argc--; argv++;		/* shift ... */
X	}
X	if (argc > 0 && argv[0][0] != '-') {
X		(void) strcpy (name, argv[0]);	/* use this login id */
X		argc--; argv++;		/* shift ... */
X	}
X	doshell = argc == 0;		/* any arguments remaining? */
X
X	if (pw = getpwuid (getuid ()))	/* need old user name */
X		(void) strcpy (oldname, pw->pw_name);
X	else				/* user ID MUST exist */
X		goto failure;
X
X	amroot = getuid () == 0;	/* currently am super user */
X
X	if (! name[0]) 			/* use default user ID */
X		(void) strcpy (name, "root");
X
X	entry (name, &pwent);		/* get password file entry */
X	if (pwent.pw_shell == (char *) 0 || pwent.pw_shell[0] == '\0')
X		pwent.pw_shell = "/bin/sh";
X
X	if (pwent.pw_name == (char *) 0) { /* unknown user */
X		(void) fprintf (stderr, "Unknown id: %s\n", name);
X		exit (1);
X	}
X#ifdef	NOUSE
X	if (strcmp (pwent.pw_shell, NOUSE) == 0)
X		goto failure;
X#endif
X#ifdef	NOLOGIN
X	if (strcmp (pwent.pw_shell, NOLOGIN) == 0)
X		if (! (pwent.pw_shell = getenv ("SHELL")))
X			pwent.pw_shell = "/bin/sh";
X#endif
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	die (0);
X
X	signal (SIGHUP, die);
X	signal (SIGINT, die);
X	signal (SIGQUIT, die);
X	signal (SIGTERM, die);
X
X#ifdef	NOBLANK
X	if (! amroot && ! password ("Password:", pass))
X		goto failure;
X#else
X	if (! amroot && (pwent.pw_name == (char *) 0 || *pwent.pw_passwd)
X			&& ! password ("Password:", pass))
X		goto failure;
X#endif
X					/* check encrypted passwords ... */
X	if (! amroot && ! valid (pass, &pwent)) {
Xfailure:	sulog (0);		/* log failed attempt */
X		puts ("Sorry.");
X		exit (1);
X	}
X	signal (SIGHUP, SIG_DFL);
X	signal (SIGINT, SIG_DFL);
X	signal (SIGQUIT, SIG_DFL);
X	signal (SIGTERM, SIG_DFL);
X
X#ifdef	SHADOWPWD
X	/*
X	 * Need to get expiration information before changing UID
X	 */
X
X	setspent ();
X	spwd = getspnam (pwent.pw_name);
X	endspent ();
X#endif
X#ifdef	AGING
X
X	/*
X	 * Check to see if the account is expired.  root gets to
X	 * ignore any expired accounts, but normal users can't become
X	 * a user with an expired password.
X	 */
X
X	if (! amroot &&
X			pwent.pw_age && pwent.pw_age[0]) {
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		expire (pwent.pw_name, (strlen (pwent.pw_age) == 4 ?
X			a64l (pwent.pw_age + 2):0L) * 7,
X			c64i (pwent.pw_age[1]), c64i (pwent.pw_age[0]));
X	}
X#endif
X#ifdef	SULOG
X	sulog (1);			/* save SU information */
X#endif
X	if (pwent.pw_uid == 0)
X		addenv (SUPATH);
X	else
X		addenv (PATH);
X
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	if (doshell && pwent.pw_shell[0] == '*') /* subsystem root required */
X		subsystem ();		/* figure out what to execute */
X
X	if (fakelogin)
X		setup (&pwent);		/* set UID, GID, HOME, etc ... */
X	else {
X		if (setgid (pwent.pw_gid) || setuid (pwent.pw_uid))  {
X			perror ("Can't set ID");
X			exit (1);
X		}
X	}
X	if (! doshell) {		/* execute arguments as command */
X		if (cp = getenv ("SHELL"))
X			pwent.pw_shell = cp;
X		argv[-1] = pwent.pw_shell;
X		(void) execv (pwent.pw_shell, &argv[-1]);
X		(void) fprintf (stderr, "No shell\n");
X		exit (1);
X	}
X	if (fakelogin) {
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	MAILCHECK
X		mailcheck ();		/* report on the status of mail */
X#endif
X		shell (pwent.pw_shell);	/* exec the shell finally. */
X	} else {
X		if (cp = strrchr (pwent.pw_shell, '/'))
X			cp++;
X		else
X			cp = pwent.pw_shell;
X
X		execl (pwent.pw_shell, cp, (char *) 0);
X		perror (pwent.pw_shell);
X		exit (1);
X	}
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		exit (killed);
X}
SHAR_EOF
if test 6591 -ne "`wc -c < 'smain.c'`"
then
	echo shar: "error transmitting 'smain.c'" '(should have been 6591 characters)'
fi
fi
echo shar: "extracting 'faillog.c'" '(4833 characters)'
if test -f 'faillog.c'
then
	echo shar: "will not over-write existing file 'faillog.c'"
else
sed 's/^X//' << \SHAR_EOF > 'faillog.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 <sys/types.h>
X#include <sys/stat.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <time.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X#include "faillog.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)faillog.c	2.2	19:23:44	7/29/90";
X#endif
X
XFILE	*fail;		/* failure file stream */
Xoff_t	user;		/* one single user, specified on command line */
Xint	days;		/* number of days to consider for print command */
Xtime_t	seconds;	/* that number of days in seconds */
Xint	max;		/* maximum failure count for fail_max */
X
Xint	mflg;		/* set fail_max for a given user */
Xint	rflg;		/* reset fail_cnt for user or all user's */
Xint	uflg;		/* set if user is a valid user id */
Xint	tflg;		/* print is restricted to most recent days */
Xstruct	faillog	faillog; /* scratch structure to play with ... */
Xstruct	stat	statbuf; /* fstat buffer for file size */
X
Xextern	int	optind;
Xextern	char	*optarg;
Xextern	char	*asctime ();
Xextern	struct	passwd	*getpwuid ();
Xextern	struct	passwd	*getpwnam ();
Xextern	struct	passwd	*getpwent ();
Xextern	struct	tm	*localtime ();
X
X#define	DAY	(24L*3600L)
X#define	NOW	(time ((time_t *) 0))
X
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	char	*mode;
X	int	uid = 0;
X	int	c;
X	struct	passwd	*pwent;
X
X	if (getuid () == 0)	/* only root can update anything */
X		mode = "r+";
X	else			/* all others can only look */
X		mode = "r";
X
X	if ((fail = fopen (FAILFILE, mode)) == (FILE *) 0) {
X		perror (FAILFILE);
X		exit (1);
X	}
X	while ((c = getopt (argc, argv, "m:pru:t:")) != EOF) {
X		switch (c) {
X			case 'm':
X				max = atoi (optarg);
X				setmax ();
X				break;
X			case 'p':
X				print ();
X				break;
X			case 'r':
X				reset ();
X				break;
X			case 'u':
X				pwent = getpwnam (optarg);
X				if (! pwent) {
X					fprintf (stderr, "Unknown User: %s\n", optarg);
X					exit (1);
X				}
X				uflg++;
X				user = pwent->pw_uid;
X				break;
X			case 't':
X				days = atoi (optarg);
X				seconds = days * DAY;
X				tflg++;
X				break;
X		}
X	}
X	fclose (fail);
X	exit (0);
X}
X
Xprint ()
X{
X	int	uid;
X	off_t	offset;
X
X	if (uflg) {
X		offset = user * sizeof faillog;
X		fstat (fileno (fail), &statbuf);
X		if (offset >= statbuf.st_size)
X			return;
X
X		fseek (fail, (off_t) user * sizeof faillog, 0);
X		if (fread ((char *) &faillog, sizeof faillog, 1, fail) == 1)
X			print_one (&faillog, user);
X		else
X			perror (FAILFILE);
X	} else {
X		for (uid = 0;
X			fread ((char *) &faillog, sizeof faillog, 1, fail) == 1;
X				uid++) {
X
X			if (faillog.fail_cnt == 0)
X				continue;
X
X			if (tflg && NOW - faillog.fail_time > seconds)
X				continue;
X
X			print_one (&faillog, uid);
X		}
X	}
X}
X
Xprint_one (faillog, uid)
Xstruct	faillog	*faillog;
X{
X	static	int	once;
X	char	*cp;
X	struct	tm	*tm;
X	struct	passwd	*pwent;
X
X	if (! once) {
X		printf ("Username        Failures    Maximum     Latest\n");
X		once++;
X	}
X	pwent = getpwuid (uid);
X	tm = localtime (&faillog->fail_time);
X	cp = asctime (tm);
X	cp[24] = '\0';
X
X	if (pwent) {
X		printf ("%-16s    %4d       %4d",
X			pwent->pw_name, faillog->fail_cnt, faillog->fail_max);
X		if (faillog->fail_time)
X			printf ("     %s on %s\n", cp, faillog->fail_line);
X		else
X			putchar ('\n');
X	}
X}
X
Xreset ()
X{
X	int	uid = 0;
X
X	if (uflg)
X		reset_one (user);
X	else
X		for (uid = 0;reset_one (uid);uid++)
X			;
X}
X
Xreset_one (uid)
Xint	uid;
X{
X	off_t	offset;
X
X	offset = uid * sizeof faillog;
X	fstat (fileno (fail), &statbuf);
X	if (offset >= statbuf.st_size)
X		return (0);
X
X	if (fseek (fail, offset, 0) != 0) {
X		perror (FAILFILE);
X		return (0);
X	}
X	if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
X		if (! feof (fail))
X			perror (FAILFILE);
X
X		return (0);
X	}
X	if (faillog.fail_cnt == 0)
X		return (1);	/* don't fill in no holes ... */
X
X	faillog.fail_cnt = 0;
X
X	if (fseek (fail, offset, 0) == 0
X		&& fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1) {
X		fflush (fail);
X		return (1);
X	} else {
X		perror (FAILFILE);
X	}
X	return (0);
X}
X
Xsetmax ()
X{
X	int	uid = 0;
X	struct	passwd	*pwent;
X
X	if (uflg) {
X		setmax_one (user);
X	} else {
X		setpwent ();
X		while (pwent = getpwent ())
X			setmax_one (pwent->pw_uid);
X	}
X}
X
Xsetmax_one (uid)
Xint	uid;
X{
X	off_t	offset;
X
X	offset = uid * sizeof faillog;
X
X	if (fseek (fail, offset, 0) != 0) {
X		perror (FAILFILE);
X		return;
X	}
X	if (fread ((char *) &faillog, sizeof faillog, 1, fail) != 1) {
X		if (! feof (fail))
X			perror (FAILFILE);
X	} else {
X#ifndef	BSD
X		memset ((char *) &faillog, '\0', sizeof faillog);
X#else
X		bzero ((char *) &faillog, sizeof faillog);
X#endif
X	}
X	faillog.fail_max = max;
X
X	if (fseek (fail, offset, 0) == 0
X		&& fwrite ((char *) &faillog, sizeof faillog, 1, fail) == 1)
X		fflush (fail);
X	else
X		perror (FAILFILE);
X}
SHAR_EOF
if test 4833 -ne "`wc -c < 'faillog.c'`"
then
	echo shar: "error transmitting 'faillog.c'" '(should have been 4833 characters)'
fi
fi
echo shar: "extracting 'pwconv.c'" '(3767 characters)'
if test -f 'pwconv.c'
then
	echo shar: "will not over-write existing file 'pwconv.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwconv.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/*
X * pwconv - convert and update shadow password files
X *
X *	Pwconv copies the old password file information to a new shadow
X *	password file, merging entries from an optional existing shadow
X *	file.
X *
X *	The new password file is left in npasswd, the new shadow file is
X *	left in nshadow.  Existing shadow entries are copied as is.
X *	New entries are created with passwords which expire in MAXDAYS days,
X *	with a last changed date of today, unless password aging
X *	information was already present.  Likewise, the minimum number of
X *	days before which the password may be changed is controlled by
X *	MINDAYS.  Entries with blank passwordsare not copied to the shadow
X *	file at all.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <pwd.h>
X#ifndef	BSD
X#include <string.h>
X#else
X#define	strchr	index
X#define	strrchr	rindex
X#include <strings.h>
X#endif
X#include "config.h"
X#include "shadow.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)pwconv.c	2.6	08:01:45	11/9/90";
X#endif
X
Xchar	buf[BUFSIZ];
X
Xlong	time ();
Xlong	a64l ();
X
Xint	main ()
X{
X	long	today;
X	struct	passwd	*pw;
X	struct	passwd	*sgetpwent ();
X	FILE	*pwd;
X	FILE	*npwd;
X	FILE	*shadow;
X	struct	spwd	*spwd;
X	struct	spwd	tspwd;
X	int	fd;
X	char	*cp;
X
X	if (! (pwd = fopen (PWDFILE, "r"))) {
X		perror (PWDFILE);
X		exit (1);
X	}
X	unlink ("npasswd");
X	if ((fd = open ("npasswd", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
X			! (npwd = fdopen (fd, "w"))) {
X		perror ("npasswd");
X		exit (1);
X	}
X	unlink  ("nshadow");
X	if ((fd = open ("nshadow", O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0 ||
X			! (shadow = fdopen (fd, "w"))) {
X		perror ("nshadow");
X		(void) unlink ("npasswd");
X		(void) unlink ("nshadow");
X		exit (1);
X	}
X
X	(void) time (&today);
X	today /= (24L * 60L * 60L);
X
X	while (fgets (buf, BUFSIZ, pwd) == buf) {
X		if (cp = strrchr (buf, '\n'))
X			*cp = '\0';
X
X		if (buf[0] == '#') {	/* comment line */
X			(void) fprintf (npwd, "%s\n", buf);
X			continue;
X		}
X		if (! (pw = sgetpwent (buf))) { /* copy bad lines verbatim */
X			(void) fprintf (npwd, "%s\n", buf);
X			continue;
X		}
X		if (pw->pw_passwd[0] == '\0') { /* no password, skip */
X			(void) fprintf (npwd, "%s\n", buf);
X			continue;
X		}
X		setspent ();		/* rewind old shadow file */
X
X		if (spwd = getspnam (pw->pw_name)) {
X			if (putspent (spwd, shadow)) { /* copy old entry */
X				perror ("nshadow");
X				goto error;
X			}
X		} else {		/* need a new entry. */
X			tspwd.sp_namp = pw->pw_name;
X			tspwd.sp_pwdp = pw->pw_passwd;
X			pw->pw_passwd = "x";
X
X			if (pw->pw_age) { /* copy old password age stuff */
X				tspwd.sp_min = c64i (pw->pw_age[1]);
X				tspwd.sp_max = c64i (pw->pw_age[0]);
X				if (strlen (pw->pw_age) == 4)
X					tspwd.sp_lstchg = a64l (&pw->pw_age[2]);
X				else
X					tspwd.sp_lstchg = 0L;
X
X				/*
X				 * Convert weeks to days
X				 */
X
X				tspwd.sp_min *= 7;
X				tspwd.sp_max *= 7;
X				tspwd.sp_lstchg *= 7;
X			} else {	/* fake up new password age stuff */
X				tspwd.sp_max = MAXDAYS;
X				tspwd.sp_min = MINDAYS;
X				tspwd.sp_lstchg = today;
X			}
X			if (putspent (&tspwd, shadow)) { /* output entry */
X				perror ("nshadow");
X				goto error;
X			}
X		}
X		(void) fprintf (npwd, "%s:%s:%d:%d:%s:%s:",
X				pw->pw_name, pw->pw_passwd,
X				pw->pw_uid, pw->pw_gid,
X				pw->pw_gecos, pw->pw_dir);
X
X		if (fprintf (npwd, "%s\n",
X				pw->pw_shell ? pw->pw_shell:"") == EOF) {
X			perror ("npasswd");
X			goto error;
X		}
X	}
X	endspent ();
X
X	if (ferror (npwd) || ferror (shadow)) {
X		perror ("pwconv");
Xerror:
X		(void) unlink ("npasswd");
X		(void) unlink ("nshadow");
X		exit (1);
X	}
X	(void) fclose (pwd);
X	(void) fclose (npwd);
X	(void) fclose (shadow);
X
X	exit (0);
X}
SHAR_EOF
if test 3767 -ne "`wc -c < 'pwconv.c'`"
then
	echo shar: "error transmitting 'pwconv.c'" '(should have been 3767 characters)'
fi
fi
echo shar: "extracting 'failure.c'" '(2948 characters)'
if test -f 'failure.c'
then
	echo shar: "will not over-write existing file 'failure.c'"
else
sed 's/^X//' << \SHAR_EOF > 'failure.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 <sys/types.h>
X#include <fcntl.h>
X#include <time.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "faillog.h"
X#include "config.h"
X
X#ifdef	FTMP
X#include <utmp.h>
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)failure.c	2.3	19:23:48	7/29/90";
X#endif
X
X#ifdef	FAILLOG
X
X#define	DAY	(24L*3600L)
X#define	YEAR	(365L*DAY)
X#define	NOW	(time ((time_t *) 0))
X
Xextern	struct	tm	*localtime ();
Xextern	char	*asctime ();
Xextern	void	failprint ();
X
X/*
X * failure - make failure entry
X */
X
Xvoid
Xfailure (uid, tty, faillog)
Xint	uid;
Xchar	*tty;
Xstruct	faillog	*faillog;
X{
X	int	fd;
X
X	if ((fd = open (FAILFILE, O_RDWR)) < 0)
X		return;
X
X	lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
X	if (read (fd, (char *) faillog, sizeof *faillog)
X			!= sizeof *faillog)
X#ifndef	BSD
X		memset ((void *) faillog, '\0', sizeof *faillog);
X#else
X		bzero ((char *) faillog, sizeof *faillog);
X#endif
X
X	if (faillog->fail_max == 0 || faillog->fail_cnt < faillog->fail_max)
X		faillog->fail_cnt++;
X
X	strncpy (faillog->fail_line, tty, sizeof faillog->fail_line);
X	faillog->fail_time = time ((time_t *) 0);
X
X	lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
X	write (fd, (char *) faillog, sizeof *faillog);
X	close (fd);
X}
X
X/*
X * failcheck - check for failures > allowable
X *
X * failcheck() is called AFTER the password has been validated.
X */
X
Xint
Xfailcheck (uid, faillog, failed)
Xint	uid;
Xstruct	faillog	*faillog;
X{
X	int	fd;
X	int	okay = 1;
X	struct	faillog	fail;
X
X	if ((fd = open (FAILFILE, O_RDWR)) < 0)
X		return (1);
X
X	lseek (fd, (off_t) (sizeof *faillog) * uid, 0);
X	if (read (fd, (char *) faillog, sizeof *faillog) == sizeof *faillog) {
X		if (faillog->fail_max != 0
X				&& faillog->fail_cnt >= faillog->fail_max)
X			okay = 0;
X	}
X	if (!failed && okay) {
X		fail = *faillog;
X		fail.fail_cnt = 0;
X
X		lseek (fd, (off_t) sizeof fail * uid, 0);
X		write (fd, (char *) &fail, sizeof fail);
X	}
X	close (fd);
X
X	return (okay);
X}
X
X/*
X * failprint - print line of failure information
X */
X
Xvoid
Xfailprint (uid, fail)
Xstruct	faillog	*fail;
X{
X	int	fd;
X	struct	tm	*tp;
X	char	*lasttime;
X
X	if (fail->fail_cnt == 0)
X		return;
X
X	tp = localtime (&fail->fail_time);
X	lasttime = asctime (tp);
X	lasttime[24] = '\0';
X
X	if (NOW - fail->fail_time < YEAR)
X		lasttime[19] = '\0';
X	if (NOW - fail->fail_time < DAY)
X		lasttime = lasttime + 11;
X
X	if (*lasttime == ' ')
X		lasttime++;
X
X	printf ("%d %s since last login.  Last was %s on %s.\n",
X		fail->fail_cnt, fail->fail_cnt > 1 ? "failures":"failure",
X		lasttime, fail->fail_line);
X}
X#endif
X
X#ifdef	FTMP
X
Xvoid
Xfailtmp (failent)
Xstruct	utmp	*failent;
X{
X	int	fd;
X
X	if ((fd = open (FTMP, O_WRONLY|O_APPEND)) == -1)
X		return;
X
X	write (fd, (char *) failent, sizeof *failent);
X	close (fd);
X}
X#endif
SHAR_EOF
if test 2948 -ne "`wc -c < 'failure.c'`"
then
	echo shar: "error transmitting 'failure.c'" '(should have been 2948 characters)'
fi
fi
echo shar: "extracting 'utmp.c'" '(1596 characters)'
if test -f 'utmp.c'
then
	echo shar: "will not over-write existing file 'utmp.c'"
else
sed 's/^X//' << \SHAR_EOF > 'utmp.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 <sys/types.h>
X#include <utmp.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include <stdio.h>
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)utmp.c	2.3	19:24:26	7/29/90";
X#endif
X
Xextern	struct	utmp	utent;
Xextern	char	name[];
X
Xstruct	utmp	*getutent ();
Xvoid	setutent ();
Xvoid	endutent ();
Xvoid	pututline ();
Xtime_t	time ();
X
Xvoid	checkutmp ()
X{
X	struct	utmp	*ut;
X#ifndef	NDEBUG
X	int	pid = getppid ();
X#else
X	int	pid = getpid ();
X#endif
X	setutent ();
X
X	while (ut = getutent ())
X		if (ut->ut_pid == pid)
X			break;
X
X	if (ut)
X		utent = *ut;
X
X	endutent ();
X
X	if (ut && utent.ut_pid == pid)
X		return;
X
X	puts ("No utmp entry.  You must exec \"login\" from the lowest level \"sh\"");
X	exit (1);
X}
X
Xvoid	setutmp ()
X{
X	FILE	*wtmp;
X	char	tty[sizeof utent.ut_line + 1];
X	char	*line;
X
X	setutent ();
X
X	(void) strncpy (utent.ut_user, name, sizeof utent.ut_user);
X
X	utent.ut_type = USER_PROCESS;
X
X	if (line = strrchr (utent.ut_line, '/')) {
X		(void) strcpy (tty, line + 1);
X#ifndef	BSD
X		(void) memset (utent.ut_line, '\0', sizeof utent.ut_line);
X#else
X		bzero (utent.ut_line, sizeof utent.ut_line);
X#endif
X		(void) strcpy (utent.ut_line, tty);
X	}
X	(void) time (&utent.ut_time);
X
X	pututline (&utent);
X	endutent ();
X
X	if ((wtmp = fopen (WTMP_FILE, "a+"))) {
X		fwrite (&utent, sizeof utent, 1, wtmp);
X		fclose (wtmp);
X	}
X}
SHAR_EOF
if test 1596 -ne "`wc -c < 'utmp.c'`"
then
	echo shar: "error transmitting 'utmp.c'" '(should have been 1596 characters)'
fi
fi
echo shar: "extracting 'shadow.c'" '(2147 characters)'
if test -f 'shadow.c'
then
	echo shar: "will not over-write existing file 'shadow.c'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.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 "shadow.h"
X#include <stdio.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)shadow.c	2.6.1.1	08:13:12	11/9/90";
X#endif
X
Xstatic	FILE	*shadow;
X#define	FIELDS	5
X
Xvoid	setspent ()
X{
X	if (shadow)
X		rewind (shadow);
X	else
X		shadow = fopen (SHADOW, "r");
X}
X
Xvoid	endspent ()
X{
X	if (shadow)
X		(void) fclose (shadow);
X
X	shadow = (FILE *) 0;
X}
X
Xstruct spwd *
Xsgetspent (string)
Xchar	*string;
X{
X	static	char	buf[BUFSIZ];
X	static	struct	spwd	spwd;
X	char	*fields[FIELDS];
X	char	*cp;
X	char	*cpp;
X	int	atoi ();
X	long	atol ();
X	int	i;
X
X	strncpy (buf, string, BUFSIZ-1);
X	buf[BUFSIZ-1] = '\0';
X
X	if (cp = strrchr (buf, '\n'))
X		*cp = '\0';
X
X	for (cp = buf, i = 0;*cp && i < FIELDS;i++) {
X		fields[i] = cp;
X		while (*cp && *cp != ':')
X			cp++;
X
X		if (*cp)
X			*cp++ = '\0';
X	}
X	if (*cp || i != FIELDS)
X		return 0;
X
X	spwd.sp_namp = fields[0];
X	spwd.sp_pwdp = fields[1];
X
X	if ((spwd.sp_lstchg = strtol (fields[2], &cpp, 10)) == 0 && *cpp)
X		return 0;
X
X	if ((spwd.sp_min = strtol (fields[3], &cpp, 10)) == 0 && *cpp)
X		return 0;
X
X	if ((spwd.sp_max = strtol (fields[4], &cpp, 10)) == 0 && *cpp)
X		return 0;
X
X	return (&spwd);
X}
X
Xstruct	spwd	*fgetspent (fp)
XFILE	*fp;
X{
X	char	buf[BUFSIZ];
X
X	if (! fp)
X		return (0);
X
X	if (fgets (buf, BUFSIZ, fp) == (char *) 0)
X		return (0);
X
X	return sgetspent (buf);
X}
X
Xstruct	spwd	*getspent ()
X{
X	if (! shadow)
X		setspent ();
X
X	return (fgetspent (shadow));
X}
X
Xstruct	spwd	*getspnam (name)
Xchar	*name;
X{
X	struct	spwd	*spwd;
X
X	setspent ();
X
X	while ((spwd = getspent ()) != (struct spwd *) 0) {
X		if (strcmp (name, spwd->sp_namp) == 0)
X			return (spwd);
X	}
X	return (0);
X}
X
Xint	putspent (spwd, fp)
Xstruct	spwd	*spwd;
XFILE	*fp;
X{
X	if (! fp)
X		return -1;
X
X	fprintf (fp, "%s:%s:%ld:%ld:%ld\n",
X			spwd->sp_namp, spwd->sp_pwdp,
X			spwd->sp_lstchg, spwd->sp_min, spwd->sp_max);
X
X	if (ferror (fp))
X		return -1;
X	else
X		return 0;
X}
SHAR_EOF
if test 2147 -ne "`wc -c < 'shadow.c'`"
then
	echo shar: "error transmitting 'shadow.c'" '(should have been 2147 characters)'
fi
fi
echo shar: "extracting 'log.c'" '(1353 characters)'
if test -f 'log.c'
then
	echo shar: "will not over-write existing file 'log.c'"
else
sed 's/^X//' << \SHAR_EOF > 'log.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 <sys/types.h>
X#include <utmp.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <time.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)log.c	2.2	19:23:53	7/29/90";
X#endif
X
X#ifdef	LASTLOG
X
X#include "lastlog.h"
X
Xextern	struct	utmp	utent;
Xextern	struct	passwd	pwent;
Xextern	struct	lastlog	lastlog;
Xextern	char	**environ;
X
Xlong	lseek ();
Xtime_t	time ();
X
Xvoid	log ()
X{
X	int	fd;
X	off_t	offset;
X	struct	lastlog	newlog;
X
X	if ((fd = open ("/usr/adm/lastlog", O_RDWR)) == -1)
X		return;
X
X	offset = pwent.pw_uid * sizeof lastlog;
X
X	if (lseek (fd, offset, 0) != offset) {
X		(void) close (fd);
X		return;
X	}
X	if (read (fd, (char *) &lastlog, sizeof lastlog) != sizeof lastlog)
X#ifndef	BSD
X		memset ((char *) &lastlog, sizeof lastlog, 0);
X#else
X		bzero ((char *) &lastlog, sizeof lastlog);
X#endif
X	newlog = lastlog;
X
X	(void) time (&newlog.ll_time);
X	(void) strncpy (newlog.ll_line, utent.ut_line, sizeof newlog.ll_line);
X	(void) lseek (fd, offset, 0);
X	(void) write (fd, (char *) &newlog, sizeof newlog);
X	(void) close (fd);
X}
X#endif
SHAR_EOF
if test 1353 -ne "`wc -c < 'log.c'`"
then
	echo shar: "error transmitting 'log.c'" '(should have been 1353 characters)'
fi
fi
echo shar: "extracting 'shadow.h'" '(879 characters)'
if test -f 'shadow.h'
then
	echo shar: "will not over-write existing file 'shadow.h'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.h'
X/*
X * Copyright 1988, 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/*
X * This information is not derived from AT&T licensed sources.  Posted
X * to the USENET 11/88.
X *
X *	@(#)shadow.h	2.3	16:34:15	11/2/90
X */
X
X/*
X * Shadow password security file structure.
X */
X
Xstruct	spwd {
X	char	*sp_namp;	/* login name */
X	char	*sp_pwdp;	/* encrypted password */
X	long	sp_lstchg;	/* date of last change */
X	long	sp_max;		/* maximum number of days between changes */
X	long	sp_min;		/* minimum number of days between changes */
X};
X
X/*
X * Shadow password security file functions.
X */
X
Xstruct	spwd	*getspent ();
Xstruct	spwd	*getspnam ();
Xstruct	spwd	*sgetspent ();
Xvoid	setspent ();
Xvoid	endspent ();
Xstruct	spwd	*fgetspent ();
Xint	putspent ();
X
X#define  SHADOW "/etc/shadow"
SHAR_EOF
if test 879 -ne "`wc -c < 'shadow.h'`"
then
	echo shar: "error transmitting 'shadow.h'" '(should have been 879 characters)'
fi
fi
echo shar: "extracting 'faillog.h'" '(715 characters)'
if test -f 'faillog.h'
then
	echo shar: "will not over-write existing file 'faillog.h'"
else
sed 's/^X//' << \SHAR_EOF > 'faillog.h'
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/*
X * faillog.h - login failure logging file format
X *
X *	@(#)faillog.h	2.2	19:23:46	7/29/90
X *
X * The login failure file is maintained by login(1) and fail(1L)
X * Each record in the file represents a separate UID and the file
X * is indexed in that fashion.
X */
X
X#define	FAILFILE	"/usr/adm/faillog"
X
Xstruct	faillog {
X	short	fail_cnt;	/* failures since last success */
X	short	fail_max;	/* failures before turning account off */
X	char	fail_line[12];	/* last failure occured here */
X	time_t	fail_time;	/* last failure occured then */
X};
SHAR_EOF
if test 715 -ne "`wc -c < 'faillog.h'`"
then
	echo shar: "error transmitting 'faillog.h'" '(should have been 715 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org

jfh@rpp386.cactus.org (John F Haugh II) (12/13/90)

#! /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:
#	gpmain.c
#	chage.c
#	pwent.c
#	valid.c
#	setup.c
#	entry.c
#	ttytype.c
#	port.h
#	grent.c
#	motd.c
#	dialup.h
# This archive created: Wed Dec 12 12:37:13 1990
# By:	John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'gpmain.c'" '(9373 characters)'
if test -f 'gpmain.c'
then
	echo shar: "will not over-write existing file 'gpmain.c'"
else
sed 's/^X//' << \SHAR_EOF > 'gpmain.c'
X/*
X * Copyright 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 <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <grp.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <errno.h>
X#ifndef	BSD
X#include <termio.h>
X#ifdef SYS3
X#include <sys/ioctl.h>
X#endif
X#include <string.h>
X#ifndef	SYS3
X#include <memory.h>
X#endif
X#else
X#include <sgtty.h>
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	PASSLENGTH
X#define	PASSLENGTH	5
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)gpmain.c	2.1	00:44:03	11/28/90";
X#endif
X
Xchar	name[BUFSIZ];
Xchar	pass[BUFSIZ];
Xchar	pass2[BUFSIZ];
X
Xstruct	group	grent;
X
Xchar	*myname;
Xchar	*user;
Xchar	*group;
Xint	aflg;
Xint	dflg;
Xint	rflg;
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
X/*
X * usage - display usage message
X */
X
Xvoid
Xusage ()
X{
X	fprintf (stderr, "usage: %s [ -r ] group\n", myname);
X	fprintf (stderr, "       %s [ -a user ] group\n", myname);
X	fprintf (stderr, "       %s [ -d user ] group\n", myname);
X	exit (1);
X}
X
Xchar **
Xadd_list (list, member)
Xchar	**list;
Xchar	*member;
X{
X	int	i;
X	int	found = 0;
X	char	**tmp;
X
X	for (i = 0;!found && list[i] != (char *) 0;i++)
X		if (strcmp (list[i], member) == 0)
X			found++;
X
X	tmp = (char **) malloc ((i + 2) * sizeof member);
X
X	for (i = 0;list[i] != (char *) 0;i++)
X		tmp[i] = list[i];
X
X	if (! found) {
X		tmp[i++] = strdup (member);
X		tmp[i] = (char *) 0;
X	}
X	return tmp;
X}
X
Xchar **
Xdel_list (list, member)
Xchar	**list;
Xchar	*member;
X{
X	int	i, j;
X	char	**tmp;
X
X	for (i = 0;list[i] != (char *) 0;i++)
X		;
X
X	tmp = (char **) malloc ((i + 1) * sizeof member);
X
X	for (j = i = 0;list[i] != (char *) 0;i++)
X		if (strcmp (list[i], member) == 0)
X			tmp[j++] = list[i];
X
X	tmp[j] = (char *) 0;
X
X	return tmp;
X}
X
Xint
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	extern	int	optind;
X	extern	char	*optarg;
X	int	flag;
X	int	i;
X	void	die ();
X	char	*cp;
X	char	*getlogin ();
X	int	amroot;
X	int	lockfd = -1;
X	int	retries;
X	int	ruid = getuid();
X	int	suid = geteuid();
X	long	salttime;
X	struct	group	*gr;
X	struct	group	*getgrnam ();
X	struct	group	*sgetgrent ();
X	struct	passwd	*pw;
X	struct	passwd	*getpwuid ();
X	struct	passwd	*getpwnam ();
X	FILE	*ngrp;
X	FILE	*ogrp;
X	char	buf[BUFSIZ];
X	char	tmp[BUFSIZ];
X
X	amroot = getuid () == 0;
X	setuid (geteuid ());
X	myname = argv[0];
X
X	if (! isatty (0) || ! isatty (1))
X		exit (1);
X
X	die (0);			/* save tty modes */
X
X	signal (SIGHUP, die);
X	signal (SIGINT, die);
X	signal (SIGQUIT, die);
X	signal (SIGTERM, die);
X
X	while ((flag = getopt (argc, argv, "a:d:gr")) != EOF) {
X		switch (flag) {
X			case 'a':	/* add a user */
X				aflg++;
X				user = optarg;
X				break;
X			case 'd':
X				dflg++;
X				user = optarg;
X				break;
X			case 'g':	/* no-op from normal password */
X				break;
X			case 'r':	/* remove group password */
X				rflg++;
X				break;
X			default:
X				usage ();
X		}
X	}
X	if (aflg + dflg + rflg > 1)
X		usage ();
X
X	if ((cp = getlogin ()) && (pw = getpwnam (cp)) && pw->pw_uid == ruid) {
X					/* need user name */
X		(void) strcpy (name, cp);
X	} else if (pw = getpwuid (ruid)) /* get it from password file */
X		strcpy (name, pw->pw_name);
X	else {				/* can't find user name! */
X		fprintf (stderr, "Who are you?\n");
X		exit (1);
X	}
X	if (! (pw = getpwnam (name)))
X		goto failure;		/* can't get my name ... */
X		
X	if (! (group = argv[optind]))
X		usage ();
X
X	if (! (gr = getgrnam (group))) {
X		fprintf (stderr, "unknown group: %s\n", group);
X		exit (1);
X	}
X	grent = *gr;
X	grent.gr_name = strdup (gr->gr_name);
X	grent.gr_passwd = strdup (gr->gr_passwd);
X
X	for (i = 0;gr->gr_mem[i];i++)
X		;
X	grent.gr_mem = (char **) malloc ((i + 1) * sizeof (char *));
X	for (i = 0;gr->gr_mem[i];i++)
X		grent.gr_mem[i] = strdup (gr->gr_mem[i]);
X	grent.gr_mem[i] = (char *) 0;
X
X	if (! amroot) {
X		if (gr->gr_mem[0] == (char *) 0)
X			goto failure;
X
X		if (strcmp (gr->gr_mem[0], name) != 0)
X			goto failure;
X	}
X	if (rflg) {
X		if (! amroot && (gr->gr_mem[0] &&
X				strcmp (name, gr->gr_mem[0]) != 0))
X			goto failure;
X
X		gr->gr_passwd = "";
X		goto output;
X	}
X	if (aflg) {
X		if (! amroot && (gr->gr_mem[0] == (char *) 0 ||
X				strcmp (name, gr->gr_mem[0]) != 0))
X			goto failure;
X
X		printf ("Adding user %s to group %s\n", user, group);
X		grent.gr_mem = add_list (gr->gr_mem, user);
X		goto output;
X	}
X	if (dflg) {
X		if (! amroot && (gr->gr_mem[0] == (char *) 0 ||
X				strcmp (name, gr->gr_mem[0]) != 0))
X			goto failure;
X
X		printf ("Removing user %s from group %s\n", user, group);
X		grent.gr_mem = del_list (gr->gr_mem, user);
X		goto output;
X	}
X	printf ("Changing password for group %s\n", group);
X
X	printf ("Enter new password (minimum of %d characters)\n", PASSLENGTH);
X	retries = RETRIES;
Xretry:
X	if (! password ("New Password:", pass))
X		exit (1);
X
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	(void) time (&salttime);
X	salttime = ((salttime & 07777) ^ ((salttime >> 12) & 07777)) & 07777;
X	grent.gr_passwd = tmp;
X	strcpy (grent.gr_passwd, crypt (pass, l64a (salttime)));
X#ifdef	DOUBLESIZE
X	if (strlen (pass) > 8) {
X		strcpy (grent.gr_passwd + 13,
X			crypt (pass + 8, l64a (salttime)) + 2);
X	}
X#endif
Xoutput:
X
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 (".grplock", O_RDONLY|O_CREAT|O_EXCL), 0444) == -1)
X#else
X	for (retries = 0;retries < 30;retries++) {
X		if ((lockfd = open (GRPLOCK, O_RDONLY|O_CREAT|O_EXCL, 0)) != -1)
X			break;
X
X		sleep (1);
X	}
X	if (lockfd == -1)
X#endif	/* NDEBUG */
X	{
X		puts ("Can't get lock");
X		exit (1);
X	}
X	umask (077);			/* close security holes to come ... */
X	if (access (NGRPFILE, 0) == 0 && unlink (NGRPFILE) == -1)
X		goto failure;
X
X#ifndef	NDEBUG
X	if ((ngrp = fopen ("ngroup", "w")) == (FILE *) 0)
X#else
X	umask (077);		/* no permissions for non-roots */
X
X	if ((ngrp = fopen (NGRPFILE, "w")) == (FILE *) 0)
X#endif	/* NDEBUG */
X		goto failure;
X
X#ifndef	NDEBUG
X	chmod (NGRPFILE, 0444);		/* lets have some security here ... */
X	chown (NGRPFILE, 0, 0);		/* ... and keep the bad guy away */
X#endif	/* NDEBUG */
X	if ((ogrp = fopen (GRPFILE, "r")) == (FILE *) 0)
X		goto failure;
X
X	while (fgets (buf, sizeof buf, ogrp) != (char *) 0) {
X		if (buf[0] == '#' || ! (gr = sgetgrent (buf))) {
X			fputs (buf, ngrp);
X		} else if (strcmp (gr->gr_name, group) != 0)
X			fputs (buf, ngrp);
X		else
X			break;
X	}
X	if (gr) {
X		(void) fprintf (ngrp, "%s:%s:%d:",
X			grent.gr_name, grent.gr_passwd ? grent.gr_passwd:"x",
X				grent.gr_gid);
X
X		for (i = 0;grent.gr_mem[i] != (char *) 0;i++) {
X			if (i)
X				fputc (',', ngrp);
X			fputs (grent.gr_mem[i], ngrp);
X		}
X		fputc ('\n', ngrp);
X	}
X	while (fgets (buf, BUFSIZ, ogrp) != (char *) 0)
X		fputs (buf, ngrp);
X
X	if (ferror (ngrp)) {
X		perror (NGRPFILE);
X		if (unlink (NGRPFILE) || unlink (GRPLOCK))
X			fputs ("Help!\n", stderr);
X
X		exit (1);
X	}
X	fflush (ngrp);
X	fclose (ngrp);
X#ifdef	NDEBUG
X	chmod (NGRPFILE, 0644);
X	if (unlink (OGRPFILE) == -1) {
X		if (errno != ENOENT) {
X			puts ("Can't unlink backup file");
X			goto unlock;
X		}
X	}
X	if (link (GRPFILE, OGRPFILE) || unlink (GRPFILE)) {
X		puts ("Can't save backup file");
X		goto unlock;
X	}
X#ifndef	BSD
X	if (link (NGRPFILE, GRPFILE) || unlink (NGRPFILE))
X#else
X	if (rename (NGRPFILE, GRPFILE))
X#endif
X	{
X		puts ("Can't rename new file");
X		goto unlock;
X	}
X#endif	/* NDEBUG */
X#ifndef	NDEBUG
X	(void) unlink (".grplock");
X#else
X	(void) unlink (GRPLOCK);
X#endif
X	exit (0);
X	/*NOTREACHED*/
X
Xfailure:
X	puts ("Permission denied.");
Xunlock:
X	if (lockfd >= 0)
X		(void) unlink (GRPLOCK);
X
X	(void) unlink (NGRPFILE);
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 9373 -ne "`wc -c < 'gpmain.c'`"
then
	echo shar: "error transmitting 'gpmain.c'" '(should have been 9373 characters)'
fi
fi
echo shar: "extracting 'chage.c'" '(10464 characters)'
if test -f 'chage.c'
then
	echo shar: "will not over-write existing file 'chage.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chage.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 <sys/types.h>
X#include <stdio.h>
X#include <pwd.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <errno.h>
X#include <ctype.h>
X#include <time.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifdef	SHADOWPWD
X#include "shadow.h"
X#endif
X#ifdef	DBM
X#include <dbm.h>
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)chage.c	2.3	08:59:07	11/5/90";
X#endif
X
Xchar	*myname;
X
Xtime_t	today;
Xchar	name[BUFSIZ];
Xchar	newage[10];
Xint	lflg;
Xint	mflg;
Xint	Mflg;
Xint	dflg;
X
Xstruct	passwd	pwent;
X#ifdef	SHADOWPWD
Xstruct	spwd	spwd;
X#endif
Xint	mindays;
Xint	maxdays;
Xlong	lastday;
X
Xextern	int	errno;
X
Xchar	Usage[] =
X"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -w week | -d day ] user\n";
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X	fprintf (stderr, Usage, myname);
X	exit (1);
X}
X
X/*
X * change_field - change a single field if a new value is given.
X *
X * prompt the user with the name of the field being changed and the
X * current value.
X */
X
Xvoid
Xchange_field (val, prompt)
Xint	*val;
Xchar	*prompt;
X{
X	int	newval;
X	char	new[BUFSIZ];
X	char	*cp;
X
X	while (1) {
X		if (*val == -1)
X			printf ("\t%s []: ", prompt);
X		else
X			printf ("\t%s [%d]: ", prompt, *val);
X
X		fgets (new, BUFSIZ, stdin);
X
X		if (cp = strchr (new, '\n'))
X			*cp = '\0';
X		else
X			return;
X
X		if (new[0] == '\0')
X			return;
X
X		newval = strtol (new, &cp, 10);
X		if (cp != new && newval >= -1 && newval <= 10000) {
X			*val = newval;
X			return;
X		}
X		fprintf (stderr, "%s: illegal value: %s\n", myname, new);
X	}
X}
X
X/*
X * new_fields - change the user's password aging information interactively.
X *
X * prompt the user for the two password age values.  set the fields
X * from the user's response, or leave alone if nothing was entered.
X */
X
Xnew_fields ()
X{
X	printf ("Enter the new value, or press return for the default\n\n");
X
X	change_field (&mindays, "Minimum Password Age");
X	change_field (&maxdays, "Maximum Password Age");
X	change_field (&lastday, "Last Password Change");
X}
X
X/*
X * list_fields - display the current values of the expiration fields
X *
X * display the mindays, maxdays, and lastday values.
X */
X
Xlist_fields ()
X{
X	struct	tm	*tp;
X	char	*cp;
X	long	changed;
X	long	expires;
X
X	changed = lastday * (24L*60L*60L);
X	expires = maxdays * (24L*60L*60L) + changed;
X
X	printf ("Minimum:\t%d\n", mindays);
X	printf ("Maximum:\t%d\n", maxdays);
X
X	printf ("Last Change:\t");
X	if (changed == 0) {
X		printf ("Never\n");
X	} else {
X		tp = localtime (&changed);
X		cp = asctime (tp);
X		printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X	}
X
X	printf ("Expires:\t");
X	if (expires == 0 || maxdays == 10000) {
X		printf ("Never\n");
X	} else {
X		tp = localtime (&expires);
X		cp = asctime (tp);
X		printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X	}
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	extern	int	optind;
X	extern	char	*optarg;
X	void	die ();
X	char	*cp;
X	char	*getlogin ();
X	int	amroot;
X	int	lockfd = -1;
X	int	flag;
X	struct	passwd	*pw;
X#ifdef	SHADOWPWD
X	struct	spwd	*sp;
X#endif
X	struct	passwd	*getpwuid ();
X	struct	passwd	*getpwnam ();
X	struct	passwd	*sgetpwent ();
X	FILE	*npwd;
X	FILE	*pwd;
X	char	buf[BUFSIZ];
X	char	tmp[BUFSIZ];
X
X	if (myname = strchr (argv[0], '/'))
X		myname++;
X	else
X		myname = argv[0];
X
X	if (getuid () != 0) {
X		fprintf (stderr, "%s: permission denied\n", myname);
X		exit (1);
X	}
X	while ((flag = getopt (argc, argv, "lm:M:d:w:")) != EOF) {
X		switch (flag) {
X			case 'l':
X				lflg++;
X				break;
X			case 'm':
X				mflg++;
X				mindays = strtol (optarg, 0, 10);
X				break;
X			case 'M':
X				Mflg++;
X				maxdays = strtol (optarg, 0, 10);
X				break;
X			case 'd':
X				dflg++;
X				lastday = strtol (optarg, 0, 10);
X				break;
X			case 'w':
X				dflg++;
X				lastday = strtol (optarg, 0, 10) * 7;
X				break;
X			default:
X				usage ();
X		}
X	}
X	if (argc != optind + 1)
X		usage ();
X
X	if (! (pw = getpwnam (argv[optind]))) {
X		fprintf (stderr, "%s: unknown user: %s\n",
X			myname, argv[optind]);
X		exit (1);
X	}
X	if (lflg && (mflg || Mflg || dflg)) {
X		fprintf (stderr, "%s: do not include \"l\" with other flags\n",
X			myname);
X		exit (1);
X	}
X	strcpy (name, pw->pw_name);
X#ifdef	SHADOWPWD
X	if (sp = getspnam (name)) {
X		spwd = *sp;
X		spwd.sp_namp = strdup (sp->sp_namp);
X		spwd.sp_pwdp = strdup (sp->sp_pwdp);
X	}
X#endif
X	pwent = *pw;
X	pwent.pw_name = strdup (pw->pw_name);
X	pwent.pw_passwd = strdup (pw->pw_passwd);
X	pwent.pw_age = strdup (pw->pw_age);
X	pwent.pw_gecos = strdup (pw->pw_gecos);
X	pwent.pw_dir = strdup (pw->pw_dir);
X	pwent.pw_shell = strdup (pw->pw_shell);
X
X	/*
X	 * Set the fields that aren't being set from the command line
X	 * from the password file.
X	 */
X
X#ifdef	SHADOWPWD
X	if (sp) {
X		if (! Mflg)
X			maxdays = spwd.sp_max;
X		if (! mflg)
X			mindays = spwd.sp_min;
X		if (! dflg)
X			lastday = spwd.sp_lstchg;
X	} else
X#endif
X	if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
X		if (! Mflg)
X			maxdays = c64i (pwent.pw_age[0]) * 7;
X		if (! mflg)
X			mindays = c64i (pwent.pw_age[1]) * 7;
X		if (! dflg && strlen (pwent.pw_age) == 4)
X			lastday = a64l (&pwent.pw_age[2]) * 7;
X	}
X
X	/*
X	 * Print out the expiration fields if the user has
X	 * requested the list option.
X	 */
X
X	if (lflg) {
X		list_fields ();
X		exit (0);
X	}
X
X	/*
X	 * If none of the fields were changed from the command line,
X	 * let the user interactively change them.
X	 */
X
X	if (! mflg && ! Mflg && ! dflg) {
X		printf ("Changing the aging information for %s\n", name);
X		new_fields ();
X	}
X
X	/*
X	 * Output the new password files.
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
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
X#ifdef	SHADOWPWD
X	if (sp) {
X		spwd.sp_min = mindays;
X		spwd.sp_max = maxdays;
X		spwd.sp_lstchg = lastday;
X
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 (sp = getspent ()) {
X			if (strcmp (sp->sp_namp, name) == 0)
X				break;
X
X			if (putspent (sp, npwd))
X				goto failure;
X		}
X		(void) putspent (&spwd, npwd);	/* add the new entry */
X
X		while (sp = getspent ())	/* finish the other ones off */
X			(void) putspent (sp, 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#ifndef	NDEBUG
X		(void) unlink (".pwdlock");
X#else
X		(void) unlink (PWDLOCK);
X#endif
X		exit (0);
X		/*NOTREACHED*/
X	}
X#endif
X	if (maxdays == -1 || mindays == -1 || lastday == -1) {
X		pwent.pw_age = "";
X	} else {
X		if (maxdays > (63*7))
X			maxdays = 63*7;
X		if (mindays > (63*7))
X			mindays = 63*7;
X
X		newage[0] = i64c (maxdays / 7);
X		newage[1] = i64c (mindays / 7);
X		strcpy (&newage[2], l64a (lastday / 7));
X		pwent.pw_age = newage;
X	}
X#ifdef	DBM
X	update_dbm (&pwent);
X#endif
X	if (access (NPWDFILE, 0) == 0 && unlink (NPWDFILE) == -1) {
X		perror (NPWDFILE);
X		exit (1);
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	{
X		perror (NPWDFILE);
X		exit (1);
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		perror (NPWDFILE);
X		exit (1);
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);
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#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}
SHAR_EOF
if test 10464 -ne "`wc -c < 'chage.c'`"
then
	echo shar: "error transmitting 'chage.c'" '(should have been 10464 characters)'
fi
fi
echo shar: "extracting 'pwent.c'" '(6808 characters)'
if test -f 'pwent.c'
then
	echo shar: "will not over-write existing file 'pwent.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwent.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 * Duplication is permitted for non-commercial [ profit making ]
X * purposes provided this and other copyright notices remain
X * intact.
X */
X
X#include <stdio.h>
X#include <pwd.h>
X#include <string.h>
X#include "config.h"
X
X#ifdef	DBM
X#include <dbm.h>
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)pwent.c	2.4	23:41:33	10/28/90";
X#endif
X
X#define	SBUFSIZ	64
X#define	NFIELDS	7
X
Xstatic	FILE	*pwdfp;
Xstatic	char	pwdbuf[BUFSIZ];
Xstatic	char	*pwdfile = "/etc/passwd";
X#ifdef	DBM
Xstatic	int	dbmopened;
Xstatic	int	dbmerror;
X#endif
Xstatic	char	*pwdfields[NFIELDS];
Xstatic	struct	passwd	pwent;
X
X/*
X * sgetpwent - convert a string to a (struct passwd)
X *
X * sgetpwent() parses a string into the parts required for a password
X * structure.  Strict checking is made for the UID and GID fields and
X * presence of the correct number of colons.  Any failing tests result
X * in a NULL pointer being returned.
X */
X
Xstruct	passwd	*sgetpwent (buf)
Xchar	*buf;
X{
X	int	i;
X	char	*cp;
X
X	/*
X	 * Copy the string to a static buffer so the pointers into
X	 * the password structure remain valid.
X	 */
X
X	strncpy (pwdbuf, buf, BUFSIZ);
X	pwdbuf[BUFSIZ-1] = '\0';
X
X	/*
X	 * Save a pointer to the start of each colon separated
X	 * field.  The fields are converted into NUL terminated strings.
X	 */
X
X	for (cp = pwdbuf, i = 0;i < NFIELDS && cp;i++) {
X		pwdfields[i] = cp;
X		if (cp = strchr (cp, ':'))
X			*cp++ = 0;
X	}
X
X	/*
X	 * There must be exactly NFIELDS colon separated fields or
X	 * the entry is invalid.  Also, the UID and GID must be non-blank.
X	 */
X
X	if (i != NFIELDS || *pwdfields[2] == '\0' || *pwdfields[3] == '\0')
X		return 0;
X
X	/*
X	 * Each of the fields is converted the appropriate data type
X	 * and the result assigned to the password structure.  If the
X	 * UID or GID does not convert to an integer value, a NULL
X	 * pointer is returned.
X	 */
X
X	pwent.pw_name = pwdfields[0];
X	pwent.pw_passwd = pwdfields[1];
X	if ((pwent.pw_uid = strtol (pwdfields[2], &cp, 10)) == 0 && *cp)
X		return 0;
X
X	if ((pwent.pw_gid = strtol (pwdfields[3], &cp, 10)) == 0 && *cp)
X		return 0;
X
X	if (cp = strchr (pwent.pw_passwd, ',')) {
X		pwent.pw_age = cp + 1;
X		*cp = '\0';
X	} else
X		pwent.pw_age = "";
X
X	pwent.pw_gecos = pwdfields[4];
X	pwent.pw_dir = pwdfields[5];
X	pwent.pw_shell = pwdfields[6];
X
X	return (&pwent);
X}
X#ifdef FGETPWENT
X/*
X * fgetpwent - get a password file entry from a stream
X *
X * fgetpwent() reads the next line from a password file formatted stream
X * and returns a pointer to the password structure for that line.
X */
X
Xstruct	passwd	*fgetpwent (fp)
XFILE	*fp;
X{
X	char	buf[BUFSIZ];
X
X	while (fgets (buf, BUFSIZ, fp) != (char *) 0) {
X		buf[strlen (buf) - 1] = '\0';
X		return (sgetpwent (buf));
X	}
X	return 0;
X}
X#endif
X#ifdef	GETPWENT
X
X/*
X * endpwent - close a password file
X *
X * endpwent() closes the password file if open.
X */
X
Xint	endpwent ()
X{
X	if (pwdfp)
X		if (fclose (pwdfp))
X			return -1;
X
X	return 0;
X}
X
X/*
X * getpwent - get a password entry from the password file
X *
X * getpwent() opens the password file, if not already opened, and reads
X * a single entry.  NULL is returned if any errors are encountered reading
X * the password file.
X */
X
Xstruct	passwd	*getpwent ()
X{
X	if (! pwdfp && setpwent ())
X		return 0;
X
X	return fgetpwent (pwdfp);
X}
X
X/*
X * getpwuid - locate the password entry for a given UID
X *
X * getpwuid() locates the first password file entry for the given UID.
X * If there is a valid DBM file, the DBM files are queried first for
X * the entry.  Otherwise, a linear search is begun of the password file
X * searching for an entry which matches the provided UID.
X */
X
Xstruct	passwd	*getpwuid (uid)
Xint	uid;
X{
X	struct	passwd	*pwd;
X#ifdef	DBM
X	datum	key;
X	datum	content;
X
X	/*
X	 * Attempt to open the DBM files if they have never been opened
X	 * and an error has never been returned.
X	 */
X
X	if (! dbmerror && ! dbmopened) {
X		char	dbmfiles[BUFSIZ];
X
X		strcpy (dbmfiles, pwdfile);
X		strcat (dbmfiles, ".pag");
X
X		if (access (dbmfiles, 0) || dbminit (pwdfile))
X			dbmerror = 1;
X		else
X			dbmopened = 1;
X	}
X
X	/*
X	 * If the DBM file are now open, create a key for this UID and
X	 * try to fetch the entry from the database.  A matching record
X	 * will be unpacked into a static structure and returned to
X	 * the user.
X	 */
X
X	if (dbmopened) {
X		pwent.pw_uid = uid;
X		key.dsize = sizeof pwent.pw_uid;
X		key.dptr = (char *) &pwent.pw_uid;
X		content = fetch (key);
X		if (content.dptr != 0) {
X			memcpy (pwdbuf, content.dptr, content.dsize);
X			pw_unpack (pwdbuf, content.dsize, &pwent);
X			return &pwent;
X		}
X	}
X#endif
X	/*
X	 * Rewind the database and begin searching for an entry which
X	 * matches the UID.  Return the entry when a match is found.
X	 */
X
X	if (setpwent ())
X		return 0;
X
X	while (pwd = getpwent ())
X		if (pwd->pw_uid == uid)
X			return pwd;
X
X	return 0;
X}
X
Xstruct	passwd	*getpwnam (name)
Xchar	*name;
X{
X	struct	passwd	*pwd;
X#ifdef	DBM
X	datum	key;
X	datum	content;
X
X	/*
X	 * Attempt to open the DBM files if they have never been opened
X	 * and an error has never been returned.
X	 */
X
X	if (! dbmerror && ! dbmopened) {
X		char	dbmfiles[BUFSIZ];
X
X		strcpy (dbmfiles, pwdfile);
X		strcat (dbmfiles, ".pag");
X
X		if (access (dbmfiles, 0) || dbminit (pwdfile))
X			dbmerror = 1;
X		else
X			dbmopened = 1;
X	}
X
X	/*
X	 * If the DBM file are now open, create a key for this UID and
X	 * try to fetch the entry from the database.  A matching record
X	 * will be unpacked into a static structure and returned to
X	 * the user.
X	 */
X
X	if (dbmopened) {
X		key.dsize = strlen (name);
X		key.dptr = name;
X		content = fetch (key);
X		if (content.dptr != 0) {
X			memcpy (pwdbuf, content.dptr, content.dsize);
X			pw_unpack (pwdbuf, content.dsize, &pwent);
X			return &pwent;
X		}
X	}
X#endif
X	/*
X	 * Rewind the database and begin searching for an entry which
X	 * matches the name.  Return the entry when a match is found.
X	 */
X
X	if (setpwent ())
X		return 0;
X
X	while (pwd = getpwent ())
X		if (strcmp (pwd->pw_name, name) == 0)
X			return pwd;
X
X	return 0;
X}
X
X/*
X * setpwent - open the password file
X *
X * setpwent() opens the system password file, and the DBM password files
X * if they are present.  The system password file is rewound if it was
X * open already.
X */
X
Xint	setpwent ()
X{
X	if (! pwdfp) {
X		if (! (pwdfp = fopen (pwdfile, "r")))
X			return -1;
X	} else {
X		if (fseek (pwdfp, 0L, 0) != 0)
X			return -1;
X	}
X#ifdef	DBM
X	/*
X	 * Attempt to open the DBM files if they have never been opened
X	 * and an error has never been returned.
X	 */
X
X	if (! dbmerror && ! dbmopened) {
X		char	dbmfiles[BUFSIZ];
X
X		strcpy (dbmfiles, pwdfile);
X		strcat (dbmfiles, ".pag");
X
X		if (access (dbmfiles, 0) || dbminit (pwdfile))
X			dbmerror = 1;
X		else
X			dbmopened = 1;
X	}
X#endif
X	return 0;
X}
X#endif
SHAR_EOF
if test 6808 -ne "`wc -c < 'pwent.c'`"
then
	echo shar: "error transmitting 'pwent.c'" '(should have been 6808 characters)'
fi
fi
echo shar: "extracting 'valid.c'" '(3190 characters)'
if test -f 'valid.c'
then
	echo shar: "will not over-write existing file 'valid.c'"
else
sed 's/^X//' << \SHAR_EOF > 'valid.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 <stdio.h>
X#include <pwd.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)valid.c	2.4	19:24:27	7/29/90";
X#endif
X
X/*
X * valid - compare encrypted passwords
X *
X *	Valid() compares the DES encrypted password from the password file
X *	against the password which the user has entered after it has been
X *	encrypted using the same salt as the original.
X */
X
Xint	valid (password, entry)
Xchar	*password;
Xstruct	passwd	*entry;
X{
X	char	*encrypt;
X	char	*salt;
X	char	*crypt ();
X	char	*shell;
X#ifdef	DOUBLESIZE
X	int	firsthalf;
X	int	longpass;
X#endif
X
X#ifdef	NOUSE
X	if (entry->pw_shell && strcmp (NOUSE, entry->pw_shell) == 0)
X		return (0);
X#if defined(SU) && defined (NOLOGIN)
X	if (entry->pw_shell && strcmp (NOLOGIN, entry->pw_shell) == 0) {
X		if (! (shell = getenv ("SHELL")))
X			return 0;
X	}
X#endif
X#if !defined(SU) && defined (NOLOGIN)
X	if (entry->pw_shell && strcmp (NOLOGIN, entry->pw_shell) == 0)
X		return 0;
X#endif
X#endif
X	/*
X	 * Start with blank or empty password entries.  Always encrypt
X	 * a password if no such user exists.  Only if the ID exists and
X	 * the password is really empty do you return quickly.  This
X	 * routine is meant to waste CPU time.
X	 */
X
X	if (entry->pw_name &&
X			(entry->pw_passwd == (char *) 0 ||
X			 strlen (entry->pw_passwd) == 0)) {
X		if (strlen (password) == 0)
X			return (1);	/* user entered nothing */
X		else
X			return (0);	/* user entered something! */
X	}
X
X#ifdef	DOUBLESIZE
X	longpass = entry->pw_passwd && strlen (entry->pw_passwd) > 13;
X#endif
X
X	/*
X	 * If there is no entry then we need a salt to use.
X	 */
X
X	if (entry->pw_passwd == (char *) 0 || entry->pw_passwd[0] == '\0')
X		salt = "xx";
X	else
X		salt = entry->pw_passwd;
X
X	/*
X	 * Now, perform the encryption using the salt from before on
X	 * the users input.  Since we always encrypt the string, it
X	 * should be very difficult to determine if the user exists by
X	 * looking at execution time.
X	 */
X
X	encrypt = crypt (password, salt);
X#ifdef	DOUBLESIZE
X	firsthalf = entry->pw_passwd
X		&& strncmp (encrypt + 2, entry->pw_passwd + 2, 11) == 0;
X
X	if (strlen (password) > 8)
X		encrypt = crypt (password + 8, salt);
X	else {
X		(void) crypt (password, salt);	/* waste time ... */
X		encrypt = "";
X	}
X#endif
X	/*
X	 * One last time we must deal with there being no password file
X	 * entry for the user.  We use the pw_passwd == NULL idiom to
X	 * cause non-existent users to not be validated.  Even still,
X	 * we are safe because if the string were == "", any encrypted
X	 * string is not going to match - the output of crypt() begins
X	 * with the salt, which is "xx", not "".
X	 */
X
X#ifndef	DOUBLESIZE
X	if (entry->pw_passwd && strcmp (encrypt, entry->pw_passwd) == 0)
X		return (1);
X	else
X		return (0);
X#else
X	if (! longpass)
X		return (firsthalf);
X
X	if (entry->pw_passwd && firsthalf
X			&& strncmp (encrypt + 2, entry->pw_passwd + 13) == 0)
X		return (1);
X	else
X		return (0);
X#endif
X}
SHAR_EOF
if test 3190 -ne "`wc -c < 'valid.c'`"
then
	echo shar: "error transmitting 'valid.c'" '(should have been 3190 characters)'
fi
fi
echo shar: "extracting 'setup.c'" '(2514 characters)'
if test -f 'setup.c'
then
	echo shar: "will not over-write existing file 'setup.c'"
else
sed 's/^X//' << \SHAR_EOF > 'setup.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 <sys/types.h>
X#include <pwd.h>
X#include <utmp.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)setup.c	2.2	19:24:10	7/29/90";
X#endif
X
Xextern	char	home[];
Xextern	char	prog[];
Xextern	char	name[];
Xextern	char	mail[];
X
X#ifndef	PATH
X#define	PATH	":/bin:/usr/bin"
X#endif
X
X#ifndef	SUPATH
X#define	SUPATH	":/bin:/usr/bin:/etc"
X#endif
X
X#ifndef	MAILDIR
X#define	MAILDIR	"/usr/spool/mail"
X#endif
X
X#ifndef	TTYPERM
X#define	TTYPERM	0622
X#endif
X
X#ifndef	SU
Xextern	struct	utmp	utent;
X#endif
X
X#ifdef	QUOTAS
Xlong	strtol ();
X#ifdef	ULIMIT
Xlong	ulimit ();
X#endif
X#endif
X
Xvoid	addenv ();
X
Xvoid	setup (info)
Xstruct	passwd	*info;
X{
X	extern	int	errno;
X	char	logname[30];
X#ifndef	SU
X	char	tty[30];
X#endif
X	char	*cp;
X	int	i;
X	long	l;
X
X#ifndef	SU
X	(void) strcat (strcpy (tty, "/dev/"), utent.ut_line);
X	if (chown (tty, info->pw_uid, info->pw_gid) ||
X					chmod (tty, TTYPERM))
X		perror (tty);
X#endif
X	if (chdir (info->pw_dir) == -1) {
X		(void) printf ("Unable to change directory to \"%s\"\n", info->pw_dir);
X		exit (errno);
X	}
X#ifdef	QUOTAS
X	for (cp = info->pw_gecos;cp != (char *) 0;cp = strchr (cp, ',')) {
X		if (*cp == ',')
X			cp++;
X
X		if (strncmp (cp, "pri=", 4) == 0) {
X			i = atoi (cp + 4);
X			if (i >= -20 && i <= 20)
X				(void) nice (i);
X
X			continue;
X		}
X#ifdef	ULIMIT
X		if (strncmp (cp, "ulimit=", 7) == 0) {
X			l = strtol (cp + 7, (char **) 0, 10);
X			(void) ulimit (2, l);
X
X			continue;
X		}
X#endif
X		if (strncmp (cp, "umask=", 6) == 0) {
X			i = strtol (cp + 6, (char **) 0, 8) & 0777;
X			(void) umask (i);
X
X			continue;
X		}
X	}
X#endif
X	if (setgid (info->pw_gid) == -1) {
X		puts ("Bad group id");
X		exit (errno);
X	}
X#ifndef	BSD
X	if (setuid (info->pw_uid))
X#else
X	if (setreuid (info->pw_uid, info->pw_uid))
X#endif
X	{
X		puts ("Bad user id");
X		exit (errno);
X	}
X	(void) strcat (strcpy (home, "HOME="), info->pw_dir);
X	addenv (home);
X
X	if (info->pw_shell == (char *) 0)
X		info->pw_shell = "/bin/sh";
X
X	(void) strcat (strcpy (prog, "SHELL="), info->pw_shell);
X	addenv (prog);
X
X	if (info->pw_uid == 0)
X		addenv (SUPATH);
X	else
X		addenv (PATH);
X
X	(void) strcat (strcpy (logname, "LOGNAME="), name);
X	addenv (logname);
X
X	(void) strcat (strcat (strcpy (mail, "MAIL="), MAILDIR), name);
X	addenv (mail);
X}
SHAR_EOF
if test 2514 -ne "`wc -c < 'setup.c'`"
then
	echo shar: "error transmitting 'setup.c'" '(should have been 2514 characters)'
fi
fi
echo shar: "extracting 'entry.c'" '(2353 characters)'
if test -f 'entry.c'
then
	echo shar: "will not over-write existing file 'entry.c'"
else
sed 's/^X//' << \SHAR_EOF > 'entry.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 <stdio.h>
X#include <pwd.h>
X#ifndef	BSD
X#include <string.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X#ifdef	SHADOWPWD
X#include "shadow.h"
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)entry.c	2.3	07:47:34	8/14/90";
X#endif
X
Xstruct	passwd	*fgetpwent ();
Xchar	*malloc ();
X
Xchar	*strdup (s)
Xchar	*s;
X{
X	char	*cp;
X
X	if (s == (char *) 0)
X		return ((char *) 0);
X
X	if (! (cp = malloc ((unsigned) strlen (s) + 1)))
X		return ((char *) 0);
X
X	return (strcpy (cp, s));
X}
X
Xvoid	entry (name, pwent)
Xchar	*name;
Xstruct	passwd	*pwent;
X{
X	FILE	*pwd;
X	struct	passwd	*passwd;
X#ifdef	SHADOWPWD
X	struct	spwd	*spwd;
X	char	*l64a ();
X#endif
X	char	*cp;
X
X	if ((pwd = fopen (PWDFILE, "r")) == (FILE *) 0) {
X		pwent->pw_passwd = (char *) 0;
X		return;
X	}
X	while (passwd = fgetpwent (pwd)) {
X		if (strcmp (name, passwd->pw_name) == 0)
X			break;
X	}
X	fclose (pwd);
X
X	if (passwd == (struct passwd *) 0) {
X		pwent->pw_name = (char *) 0;
X		pwent->pw_passwd = (char *) 0;
X	} else  {
X		pwent->pw_name = strdup (passwd->pw_name);
X		pwent->pw_uid = passwd->pw_uid;
X		pwent->pw_gid = passwd->pw_gid;
X		pwent->pw_comment = (char *) 0;
X		pwent->pw_gecos = strdup (passwd->pw_gecos);
X		pwent->pw_dir = strdup (passwd->pw_dir);
X		pwent->pw_shell = strdup (passwd->pw_shell);
X#ifdef	SHADOWPWD
X		setspent ();
X		if (spwd = getspnam (name)) {
X			pwent->pw_passwd = strdup (spwd->sp_pwdp);
X
X			pwent->pw_age = malloc (5);
X
X			if (spwd->sp_max > (63*7))
X				spwd->sp_max = (63*7);
X			if (spwd->sp_min > (63*7))
X				spwd->sp_min = (63*7);
X
X			pwent->pw_age[0] = i64c (spwd->sp_max / 7);
X			pwent->pw_age[1] = i64c (spwd->sp_min / 7);
X
X			cp = l64a (spwd->sp_lstchg / 7);
X			pwent->pw_age[2] = cp[0];
X			pwent->pw_age[3] = cp[1];
X
X			pwent->pw_age[4] = '\0';
X
X			endspent ();
X			return;
X		}
X		endspent ();
X		passwd->pw_age = pwent->pw_age = (char *) 0;
X#endif
X		if (passwd->pw_passwd)
X			pwent->pw_passwd = strdup (passwd->pw_passwd);
X		else
X			pwent->pw_passwd = (char *) 0;
X
X		if (passwd->pw_age) {
X			pwent->pw_age = malloc (5);	/* longest legal time */
X			(void) strncpy (pwent->pw_age, passwd->pw_age, 5);
X		} else
X			pwent->pw_age = (char *) 0;
X	}
X}
SHAR_EOF
if test 2353 -ne "`wc -c < 'entry.c'`"
then
	echo shar: "error transmitting 'entry.c'" '(should have been 2353 characters)'
fi
fi
echo shar: "extracting 'ttytype.c'" '(1125 characters)'
if test -f 'ttytype.c'
then
	echo shar: "will not over-write existing file 'ttytype.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ttytype.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 <stdio.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifdef	TTYTYPE
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)ttytype.c	2.2	19:24:24	7/29/90";
X#endif
X
X/*
X * ttytype - set ttytype from port to terminal type mapping database
X */
X
Xvoid	ttytype (line)
Xchar	*line;
X{
X	FILE	*fp;
X	char	buf[BUFSIZ];
X	char	termvar[BUFSIZ];
X	char	*cp;
X	char	*type;
X	char	*port;
X	char	*getenv ();
X
X	if (getenv ("TERM"))
X		return;
X
X	if (! (fp = fopen (TTYTYPE, "r")))
X		return;
X
X	while (fgets (buf, BUFSIZ, fp)) {
X		if (buf[0] == '#')
X			continue;
X
X		if (cp = strchr (buf, '\n'))
X			*cp = '\0';
X
X		if ((type = strtok (buf, " \t"))
X				&& (port = strtok ((char *) 0, " \t"))) {
X			if (strcmp (line, port) == 0)
X				break;
X		}
X	}
X	if (! feof (fp) && ! ferror (fp)) {
X		strcat (strcpy (termvar, "TERM="), type);
X		addenv (termvar);
X	}
X	fclose (fp);
X}
X#endif
SHAR_EOF
if test 1125 -ne "`wc -c < 'ttytype.c'`"
then
	echo shar: "error transmitting 'ttytype.c'" '(should have been 1125 characters)'
fi
fi
echo shar: "extracting 'port.h'" '(1459 characters)'
if test -f 'port.h'
then
	echo shar: "will not over-write existing file 'port.h'"
else
sed 's/^X//' << \SHAR_EOF > 'port.h'
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
X/*
X * port.h - structure of /etc/porttime
X *
X *	@(#)port.h	1.3	08:26:37	8/20/90
X *
X *	Each entry in /etc/porttime consists of a TTY device
X *	name or "*" to indicate all TTY devices, followed by
X *	a list of 1 or more user IDs or "*" to indicate all
X *	user names, followed by a list of zero or more valid
X *	login times.  Login time entries consist of zero or
X *	more day names (Su, Mo, Tu, We, Th, Fr, Sa, Wk, Al)
X *	followed by a pair of time values in HHMM format
X *	separated by a "-".
X */
X
X/*
X * PORTS - Name of system port access time file.
X * PORT_IDS - Allowable number of IDs per entry.
X * PORT_TIMES - Allowable number of time entries per entry.
X * PORT_DAY - Day of the week to a bit value (0 = Sunday).
X */
X
X#define	PORTS	"/etc/porttime"
X#define	PORT_IDS	64
X#define	PORT_TIMES	24
X#define	PORT_DAY(day)	(1<<(day))
X
X/*
X *	pt_name - pointer to device name in /dev/
X *	pt_users - pointer to array of applicable user IDs.
X *	pt_times - pointer to list of allowable time periods.
X */
X
Xstruct	port	{
X	char	*pt_name;
X	char	**pt_users;
X	struct	pt_time	*pt_times;
X};
X
X/*
X *	t_days - bit array for each day of the week (0 = Sunday)
X *	t_start - starting time for this entry
X *	t_end - ending time for this entry
X */
X
Xstruct	pt_time	{
X	short	t_days;
X	short	t_start;
X	short	t_end;
X};
SHAR_EOF
if test 1459 -ne "`wc -c < 'port.h'`"
then
	echo shar: "error transmitting 'port.h'" '(should have been 1459 characters)'
fi
fi
echo shar: "extracting 'grent.c'" '(1297 characters)'
if test -f 'grent.c'
then
	echo shar: "will not over-write existing file 'grent.c'"
else
sed 's/^X//' << \SHAR_EOF > 'grent.c'
X/*
X * Copyright 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 <stdio.h>
X#include <grp.h>
X#include <string.h>
X#include "config.h"
X#ifdef	DBM
X#include <dbm.h>
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)grent.c	1.1	08:14:07	6/20/90";
X#endif
X
X#define	NFIELDS	4
X#define	MAXMEM	1024
X
Xstatic	char	grpbuf[4*BUFSIZ];
Xstatic	char	*grpfields[NFIELDS];
Xstatic	char	*members[MAXMEM+1];
X
Xstatic char **
Xlist (s)
Xchar	*s;
X{
X	int	nmembers = 0;
X
X	while (*s) {
X		members[nmembers++] = s;
X		if (s = strchr (s, ','))
X			*s++ = '\0';
X	}
X	members[nmembers] = (char *) 0;
X	return members;
X}
X
Xstruct	group	*sgetgrent (buf)
Xchar	*buf;
X{
X	int	i;
X	char	*cp;
X	static	struct	group	grent;
X
X	strncpy (grpbuf, buf, sizeof grpbuf);
X	grpbuf[sizeof grpbuf - 1] = '\0';
X	if (cp = strrchr (grpbuf, '\n'))
X		*cp = '\0';
X
X	for (cp = grpbuf, i = 0;i < NFIELDS && cp;i++) {
X		grpfields[i] = cp;
X		if (cp = strchr (cp, ':'))
X			*cp++ = 0;
X	}
X	if (i < (NFIELDS-1) || *grpfields[2] == '\0')
X		return ((struct group *) 0);
X
X	grent.gr_name = grpfields[0];
X	grent.gr_passwd = grpfields[1];
X	grent.gr_gid = atoi (grpfields[2]);
X	grent.gr_mem = list (grpfields[3]);
X
X	return (&grent);
X}
SHAR_EOF
if test 1297 -ne "`wc -c < 'grent.c'`"
then
	echo shar: "error transmitting 'grent.c'" '(should have been 1297 characters)'
fi
fi
echo shar: "extracting 'motd.c'" '(750 characters)'
if test -f 'motd.c'
then
	echo shar: "will not over-write existing file 'motd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'motd.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 <stdio.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)motd.c	2.2	19:23:58	7/29/90";
X#endif
X
Xextern	char	home[];
X#ifdef	HUSHLOGIN
Xextern	int	hushed;
X#endif
X
X#ifdef	MOTD
Xvoid	motd ()
X{
X	FILE	*fp;
X	register int	c;
X
X#ifdef	HUSHLOGIN
X	if (hushed)
X		return;
X#endif
X	if ((fp = fopen ("/etc/motd", "r")) == (FILE *) 0)
X		return;
X
X	while ((c = getc (fp)) != EOF)
X		putchar (c);
X
X	fclose (fp);
X	fflush (stdout);
X}
X#endif
SHAR_EOF
if test 750 -ne "`wc -c < 'motd.c'`"
then
	echo shar: "error transmitting 'motd.c'" '(should have been 750 characters)'
fi
fi
echo shar: "extracting 'dialup.h'" '(928 characters)'
if test -f 'dialup.h'
then
	echo shar: "will not over-write existing file 'dialup.h'"
else
sed 's/^X//' << \SHAR_EOF > 'dialup.h'
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/*
X * Structure of d_passwd file
X *
X *	The d_passwd file contains the names of login shells which require
X *	dialup passwords.  Each line contains the fully qualified path name
X *	for the shell, followed by an optional password.  Each field is
X *	separated by a ':'.
X *
X * Structure of the dialups file
X *
X *	The dialups file contains the names of ports which may be dialup
X *	lines.  Each line consists of the last component of the path
X *	name.  Any leading directory names are removed.
X *
X *	@(#)dialup.h	2.2	19:23:40	7/29/90
X */
X
Xstruct	dialup {
X	char	*du_shell;
X	char	*du_passwd;
X};
X
Xvoid	setduent ();
Xvoid	endduent ();
Xstruct	dialup	*getduent ();
Xstruct	dialup	*getdushell ();
X
X#define	DIALPWD	"/etc/d_passwd"
X#define	DIALUPS	"/etc/dialups"
SHAR_EOF
if test 928 -ne "`wc -c < 'dialup.h'`"
then
	echo shar: "error transmitting 'dialup.h'" '(should have been 928 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org

jfh@rpp386.cactus.org (John F Haugh II) (12/13/90)

#! /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:
#	chage.1
#	chfn.1
#	chsh.1
#	login.1
#	passwd.1
#	su.1
#	shadow.3
#	faillog.4
#	passwd.4
#	porttime.4
#	shadow.4
#	faillog.8
#	pwconv.8
#	pwunconv.8
#	sulogin.8
# This archive created: Wed Dec 12 12:37:26 1990
# By:	John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'chage.1'" '(1879 characters)'
if test -f 'chage.1'
then
	echo shar: "will not over-write existing file 'chage.1'"
else
sed 's/^X//' << \SHAR_EOF > 'chage.1'
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.\"	@(#)chage.1	2.1.1.1	09:07:05	11/26/90
X.\"
X.TH CHAGE 1
X.SH NAME
Xchage \- change user password expirate information
X.SH SYNOPSIS
X\fBchage\fR [ \fB-m \fImindays\fR ] [ \fB-M \fImaxdays\fR ] [ \fB-d \fIlastday\fR ] \fIuser\fR
X.SH DESCRIPTION
X\fIchage\f changes the number of days between password changes and the
Xdate of the last password change.
XThis information is used by the system to determine when a user must
Xchange their password.
XThe \fIchage\f command is restricted to the root user.
X.PP
XThe value of \fImindays\f is the minimum number of days between
Xpassword changes.
XA value of zero for this field indicates that the user may change
Xher password at any time.
X.PP
XThe value of \fImaxdays\f is the maximum number of days during
Xwhich a password is valid.
XWhen \fImaxdays\f plus \fIlastday\f is less than the current day,
Xthe user will be required to change her password before being
Xable to use her account.
X.PP
XThe value of \fIlastday\f is the number of days since January 1st,
X1970 when the password was last changed.
X.PP
XAll of the above values are stored exactly as days when the shadow
Xpassword file is used, but are converted to and from weeks when the
Xstandard password file is used.
XBecause of this conversion, rounding errors may result.
X.PP
XIf none of the options are selected, \fIchage\f operates in an interactive
Xfashion, prompting the user with the current values for all of the fields.
XEnter the new value to change the field, or leave the line blank to use
Xthe current value.
XThe current value is displayed between a pair of \fB[ ]\f marks.
X.SH Files
X/etc/passwd \- user account information
X.br
X/etc/shadow \- shadow user account information
X.SH See Also
Xpasswd(4),
Xshadow(4)
SHAR_EOF
if test 1879 -ne "`wc -c < 'chage.1'`"
then
	echo shar: "error transmitting 'chage.1'" '(should have been 1879 characters)'
fi
fi
echo shar: "extracting 'chfn.1'" '(1602 characters)'
if test -f 'chfn.1'
then
	echo shar: "will not over-write existing file 'chfn.1'"
else
sed 's/^X//' << \SHAR_EOF > 'chfn.1'
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.\"	@(#)chfn.1	2.1.1.1	09:07:07	11/26/90
X.\"
X.TH CHFN 1
X.SH NAME
Xchfn \- change user name and information
X.SH SYNOPSIS
X\fBchfn\fR [ \fB-f \fIfull_name\fR ] [ \fB-r \fIroom_no\fR ]
X.br
X[ \fB-w \fIwork_ph\fR ] [ \fB-h \fIhome_ph\fR ] [ \fB-o \fIother\fR ]
X[ \fIuser\fR ]
X.SH DESCRIPTION
X\fIchfn\f changes user fullname, office number, office extension, and home
Xphone number information for a user's account. 
XThis information is typically printed by \fIfinger(1)\f and similiar
Xprograms.
XA normal user may only change the fields for their own account,
Xthe super user may change the fields for any account.
XAlso, only the super user may use the \fB-o\f option to change the
Xundefined portions of the GCOS field.
X.PP
XThe only restrictions placed on the contents of the fields is that no
Xcontrol characters may be present, nor any of comma, colon, or equal sign.
XThe \fIother\f field does not have this restriction, and is used to
Xstore accounting information used by other applications.
X.PP
XIf none of the options are selected, \fIchfn\f operates in an interactive
Xfashion, prompting the user with the current values for all of the fields.
XEnter the new value to change the field, or leave the line blank to use
Xthe current value.
XThe current value is displayed between a pair of \fB[ ]\f marks.
XWithout options, chfn prompts for the current user account.
X.SH Files
X/etc/passwd \- user account information
X.SH See Also
Xpasswd(4)
SHAR_EOF
if test 1602 -ne "`wc -c < 'chfn.1'`"
then
	echo shar: "error transmitting 'chfn.1'" '(should have been 1602 characters)'
fi
fi
echo shar: "extracting 'chsh.1'" '(1479 characters)'
if test -f 'chsh.1'
then
	echo shar: "will not over-write existing file 'chsh.1'"
else
sed 's/^X//' << \SHAR_EOF > 'chsh.1'
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.\"	@(#)chsh.1	1.1.1.1	09:07:08	11/26/90
X.\"
X.TH CHSH 1
X.SH NAME
Xchsh \- change login shell
X.SH SYNOPSIS
X\fBchsh\fR [ \fB-s \fIlogin_shell\fR ] [ \fIuser\fR ]
X.SH DESCRIPTION
X\fIchsh\f changes the user login shell.
XThis determines the name of the user's initial login command.
XA normal user may only change the login shell for their own account,
Xthe super user may change the login shell for any account.
X.PP
XThe only restrictions placed on the login shell is that the
Xcommand name must be listed in \fB/etc/shells\fR, unless the
Xinvoker is the super-user, and then any value may be added.
XAn account with a restricted login shell may not change
Xtheir login shell.
XFor this reason, placing \fB/bin/rsh\fR in \fB/etc/shells\fR
Xis discouraged since accidentally changing to a restricted
Xshell would prevent the user from every changing their login
Xshell back to its original value.
X.PP
XIf the \fB-s\fR option is not selected, \fIchsh\f operates in an interactive
Xfashion, prompting the user with the current login shell.
XEnter the new value to change the field, or leave the line blank to use
Xthe current value.
XThe current value is displayed between a pair of \fB[ ]\f marks.
X.SH Files
X/etc/passwd \- user account information
X.br
X/etc/shells \- list of valid login shells
X.SH See Also
Xchfn(1),
Xpasswd(4)
SHAR_EOF
if test 1479 -ne "`wc -c < 'chsh.1'`"
then
	echo shar: "error transmitting 'chsh.1'" '(should have been 1479 characters)'
fi
fi
echo shar: "extracting 'login.1'" '(3348 characters)'
if test -f 'login.1'
then
	echo shar: "will not over-write existing file 'login.1'"
else
sed 's/^X//' << \SHAR_EOF > 'login.1'
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.\"	@(#)login.1	2.1.1.1	09:07:10	11/26/90
X.\"
X.TH LOGIN 1
X.SH NAME
Xlogin \- Begin session on the system
X.SH SYNOPSIS
X.B login
X[ username [ environmental-variables ] ]
X.SH DESCRIPTION
X.I login
Xis used to establish a new session with the system.
XIt is normally invoked automatically by responding to the
X.B login:
Xprompt on the user\'s terminal.
X.I login
Xmay be special to the shell and may not be invoked as a sub-process.
XTypically,
X.I login
Xis treated by the shell as \fBexec login\fR which causes the user
Xto exit from the current shell.
XAttempting to execute \fIlogin\fR from any shell but the login shell
Xwill produce an error message.
X.PP
XWhen invoked from the \fBlogin:\fR prompt, the user may enter
Xenvironmental variables after the username.
XThese variables are entered in the form \fBNAME=VALUE\fR.
XNot all variables may be set in the fashion, notably \fBPATH\fR,
X\fBHOME\fR and \fBSHELL\fR.
XAdditionally, \fBIFS\fR may be inhibited if the user\'s login
Xshell is \fB/bin/sh\fR.
X.PP
XThe user is then prompted for a password, where appropriate.
XEchoing is disabled to prevent revealing the password.
XOnly a small number of password failures are permitted before
X\fIlogin\fR exits and the communications link is severed.
X.PP
XIf password aging has been enabled for your account, you may be
Xprompted for a new password before proceeding.
XYou will be forced to provide your old password and the new
Xpassword before continuing.
XPlease refer to \fIpasswd(1)\fR for more information.
X.PP
XAfter a successful login,
Xyou will be informed of any system messages and the presence
Xof mail.
XYou may turn off the printing of the system message file,
X\fI/etc/motd\fR, by creating a zero-length file \fI.hushlogin\fR
Xin your login directory.
XThe mail message will be one of "\fIYou have new mail.\fR",
X"\fIYou have mail.\fR", or "\fINo Mail.\fR" according to
Xthe condition of your mailbox.
X.PP
XYour user and group ID will be set according to their values in
Xthe \fI/etc/passwd\fR file.
XThe value for \fB$HOME\fR, \fB$SHELL\fR, \fB$PATH\fR, \fB$LOGNAME\fR,
Xand \fB$MAIL\fR are set according to the appropriate fields in the
Xpassword entry.
XUlimit, umask and nice values may also be set according to
Xentries in the GECOS field.
X.PP
XOn some installations, the environmental variable \fB$TERM\fR will be
Xinitialize to the terminal type on your tty line, as specified in
X\fI/etc/ttytype\fR.
X.PP
XAn initialization script for your command interpreter may also be
Xexecuted.
XPlease see the appropriate manual section for more information on
Xthis function.
X.SH CAVEATS
X.PP
XThis version of \fIlogin\fR has many compilation options, only some of which
Xmay be in use at any particular site.
X.SH Files
X/etc/utmp \- list of current login sessions
X.br
X/etc/wtmp \- list of previous login sessions
X.br
X/etc/passwd \- user account information
X.br
X/etc/shadow \- encrypted passwords and age information
X.br
X/etc/motd \- system message file
X.br
X/etc/ttytype \- list of terminal types
X.br
X$HOME/.profile \- initialization script for default shell
X.br
X$HOME/.hushlogin \- suppress printing of system messages
X.br
X.SH See Also
X.PP
Xgetty(1M),
Xmail(1),
Xpasswd(1),
Xsh(1),
Xsu(1),
Xd_passwd(4),
Xpasswd(4)
SHAR_EOF
if test 3348 -ne "`wc -c < 'login.1'`"
then
	echo shar: "error transmitting 'login.1'" '(should have been 3348 characters)'
fi
fi
echo shar: "extracting 'passwd.1'" '(4120 characters)'
if test -f 'passwd.1'
then
	echo shar: "will not over-write existing file 'passwd.1'"
else
sed 's/^X//' << \SHAR_EOF > 'passwd.1'
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.\"	@(#)passwd.1	2.2.1.1	09:07:11	11/26/90
X.\"
X.TH PASSWD 1
X.SH NAME
Xpasswd \- change user password
X.SH SYNOPSIS
X\fBpasswd\fR [ \fB-f\fR ] [ \fIname\fR ]
X.br
X\fBpasswd\fR [ \fB-g\fR ] [ \fB-r\fR ] \fIgroup\fR
X.SH DESCRIPTION
X\fIpasswd\f changes passwords for user accounts.
XA normal user may only change the password for their own account,
Xthe super user may change the password for any account.
X.PP
XThe user is first prompted for their old password,
Xif one is present.
XThis password is then encrypted and compared against the
Xstored password.
XThe user has only one chance to enter the correct password.
XThe super user is permitted to bypass this step so that forgotten
Xpasswords may be changed.
X.PP
XAfter the password has been entered password aging information
Xis checked to see if the user is permitted to change their password
Xat this time.
XIf not, \fIpasswd\fR refuses to change the password and exits.
X.PP
XThe user is then prompted for a replacement password.
XThis password is tested for complexity.
XAs a general guideline,
Xpasswords should consist of 6 to 8 characters including
Xone or more from each of following sets:
X.IP "" .5i
XLower case alphabetics
X.IP "" .5i
XUpper case alphabetics
X.IP "" .5i
XDigits 0 thru 9
X.IP "" .5i
XPunctuation marks
X.PP
XCare must be taken not to include the system default erase
Xor kill characters.
X\fIpasswd\fR will reject any password which is not suitably
Xcomplex.
X.PP
XIf the password is accepted,
X\fIpasswd\fR will prompt again and compare the second entry
Xagainst the first.
XBoth entries are require to match in order for the password
Xto be changed.
X.PP
XWhen the \fB-g\f option is used, the password for the named
Xgroup is changed.
XThe user must either be the super user, or the first group
Xmember listed for the named group.
XThe current group password is not prompted for.
XThe \fB-r\f option is used with the \fB-g\f option to remove
Xthe current password from the named group.
X.SH Hints for user passwords
XThe security of a password depends upon the strength of the
Xencryption algorithm and the size of the key space.
XThe \fB\s-2UNIX\s+2\fR System encryption method is based on
Xthe NBS DES algorithm and is very secure.
XThe size of the key space depends upon the randomness of the
Xpassword which is selected.
X.PP
XCompromises in password security normally result from careless
Xpassword selection or handling.
XFor this reason, you should select a password which does not
Xappear in a dictionary or which must be written down.
XThe password should also not be a proper name, your license
Xnumber, birth date, or street address.
XAny of these may be used as guesses to violate system security.
X.PP
XYour password must easily remembered so that you will not
Xbe forced to write it on a piece of paper.
XThis can be accomplished by appending two small words together
Xand separating each with a special character or digit.
XFor example, Pass%word.
X.PP
XOther methods of construction involve selecting an easily
Xremembered phrase from literature and selecting the first
Xor last letter from each.
XAn example of this is
X.IP "" .5i
XAsk not for whom the bell tolls.
X.PP
Xwhich produces
X.IP "" .5i
XAn4wtbt.
X.PP
XYou may be reasonably sure few crackers will have
Xincluded this in their dictionary.
X.SH Notes about group passwords
XGroup passwords are an inherent security problem since more
Xthan one person is permitted to know the password.
XHowever, groups are a useful tool for permitting co-operation
Xbetween different users.
X.SH CAVEATS
XNot all options may be supported.
XPassword complexity checking may vary from site to site.
XThe user is urged to select as complex a password as they
Xfeel comfortable with.
XA \fB-f\fR option exists to permit the superuser to override
Xany password complexity testing;
Xnormal users must create passwords which pass the complexity
Xtest.
X.SH Files
X/etc/passwd \- user account information
X.br
X/etc/shadow \- encrypted user passwords
X.SH See Also
Xpasswd(3),
Xshadow(3),
Xgroup(4),
Xpasswd(4)
SHAR_EOF
if test 4120 -ne "`wc -c < 'passwd.1'`"
then
	echo shar: "error transmitting 'passwd.1'" '(should have been 4120 characters)'
fi
fi
echo shar: "extracting 'su.1'" '(1701 characters)'
if test -f 'su.1'
then
	echo shar: "will not over-write existing file 'su.1'"
else
sed 's/^X//' << \SHAR_EOF > 'su.1'
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.\"	@(#)su.1	2.1.1.1	09:07:13	11/26/90
X.\"
X.TH SU 1
X.SH NAME
Xsu \- Change user ID or become super-user
X.SH SYNOPSIS
X.B su
X[ - ] [ username [ args ] ]
X.SH DESCRIPTION
X.I su
Xis used to become another user during a login session.
XInvoked without a username, \fIsu\fR defaults to becoming
Xthe super user.
XThe optional argument \fB\-\fR may be used to provide an
Xenvironment similiar to what the user would expect had
Xthe user logged in directly.
X.PP
XAdditional arguments may be provided after the username,
Xin which case they are supplied to the user\'s login shell.
XIn particular, an argument of \fB-c\fR will cause the
Xnext argument to be treated as a command by most command
Xinterpreters.
XThe command will be executed under the shell specified by
X\fB$SHELL\fR, or if undefined, by the one specified in
X\fI/etc/passwd\fR.
X.PP
XThe user will be prompted for a password, if appropriate.
XInvalid passwords will produce an error message.
XAll attempts, both valid and invalid, are logged to detect
Xabuses of the system.
X.PP
XThe current environment is passed to the new shell.
XThe value of \fB$PATH\fR is reset to \fB/bin:/usr/bin\fR
Xfor normal users, or \fB/bin:/usr/bin:/etc\fR for the super user.
X.SH CAVEATS
X.PP
XThis version of \fIsu\fR has many compilation options, only some of which
Xmay be in use at any particular site.
X.SH Files
X/etc/passwd \- user account information
X.br
X/etc/shadow \- encrypted passwords and age information
X.br
X$HOME/.profile \- initialization script for default shell
X.SH See Also
Xlogin(1),
Xsh(1)
SHAR_EOF
if test 1701 -ne "`wc -c < 'su.1'`"
then
	echo shar: "error transmitting 'su.1'" '(should have been 1701 characters)'
fi
fi
echo shar: "extracting 'shadow.3'" '(2117 characters)'
if test -f 'shadow.3'
then
	echo shar: "will not over-write existing file 'shadow.3'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.3'
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.\"	@(#)shadow.3	2.1.1.1	09:07:15	11/26/90
X.\"
X.TH SHADOW 3
X.SH NAME
Xshadow \- encrypted password file routines
X.SH Syntax
X.IP "" .5i
X#include <shadow.h>
X.IP "" .5i
Xstruct spwd *getspent();
X.br
Xstruct spwd *getspnam(char * name);
X.br
Xvoid setspent();
X.br
Xvoid endspent();
X.br
Xstruct spwd *fgetspent(FILE *fp);
X.br
Xint putspent(struct spwd *p,FILE *fp);
X.SH DESCRIPTION
X.I shadow
Xmanipulates the contents of the shadow password file,
X\fB/etc/shadow\fR.
XThe structure in the \fI#include\fR file is
X.IP "" .5i
Xstruct spwd {
X.br
X	char	*sp_namp; /* user login name */
X.br
X	char	*sp_pwdp; /* encrypted password */
X.br
X	long	sp_lstchg; /* last password change */
X.br
X	int	sp_max; /* days before change required */
X.br
X	int	sp_min; /* days until change allowed. */
X.br
X}
X.PP
XThe meanings of each field are
X.IP "" .5i
Xsp_namp \- pointer to null-terminated user name.
X.IP "" .5i
Xsp_pwdp \- pointer to null-terminated password.
X.IP "" .5i
Xsp_lstchg \- days since Jan 1, 1970 password was last changed.
X.IP "" .5i
Xsp_max \- days after which password must be changed
X.IP "" .5i
Xsp_min \- days before which password may not be changed.
X.SH Description
X\fIgetspent\fR, \fIgetspname\fR, and \fIfgetspent\fR each return
Xa pointer to a \fBstruct spent\fR.
X\fIgetspent\fR returns the
Xnext entry from the file, and \fIfgetspent\fR returns the next
Xentry from the given stream, which is assumed to be a file of
Xthe proper format.
X\fIgetspnam\fR searches from the current position in the file for
Xan entry matching \fIname\fR.
X.PP
X\fIsetspent\fR and \fIendspent\fR may be used to begin and end,
Xrespectively, access to the shadow password file.
X.SH Diagnostics
XRoutines return NULL if no more entries are available or if an
Xerror occurs during processing.
X.SH Caveats
XThese routines may only be used by the super user as access to
Xthe shadow password file is restricted.
X.SH Files
X/etc/shadow \- encrypted user passwords
X.SH See Also
Xgetpwent(3),
Xshadow(4)
SHAR_EOF
if test 2117 -ne "`wc -c < 'shadow.3'`"
then
	echo shar: "error transmitting 'shadow.3'" '(should have been 2117 characters)'
fi
fi
echo shar: "extracting 'faillog.4'" '(973 characters)'
if test -f 'faillog.4'
then
	echo shar: "will not over-write existing file 'faillog.4'"
else
sed 's/^X//' << \SHAR_EOF > 'faillog.4'
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.\"	@(#)faillog.4	2.1.1.1	09:07:16	11/26/90
X.\"
X.TH FAILLOG 4
X.SH NAME
Xfaillog \- Login failure logging file
X.SH DESCRIPTION
X.I faillog
Xmaintains a count of login failures and the limits for each account.
XThe file is fixed length record, indexed by numerical UID.
XEach record contains the count of login failures since the last
Xsuccessful login;
Xthe maximum number of failures before the account is disabled;
Xthe line the last login failure occured on;
Xand the date the last login failure occured.
X.PP
XThe structure of the file is
X.DS
X
X        struct	faillog {
X                short   fail_cnt;
X                short   fail_max;
X                char    fail_line[12];
X                time_t  fail_time;
X        };
X
X.DE
X.SH Files
X/usr/adm/faillog \- login failure log
X.SH See Also
Xfaillog(8)
SHAR_EOF
if test 973 -ne "`wc -c < 'faillog.4'`"
then
	echo shar: "error transmitting 'faillog.4'" '(should have been 973 characters)'
fi
fi
echo shar: "extracting 'passwd.4'" '(2524 characters)'
if test -f 'passwd.4'
then
	echo shar: "will not over-write existing file 'passwd.4'"
else
sed 's/^X//' << \SHAR_EOF > 'passwd.4'
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.\"	@(#)passwd.4	2.1.1.1	09:07:17	11/26/90
X.\"
X.TH PASSWD 4
X.SH NAME
Xpasswd \- The password file
X.SH DESCRIPTION
X.I passwd
Xcontains various pieces of information for each user account.
XIncluded is
X.IP "" .5i
XLogin name
X.IP "" .5i
XOptional encrypted password
X.IP "" .5i
XNumerical user ID
X.IP "" .5i
XNumerical group ID
X.IP "" .5i
XUser name or comment field
X.IP "" .5i
XUser home directory
X.IP "" .5i
XUser command interpreter
X.PP
XThe password field may not be filled if shadow passwords
Xhave been enabled.
XIf shadow passwords are being used, the encrypted password will
Xbe found in \fB/etc/shadow\fR.
XThe encryped password consists of 13 characters from the
X64 character alphabet
Xa thru z, A thru Z, 0 thru 9, \. and /.
XRefer to \fIcrypt(3)\fR for details on how this string is
Xinterpreted.
X.PP
XAn optional password age string may follow the encrypted
Xpassword, separated by a comma, from the same alphabet
Xas the password itself.
XThe first character gives the number of weeks during which the
Xpassword is valid.
XThe second character gives the number of weeks which must pass
Xbefore the user is permitted to change the password.
XThe last two characters give the week since Jan 1970 when the
Xpassword was last changed.
XWhen the number of weeks during which the password is valid
Xhave passed, the user will be required to provide a new
Xpassword.
X.PP
XThe comment field is used by various system utilities, such as
X\fIfinger(1)\fR.
XThree additional values may be present in the comment field.
XThey are
X.IP "" .5i
Xpri= \- set initial value of nice
X.IP "" .5i
Xumask= \- set initial value of umask
X.IP "" .5i
Xulimit= \- set initial value of ulimit
X.PP
XThese fields are separated from each other and from any other
Xcomment field by a comma.
X.PP
XThe home directory field provides the name of the initial
Xworking directory.
X\fILogin\fR uses this information to set the value of
Xthe \fBHOME\fR environmental variable.
X.PP
XThe command interpreter field provides the name of the user's
Xcommand language interpreter, or the name of the initial program
Xto execute.
X\fILogin\fR uses this information to set the value of the
X\fBSHELL\fR environmental variable.
XIf this field is empty, it defaults to the value \fB/bin/sh\fR.
X.SH Files
X/etc/passwd \- user account information
X.SH See Also
Xlogin(1),
Xpasswd(1),
Xsu(1),
Xsulogin(1M),
Xshadow(4),
Xpwconv(8),
Xpwunconv(8)
SHAR_EOF
if test 2524 -ne "`wc -c < 'passwd.4'`"
then
	echo shar: "error transmitting 'passwd.4'" '(should have been 2524 characters)'
fi
fi
echo shar: "extracting 'porttime.4'" '(1867 characters)'
if test -f 'porttime.4'
then
	echo shar: "will not over-write existing file 'porttime.4'"
else
sed 's/^X//' << \SHAR_EOF > 'porttime.4'
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.\"	@(#)porttime.4	2.1.1.1	09:07:19	11/26/90
X.\"
X.TH PORTTIME 4
X.SH NAME
Xporttime \- port access time file
X.SH DESCRIPTION
X.I porttime
Xcontains a list of tty device, user name, and permitted login times.
X.PP
XEach entry consists of three colon separated fields.
XThe first field is the name of the tty device, or an asterisk to
Xindicate that all tty devices are matched by this entry.
XThe second field is a comma separated list of user names, or an
Xasterisk to indicated that all user names are matched by this entry.
XThe third field is a comma separated list of permitted access times.
X.PP
XEach access time entry consists of zero or more days of the week,
Xabbreviated \fBSu\fR, \fBMo\fR, \fBTu\fR, \fBWe\fR, \fBTh\fR,
X\fBFr\fR, and \fBSa\fR, followed by a pair of times separated by
Xa hyphen.
XThe abbreviation \fBWk\fR may be used to represent Monday thru Friday,
Xand \fBAl\fR may be used to indicate every day.
XIf no days are given, \fBAl\fR is assumed.
X.SH Examples
XThe following entry allows access to user \fBjfh\fR on every port
Xduring weekdays from 9am to 5pm.
X.br
X.sp 1
X*:jfh:Wk0900-1700
X.br
X.sp 1
XThe following entries allow access only to the users \fBroot\fR and
X\fBoper\fR on /dev/console at any time.  This illustrates how the
X\fB/etc/porttime\fR file is an ordered list of access times.  Any
Xother user would match the second entry which does not permit
Xaccess at any time.
X.br
X.sp 1
Xconsole:root,oper:Al0000-2400
X.br
Xconsole:*:
X.br
X.sp 1
XThe following entry allows access for the user \fBgames\fR on any
Xport during non-working hours.
X.br
X.sp 1
X*:games:Wk1700-0900,SaSu0000-2400
X.br
X.sp 1
X.SH Files
X/etc/porttime \- file containing port access times
X.SH See Also
Xlogin(1)
SHAR_EOF
if test 1867 -ne "`wc -c < 'porttime.4'`"
then
	echo shar: "error transmitting 'porttime.4'" '(should have been 1867 characters)'
fi
fi
echo shar: "extracting 'shadow.4'" '(1594 characters)'
if test -f 'shadow.4'
then
	echo shar: "will not over-write existing file 'shadow.4'"
else
sed 's/^X//' << \SHAR_EOF > 'shadow.4'
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.\"	@(#)shadow.4	2.1.1.1	09:07:21	11/26/90
X.\"
X.TH SHADOW 4
X.SH NAME
Xshadow \- encrypted password file
X.SH DESCRIPTION
X.I shadow
Xcontains the encrypted password information for user's accounts
Xand optional the password aging information.
XIncluded is
X.IP "" .5i
XLogin name
X.IP "" .5i
XEncrypted password
X.IP "" .5i
XDate password last changed
X.IP "" .5i
XDays before password may be changed
X.IP "" .5i
XDays after which password must be changed
X.PP
XThe password field must be filled.
XThe encryped password consists of 13 characters from the
X64 character alphabet
Xa thru z, A thru Z, 0 thru 9, \. and /.
XRefer to \fIcrypt(3)\fR for details on how this string is
Xinterpreted.
X.PP
XThe date of the last password change is given as the number
Xof days since Jan 1, 1970.
XThe password may not be changed again until the proper number
Xof days have passed, and must be changed after the maximum
Xnumber of days.
XIf the minimum number of days required is greater than the
Xmaximum number of day allowed, this password may not be
Xchanged by the user.
X.PP
XThis information supercedes any password or password age
Xinformation present in \fB/etc/passwd\fR.
X.PP
XThis file must not be readable by regular users if password
Xsecurity is to be maintained.
X.SH Files
X/etc/passwd \- user account information
X.br
X/etc/shadow \- encrypted user passwords
X.SH See Also
Xlogin(1),
Xpasswd(1),
Xsu(1),
Xsulogin(1M),
Xpasswd(4),
Xpwconv(8),
Xpwunconv(8)
SHAR_EOF
if test 1594 -ne "`wc -c < 'shadow.4'`"
then
	echo shar: "error transmitting 'shadow.4'" '(should have been 1594 characters)'
fi
fi
echo shar: "extracting 'faillog.8'" '(2034 characters)'
if test -f 'faillog.8'
then
	echo shar: "will not over-write existing file 'faillog.8'"
else
sed 's/^X//' << \SHAR_EOF > 'faillog.8'
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.\"	@(#)faillog.8	2.1.1.1	09:07:22	11/26/90
X.\"
X.TH FAILLOG 8
X.SH NAME
Xfaillog \- examine faillog and set login failure limits
X.SH SYNOPSIS
X/etc/faillog [ -u uid ] [ -t days ] [ -m max ] [ -pr ] 
X.SH DESCRIPTION
X\fIPlastlog\fR formats the contents of the failure log,
X\fI/usr/adm/faillog\fR, and maintains failure counts and
Xlimits.
XThe order of the arguments to \fIfaillog\fR is significant.
XEach argument is processed immediately in the order given.
X.PP
XThe \fB-p\fR flag causes failure entries to be printed in UID
Xorder.
XEntering \fB-u login-name\fR flag will
Xcause the failure record for \fBlogin-name\fR only to be printed.
XEntering \fB-t days\fR will cause only the
Xfailures more recent than \fBdays\fR to be printed.
XThe \fB-t\fR flag overrides the use of \fB-u\fR.
X.PP
XThe \fB-r\fR flag is used to reset the count of login failures.
XWrite access to \fI/usr/adm/faillog\fR is required for
Xthis option.
XEntering \fB-u login-name\fR will cause only the failure count
Xfor \fBlogin-name\fR to be reset.
X.PP
XThe \fB-m\fR flag is used to set the maximum number of login
Xfailures before the account is disabled.
XWrite access to \fB/usr/adm/faillog\fR is required for this
Xoption.
XEntering \fB-m max\fR will cause all accounts to be disabled
Xafter \fBmax\fR failed logins occur.
XThis may be modified with \fB-u login-name\fR to limit this
Xfunction to \fBlogin-name\fR only.
XSelecting a \fBmax\fR value of 0 has the effect of not placing
Xa limit on the number of failed logins.
XThe maximum failure count
Xshould always be 0 for \fBroot\fR to prevent
Xa denial of services attack against the system.
X.PP
XOptions may be combined in virtually any fashion.
XEach \fB-p\fR, \fB-r\fR, and \fB-m\fR option will cause
Ximmediate execution using any \fB-u\fR or \fB-t\fR modifier.
X.SH Files
X/usr/adm/faillog \- failure logging file
X.SH See Also
Xlogin(1),
Xfaillog(4)
SHAR_EOF
if test 2034 -ne "`wc -c < 'faillog.8'`"
then
	echo shar: "error transmitting 'faillog.8'" '(should have been 2034 characters)'
fi
fi
echo shar: "extracting 'pwconv.8'" '(1202 characters)'
if test -f 'pwconv.8'
then
	echo shar: "will not over-write existing file 'pwconv.8'"
else
sed 's/^X//' << \SHAR_EOF > 'pwconv.8'
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.\"	@(#)pwconv.8	2.1.1.1	09:07:23	11/26/90
X.\"
X.TH PWCONV 8
X.SH NAME
Xpwconv \- convert and update shadow password files
X.SH SYNOPSIS
X/etc/pwconv
X.SH DESCRIPTION
X\fIPwconv\fR copies the old password file information to a new shadow
Xpassword file,
Xmerging entries from an optional existing shadow file.
XThe new password file is left in \fBnpasswd\fR,
Xthe new shadow file is left in \fBnshadow\fR.
XBoth of these are files are created with modes which only permit
Xread access to the owner.
XExisting shadow entries are copied as is.
XNew entries are created with passwords which expire in 10000 days,
Xwith a last changed date of today,
Xunless password aging information was already present.
XEntries with blank passwords are not copied to the shadow file at all.
X.SH Files
X/etc/passwd \- old encrypted passwords and password aging
X.br
X/etc/shadow \- previously converted shadow password file
X.br
X./npasswd \- new password file
X.br
X./nshadow \- new shadow password file
X.SH See Also
Xpasswd(1),
Xpasswd(4),
Xshadow(4),
Xpwunconv(8)
SHAR_EOF
if test 1202 -ne "`wc -c < 'pwconv.8'`"
then
	echo shar: "error transmitting 'pwconv.8'" '(should have been 1202 characters)'
fi
fi
echo shar: "extracting 'pwunconv.8'" '(930 characters)'
if test -f 'pwunconv.8'
then
	echo shar: "will not over-write existing file 'pwunconv.8'"
else
sed 's/^X//' << \SHAR_EOF > 'pwunconv.8'
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.\"	@(#)pwunconv.8	2.1.1.1	09:07:25	11/26/90
X.\"
X.TH PWUNCONV 8
X.SH NAME
Xpwunconv \- restore old password file from shadow password file
X.SH SYNOPSIS
X/etc/pwunconv
X.SH DESCRIPTION
X\fIPwunconv\fR copies the password file information from the shadow
Xpassword file,
Xmerging entries from an optional existing shadow file.
XThe new password file is left in \fBnpasswd\fR.
XThis file is created with modes which allow read access for
Xthe owner only.
XThere is no new shadow file.
XPassword aging information is translated where possible.
X.SH Files
X/etc/passwd \- old encrypted passwords and password aging
X.br
X/etc/shadow \- previously converted shadow password file
X.br
X./npasswd \- new password file
X.SH See Also
Xpasswd(1),
Xpasswd(4),
Xshadow(4),
Xpwconv(8)
SHAR_EOF
if test 930 -ne "`wc -c < 'pwunconv.8'`"
then
	echo shar: "error transmitting 'pwunconv.8'" '(should have been 930 characters)'
fi
fi
echo shar: "extracting 'sulogin.8'" '(1615 characters)'
if test -f 'sulogin.8'
then
	echo shar: "will not over-write existing file 'sulogin.8'"
else
sed 's/^X//' << \SHAR_EOF > 'sulogin.8'
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.\"	@(#)sulogin.8	2.1.1.1	09:07:26	11/26/90
X.\"
X.TH SULOGIN 8
X.SH NAME
Xsulogin \- Single-user login
X.SH DESCRIPTION
X.I sulogin
Xis invoked by \fB/etc/init\fR prior to allowing the user
Xaccess to the system when in single user mode.
XThis feature may only be available on certain systems where
X\fIinit\fR has been modified accordingly, or where the
X\fB/etc/inittab\fR has an entry for a single user login.
X.PP
XThe user is prompted
X.IP "" .5i
XType control-d for normal startup,
X.br
X(or give root password for system maintenance):
X.PP
XIf the user enters the correct root password, a login session
Xis initiated.
XWhen \fBEOF\fR is pressed instead, the system enters multi-user
Xmode.
X.PP
XAfter the user exits the single-user shell, or presses \fBEOF\fR,
Xthe system begins the initialization process required to enter
Xmulti-user mode.
X.SH CAVEATS
X.PP
XThis command can only be used if \fIinit\fR has been modified to call
X\fB/etc/sulogin\fR instead of \fB/bin/sh\fR,
Xor if the user has set the \fIinittab\fR to support a single user
Xlogin.
X.PP
XAs complete an environment as possible is created.
XHowever, various devices may be unmounted or uninitialized and many 
Xof the user commands may be unavailable or nonfunctional as a result.
X.SH Files
X/etc/passwd \- user account information
X.br
X/etc/shadow \- encrypted passwords and age information
X.br
X/.profile \- initialization script for single user shell
X.SH See Also
Xlogin(1),
Xinit(1M),
Xsh(1)
SHAR_EOF
if test 1615 -ne "`wc -c < 'sulogin.8'`"
then
	echo shar: "error transmitting 'sulogin.8'" '(should have been 1615 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
John F. Haugh II                             UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 832-8832                           Domain: jfh@rpp386.cactus.org