Shadow Login Suite, version 3 (part 2 of 8)

John F Haugh II jfh at rpp386.cactus.org
Fri May 17 02:31:34 AEST 1991


#! /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:
#	passwd.c
#	port.c
#	lmain.c
#	mkpasswd.c
#	sulogin.c
#	pwpack.c
#	dialup.c
#	sulog.c
#	getpass.c
# This archive created: Sun Mar  3 13:27:16 1991
# By:	John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'passwd.c'" '(17138 characters)'
if test -f 'passwd.c'
then
	echo shar: "will not over-write existing file 'passwd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'passwd.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <sys/types.h>
X#include <time.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <syslog.h>
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)passwd.c	3.1	09:00:47	2/8/91";
X#endif
X
X/*
X * Set up some BSD defines so that all the BSD ifdef's are
X * kept right here 
X */
X
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#define	bzero(a,n)	memset(a, 0, n)
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X
X#include "config.h"
X#include "pwd.h"
X#include "lastlog.h"
X#include "shadow.h"
X
X/*
X * Password aging constants
X *
X *	DAY - seconds in a day
X *	WEEK - seconds in a week
X *	SCALE - convert from clock to aging units
X */
X
X#define	DAY	(24L*3600L)
X#define	WEEK	(7L*DAY)
X
X#ifdef	ITI_AGING
X#define	SCALE	(1)
X#else
X#define	SCALE	DAY
X#endif
X
X/*
X * Global variables
X */
X
Xchar	name[32];		/* The user's name */
Xchar	*Prog;			/* Program name */
Xint	amroot;			/* The real UID was 0 */
X
X/*
X * External identifiers
X */
X
Xextern	char	*getpass();
Xextern	char	*pw_encrypt();
Xextern	char	*getlogin();
Xextern	int	optind;		/* Index into argv[] for current option */
Xextern	char	*optarg;	/* Pointer to current option value */
X#ifdef	NDBM
Xextern	int	sp_dbm_mode;
Xextern	int	pw_dbm_mode;
X#endif
X
X/*
X * #defines for messages.  This facilities foreign language conversion
X * since all messages are defined right here.
X */
X
X#define	USAGE		"usage: %s [ -f | -s ] [ name ]\n"
X#define	ADMUSAGE \
X	"       %s [ -x max ] [ -n min ] [ -w warn ] [ -i inact ] name\n"
X#define	ADMUSAGE2 \
X	"       %s { -l | -d | -S } name\n"
X#define	OLDPASS		"Old Password:"
X#define	NEWPASSMSG \
X"Enter the new password (minimum of 5 characters)\n\
XPlease use a combination of upper and lower case letters and numbers.\n"
X#define NEWPASS		"New Password:"
X#define	NEWPASS2	"Re-enter new password:"
X#define	WRONGPWD	"Incorrect password for %s.\n"
X#define	WRONGPWD2	"incorrect password for `%s'\n"
X#define	NOMATCH		"They don't match; try again.\n"
X#define	CANTCHANGE	"The password for %s cannot be changed.\n"
X#define	CANTCHANGE2	"password locked for `%s'\n"
X#define	TOOSOON		"Sorry, the password for %s cannot be changed yet.\n"
X#define	TOOSOON2	"now < sp_min for `%s'\n"
X#define	EXECFAILED	"%s: Cannot execute %s"
X#define	EXECFAILED2	"cannot execute %s\n"
X#define	WHOAREYOU	"%s: Cannot determine you user name.\n"
X#define	UNKUSER		"%s: Unknown user %s\n"
X#define	NOPERM		"You may not change the password for %s.\n"
X#define	NOPERM2		"can't change pwd for `%s'\n"
X#define	UNCHANGED	"The password for %s is unchanged.\n"
X#define	SPWDBUSY	"Cannot lock the password file; try again later.\n"
X#define	SPWDBUSY2	"can't lock /etc/shadow\n"
X#define	OPNERROR	"Cannot open the password file.\n"
X#define	OPNERROR2	"can't open /etc/shadow\n"
X#define	UPDERROR	"Error updating the password entry.\n"
X#define	UPDERROR2	"error updating shadow entry\n"
X#define	DBMERROR	"Error updating the DBM password entry.\n"
X#define	DBMERROR2	"error updating DBM shadow entry.\n"
X#define	NOTROOT		"Cannot change ID to root.\n"
X#define	NOTROOT2	"can't setuid(0).\n"
X#define	CLSERROR	"Cannot commit shadow file changes.\n"
X#define	CLSERROR2	"can't rewrite /etc/shadow.\n"
X#define	UNLKERROR	"Cannot unlock the shadow file.\n"
X#define	UNLKERROR2	"can't unlock /etc/shadow.\n"
X#define	TRYAGAIN	"Try again.\n"
X#define	CHGPASSWD	"changed password for `%s'\n"
X
X/*
X * usage - print command usage and exit
X */
X
Xvoid
Xusage ()
X{
X	fprintf (stderr, USAGE, Prog);
X	if (amroot) {
X		fprintf (stderr, ADMUSAGE, Prog);
X		fprintf (stderr, ADMUSAGE2, Prog);
X	}
X	exit (1);
X}
X
X/*
X * new_password - validate old password and replace with new
X */
X
Xint
Xnew_password (pw, sp)
Xstruct	passwd	*pw;
Xstruct	spwd	*sp;
X{
X	char	*clear;		/* Pointer to clear text */
X	char	*cipher;	/* Pointer to cipher text */
X	char	*cp;		/* Pointer to getpass() response */
X	char	orig[BUFSIZ];	/* Original password */
X	char	pass[BUFSIZ];	/* New password */
X	int	i;		/* Counter for retries */
X
X	/*
X	 * Authenticate the user.  The user will be prompted for their
X	 * own password.
X	 */
X
X	if (! amroot && sp->sp_pwdp[0]) {
X		bzero (orig, sizeof orig);
X
X		if (! (clear = getpass (OLDPASS)))
X			return -1;
X
X		cipher = pw_encrypt (clear, sp->sp_pwdp);
X		if (strcmp (cipher, sp->sp_pwdp) != 0) {
X			sleep (1);
X			fprintf (stderr, WRONGPWD, sp->sp_namp);
X			syslog (LOG_WARN, WRONGPWD2, sp->sp_namp);
X			return -1;
X		}
X		strcpy (orig, clear);
X	}
X
X	/*
X	 * Get the new password.  The user is prompted for the new password
X	 * and has three tries to get it right.  The password will be tested
X	 * for strength, unless it is the root user.  This provides an escape
X	 * for initial login passwords.
X	 */
X
X	printf (NEWPASSMSG);
X	for (i = 0;i < 3;i++) {
X		if (! (cp = getpass (NEWPASS)))
X			return -1;
X		else
X			strcpy (pass, cp);
X
X		if (! amroot && ! obscure (orig, pass)) {
X			printf (TRYAGAIN);
X			continue;
X		}
X		if (! (cp = getpass (NEWPASS2)))
X			return -1;
X
X		if (strcmp (cp, pass))
X			fprintf (stderr, NOMATCH);
X		else
X			break;
X	}
X	if (i == 3)
X		return -1;
X
X	/*
X	 * Encrypt the password.  The new password is encrypted and
X	 * the shadow password structure updated to reflect the change.
X	 */
X
X	sp->sp_pwdp = pw_encrypt (pass, (char *) 0);
X	sp->sp_lstchg = time ((time_t *) 0) / SCALE;
X
X	return 0;
X}
X
X/*
X * check_password - test a password to see if it can be changed
X *
X *	check_password() sees if the invoker has permission to change the
X *	password for the given user.
X */
X
Xvoid
Xcheck_password (pw, sp)
Xstruct	passwd	*pw;
Xstruct	spwd	*sp;
X{
X	time_t	now = time ((time_t *) 0) / SCALE;
X
X	/*
X	 * Root can change any password any time.
X	 */
X
X	if (amroot)
X		return;
X
X	/*
X	 * Expired accounts cannot be changed ever.  Passwords
X	 * which are locked may not be changed.  Passwords where
X	 * min > max may not be changed.  Passwords which have
X	 * been inactive too long cannot be changed.
X	 */
X
X	if ((sp->sp_expire > 0 && now >= sp->sp_expire) ||
X	    (sp->sp_inact >= 0 && sp->sp_max >= 0 &&
X		now >= (sp->sp_lstchg + sp->sp_inact + sp->sp_max)) ||
X			strcmp (sp->sp_pwdp, "!") == 0 ||
X			sp->sp_min > sp->sp_max) {
X		fprintf (stderr, CANTCHANGE, sp->sp_namp);
X		syslog (LOG_WARN, CANTCHANGE2, sp->sp_namp);
X		exit (1);
X	}
X
X	/*
X	 * Passwords may only be changed after sp_min time is up.
X	 */
X
X	if (sp->sp_min >= 0 && now < (sp->sp_lstchg + sp->sp_min)) {
X		fprintf (stderr, TOOSOON, sp->sp_namp);
X		syslog (LOG_WARN, TOOSOON2, sp->sp_namp);
X		exit (1);
X	}
X}
X
X/*
X * pwd_to_spwd - create entries for new spwd structure
X *
X *	pwd_to_spwd() creates a new (struct spwd) containing the
X *	information in the pointed-to (struct passwd).
X */
X
Xvoid
Xpwd_to_spwd (pw, sp)
Xstruct	passwd	*pw;
Xstruct	spwd	*sp;
X{
X	time_t	t;
X
X	/*
X	 * Nice, easy parts first.  The name and passwd map directly
X	 * from the old password structure to the new one.
X	 */
X
X	sp->sp_namp = strdup (pw->pw_name);
X	sp->sp_pwdp = strdup (pw->pw_passwd);
X#ifdef	ATT_AGE
X
X	/*
X	 * AT&T-style password aging maps the sp_min, sp_max, and
X	 * sp_lstchg information from the pw_age field, which appears
X	 * after the encrypted password.
X	 */
X
X	if (pw->pw_age[0]) {
X		t = (c64i (pw->pw_age[0]) * WEEK) / SCALE;
X		sp->sp_max = t;
X
X		if (pw->pw_age[1]) {
X			t = (c64i (pw->pw_age[1]) * WEEK) / SCALE;
X			sp->sp_min = t;
X		} else
X			sp->sp_min = (10000L * DAY) / SCALE;
X
X		if (pw->pw_age[1] && pw->pw_age[2]) {
X			t = (a64l (pw->pw_age + 2) * WEEK) / SCALE;
X			sp->sp_lstchg = t;
X		} else
X			sp->sp_lstchg = time ((time_t *) 0) / SCALE;
X	} else {
X		sp->sp_min = 0;
X		sp->sp_max = (10000L * DAY) / SCALE;
X		sp->sp_lstchg = time ((time_t *) 0) / SCALE;
X	}
X#else
X	/*
X	 * BSD does not use the pw_age field and has no aging information
X	 * anywheres.  The default values are used to initialize the
X	 * fields which are in the missing pw_age field;
X	 */
X
X	sp->sp_min = 0;
X	sp->sp_max = (10000L * DAY) / SCALE;
X	sp->sp_lstchg = time ((time_t *) 0) / SCALE;
X#endif
X
X	/*
X	 * These fields have no corresponding information in the password
X	 * file.  They are set to uninitialized values.
X	 */
X
X	sp->sp_warn = -1;
X	sp->sp_inact = -1;
X	sp->sp_expire = -1;
X	sp->sp_flag = -1;
X}
X
X/*
X * print_status - print current password status
X */
X
Xvoid
Xprint_status (sp)
Xstruct	spwd	*sp;
X{
X	struct	tm	*tm;
X	time_t	time;
X
X	time = sp->sp_lstchg * SCALE;
X	tm = gmtime (&time);
X
X	printf ("%s ", sp->sp_namp);
X	printf ("%s ",
X		sp->sp_pwdp[0] ? (sp->sp_pwdp[0] == '!' ? "L":"P"):"NP");
X	printf ("%02.2d/%02.2d/%02.2d ",
X		tm->tm_mon + 1, tm->tm_mday, tm->tm_year % 100);
X	printf ("%d %d %d %d\n",
X		(sp->sp_min * SCALE) / DAY, (sp->sp_max * SCALE) / DAY,
X		(sp->sp_warn * SCALE) / DAY, (sp->sp_inact * SCALE) / DAY);
X}
X
X/*
X * passwd - change a user's password file information
X *
X *	This command controls the password file and commands which are
X * 	used to modify it.
X *
X *	The valid options are
X *
X *	-l	lock the named account (*)
X *	-d	delete the password for the named account (*)
X *	-x #	set sp_max to # days (*)
X *	-n #	set sp_min to # days (*)
X *	-w #	set sp_warn to # days (*)
X *	-i #	set sp_inact to # days (*)
X *	-S	show password status of named account (*)
X *	-g	execute gpasswd command to interpret flags
X *	-f	execute chfn command to interpret flags
X *	-s	execute chsh command to interpret flags
X *
X *	(*) requires root permission to execute.
X *
X *	All of the time fields are entered in days and converted to the
X * 	appropriate internal format.  For finer resolute the chage
X *	command must be used.
X */
X
Xint
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	char	buf[BUFSIZ];		/* I/O buffer for messages, etc.      */
X	char	*cp;			/* Miscellaneous character pointing   */
X	time_t	min;			/* Minimum days before change         */
X	time_t	max;			/* Maximum days until change          */
X	time_t	warn;			/* Warning days before change         */
X	time_t	inact;			/* Days without change before locked  */
X	int	i;			/* Loop control variable              */
X	int	flag;			/* Current option to process          */
X	int	lflg = 0;		/* -l - lock account option           */
X	int	dflg = 0;		/* -d - delete password option        */
X	int	xflg = 0;		/* -x - set maximum days              */
X	int	nflg = 0;		/* -n - set minimum days              */
X	int	wflg = 0;		/* -w - set warning days              */
X	int	iflg = 0;		/* -i - set inactive days             */
X	int	Sflg = 0;		/* -S - show password status          */
X	struct	passwd	*pw;		/* Password file entry for user       */
X	struct	spwd	*sp;		/* Shadow file entry for user         */
X	struct	spwd	tspwd;		/* New shadow file entry if none      */
X
X	/*
X	 * The program behaves differently when executed by root
X	 * than when executed by a normal user.
X	 */
X
X	amroot = getuid () == 0;
X#ifdef	NDBM
X	sp_dbm_mode = O_RDWR;
X	pw_dbm_mode = O_RDWR;
X#endif
X
X	/*
X	 * Get the program name.  The program name is used as a
X	 * prefix to most error messages.  It is also used as input
X	 * to the openlog() function for error logging.
X	 */
X
X	if (Prog = strrchr (argv[0], '/'))
X		Prog++;
X	else
X		Prog = argv[0];
X
X	openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
X
X	/*
X	 * Start with the flags which cause another command to be
X	 * executed.  The effective UID will be set back to the
X	 * real UID and the new command executed with the flags
X	 */
X
X	if (argc > 1 && argv[1][0] == '-' && strchr ("gfs", argv[1][1])) {
X		setuid (getuid ());
X		switch (argv[1][1]) {
X			case 'g':
X				argv[1] = "gpasswd";
X				execv ("/bin/gpasswd", &argv[1]);
X				break;
X			case 'f':
X				argv[1] = "chfn";
X				execv ("/bin/chfn", &argv[1]);
X				break;
X			case 's':
X				argv[1] = "chsh";
X				execv ("/bin/chsh", &argv[1]);
X				break;
X			default:
X				usage ();
X		}
X		sprintf (buf, EXECFAILED, Prog, argv[1]);
X		perror (buf);
X		syslog (LOG_CRIT, EXECFAILED2, argv[1]);
X		exit (1);
X	}
X
X	/* 
X	 * The remaining arguments will be processed one by one and
X	 * executed by this command.  The name is the last argument
X	 * if it does not begin with a "-", otherwise the name is
X	 * determined from the environment and must agree with the
X	 * real UID.  Also, the UID will be checked for any commands
X	 * which are restricted to root only.
X	 */
X
X	while ((flag = getopt (argc, argv, "ldx:n:w:i:S")) != EOF) {
X		switch (flag) {
X			case 'x':
X				max = strtol (optarg, &cp, 10);
X				if (*cp || getuid ())
X					usage ();
X
X				xflg++;
X				break;
X			case 'n':
X				min = strtol (optarg, &cp, 10);
X				if (*cp || getuid ())
X					usage ();
X
X				nflg++;
X				break;
X			case 'w':
X				warn = strtol (optarg, &cp, 10);
X				if (*cp || getuid ())
X					usage ();
X
X				wflg++;
X				break;
X			case 'i':
X				inact = strtol (optarg, &cp, 10);
X				if (*cp || getuid ())
X					usage ();
X
X				iflg++;
X				break;
X			case 'S':
X				if (getuid ())
X					usage ();
X
X				Sflg++;
X				break;
X			case 'd':
X				dflg++;
X				break;
X			case 'l':
X				lflg++;
X				break;
X			default:
X				usage ();
X		}
X	}
X
X	/*
X	 * If any of the flags were given, a user name must be supplied
X	 * on the command line.  Only an unadorned command line doesn't
X	 * require the user's name be given.  Also, on -x, -n, -m, and
X	 * -i may appear with each other.  -d, -l and -S must appear alone.
X	 */
X
X	if ((dflg || lflg || xflg || nflg ||
X				wflg || iflg || Sflg) && optind >= argc)
X		usage ();
X
X	if ((dflg + lflg + (xflg || nflg || wflg || iflg) + Sflg) > 1)
X		usage ();
X
X	/*
X	 * Now I have to get the user name.  The name will be gotten 
X	 * from the command line if possible.  Otherwise it is figured
X	 * out from the environment.
X	 */
X
X	if (optind < argc) {
X		strncpy (name, argv[optind], sizeof name);
X		name[sizeof name - 1] = '\0';
X	} else if (cp = getlogin ()) {
X		strncpy (name, cp, sizeof name);
X		name[sizeof name - 1] = '\0';
X	} else {
X		fprintf (stderr, WHOAREYOU, Prog);
X		exit (1);
X	}
X
X	/*
X	 * Now I have a name, let's see if the UID for the name
X	 * matches the current real UID.
X	 */
X
X	if (! (pw = getpwnam (name))) {
X		fprintf (stderr, UNKUSER, Prog, name);
X		exit (1);
X	}
X	if (! amroot && pw->pw_uid != getuid ()) {
X		fprintf (stderr, NOPERM, name);
X		syslog (LOG_WARN, NOPERM2, name);
X		exit (1);
X	}
X
X	/*
X	 * The user name is valid, so let's get the shadow file
X	 * entry.
X	 */
X
X	if (! (sp = getspnam (name)))
X		pwd_to_spwd (pw, sp = &tspwd);
X
X	/*
X	 * Save the shadow entry off to the side so it doesn't
X	 * get changed by any of the following code.
X	 */
X
X	if (sp != &tspwd) {
X		tspwd = *sp;
X		sp = &tspwd;
X	}
X	tspwd.sp_namp = strdup (sp->sp_namp);
X	tspwd.sp_pwdp = strdup (sp->sp_pwdp);
X
X	if (Sflg) {
X		print_status (sp);
X		exit (0);
X	}
X
X	/*
X	 * If there are no other flags, just change the password.
X	 */
X
X	if (! (dflg || lflg || xflg || nflg || wflg || iflg)) {
X
X		/*
X		 * See if the user is permitted to change the password.
X		 * Otherwise, go ahead and set a new password.
X		 */
X
X		check_password (pw, sp);
X
X		if (new_password (pw, sp)) {
X			fprintf (stderr, UNCHANGED, name);
X			exit (1);
X		}
X	}
X
X	/*
X	 * The other options are incredibly simple.  Just modify the
X	 * field in the shadow file entry.
X	 */
X
X	if (dflg)			/* Set password to blank */
X		sp->sp_pwdp = "";
X
X	if (lflg)			/* Set password to "locked" value */
X		sp->sp_pwdp = "!";
X
X	if (xflg)
X		sp->sp_max = (max * DAY) / SCALE;
X
X	if (nflg)
X		sp->sp_min = (min * DAY) / SCALE;
X
X	if (wflg)
X		sp->sp_warn = (warn * DAY) / SCALE;
X
X	if (iflg)
X		sp->sp_inact = (inact * DAY) / SCALE;
X
X	/*
X	 * Before going any further, raise the ulimit to prevent
X	 * colliding into a lowered ulimit, and set the real UID
X	 * to root to protect against unexpected signals.  Any
X	 * keyboard signals are set to be ignored.
X	 */
X
X	ulimit (2, 30000);
X	if (setuid (0)) {
X		fprintf (stderr, NOTROOT);
X		syslog (LOG_ERR, NOTROOT2);
X		exit (1);
X	}
X	signal (SIGHUP, SIG_IGN);
X	signal (SIGINT, SIG_IGN);
X	signal (SIGQUIT, SIG_IGN);
X#ifdef	SIGTSTP
X	signal (SIGTSTP, SIG_IGN);
X#endif
X
X	/*
X	 * The shadow entry is now ready to be committed back to
X	 * the shadow file.  Get a lock on the file and open it.
X	 */
X
X	for (i = 0;i < 30;i++)
X		if (spw_lock ())
X			break;
X
X	if (i == 30) {
X		fprintf (stderr, SPWDBUSY);
X		syslog (LOG_WARN, SPWDBUSY2);
X		exit (1);
X	}
X	if (! spw_open (O_RDWR)) {
X		fprintf (stderr, OPNERROR);
X		syslog (LOG_ERR, OPNERROR2);
X		(void) spw_unlock ();
X		exit (1);
X	}
X
X	/*
X	 * Update the shadow file entry.  If there is a DBM file,
X	 * update that entry as well.
X	 */
X
X	if (! spw_update (sp)) {
X		fprintf (stderr, UPDERROR);
X		syslog (LOG_ERR, UPDERROR2);
X		(void) spw_unlock ();
X		exit (1);
X	}
X#ifdef	NDBM
X	if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (sp)) {
X		fprintf (stderr, DBMERROR);
X		syslog (LOG_ERR, DBMERROR2);
X		(void) spw_unlock ();
X		exit (1);
X	}
X#endif
X
X	/*
X	 * Changes have all been made, so commit them and unlock the
X	 * file.
X	 */
X
X	if (! spw_close ()) {
X		fprintf (stderr, CLSERROR);
X		syslog (LOG_ERR, CLSERROR2);
X		(void) spw_unlock ();
X		exit (1);
X	}
X	if (! spw_unlock ()) {
X		fprintf (stderr, UNLKERROR);
X		syslog (LOG_ERR, UNLKERROR2);
X		exit (1);
X	}
X	syslog (LOG_INFO, CHGPASSWD, name);
X	exit (0);
X}
SHAR_EOF
if test 17138 -ne "`wc -c < 'passwd.c'`"
then
	echo shar: "error transmitting 'passwd.c'" '(should have been 17138 characters)'
fi
fi
echo shar: "extracting 'port.c'" '(8978 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, 1991, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
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	3.1	08:59:32	2/8/91";
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	*ttys[PORT_TTY+1]; /* some pointers to tty names     */
X	static	char	*users[PORT_IDS+1]; /* some pointers to user ids     */
X	static	struct	pt_time	times[PORT_TIMES+1]; /* time ranges          */
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 names
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_names = ttys;
X	for (cp = buf, j = 0;j < PORT_TTY;j++) {
X		port.pt_names[j] = cp;
X		while (*cp && *cp != ':' && *cp != ',')
X			cp++;
X
X		if (! *cp)
X			goto again;	/* line format error */
X
X		if (*cp == ':')		/* end of tty name list */
X			break;
X
X		if (*cp == ',')		/* end of current tty name */
X			*cp++ = '\0';
X	}
X	*cp++ = 0;
X	port.pt_names[j + 1] = (char *) 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) {
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;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, j;
X	struct	port	*port;
X
X	setttyent ();
X
X	while (port = getttyent ()) {
X		if (port->pt_names == 0 || port->pt_users == 0)
X			continue;
X
X		for (i = 0;port->pt_names[i];i++)
X			if (strcmp (port->pt_names[i], tty) == 0 ||
X					strcmp (port->pt_names[i], "*") == 0)
X				break;
X
X		if (port->pt_names[i] == 0)
X			continue;
X
X		for (j = 0;port->pt_users[j];j++)
X			if (strcmp (user, port->pt_users[j]) == 0 ||
X					strcmp (port->pt_users[j], "*") == 0)
X				break;
X
X		if (port->pt_users[j] != 0)
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 (port, id)))
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 8978 -ne "`wc -c < 'port.c'`"
then
	echo shar: "error transmitting 'port.c'" '(should have been 8978 characters)'
fi
fi
echo shar: "extracting 'lmain.c'" '(13146 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
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#include <syslog.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#define	bzero(a,n)	memset(a, 0, n);
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#include "shadow.h"
X
X#ifndef	lint
Xstatic	char	sccsid[] = "%W%	%U%	%G%";
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
X#ifdef	UT_HOST
Xchar	host[BUFSIZ];
X#endif
X#ifdef	HUSHLOGIN
Xint	hushed;
X#endif
X
Xstruct	passwd	pwent;
Xstruct	utmp	utent;
Xstruct	lastlog	lastlog;
Xint	pflg;
Xint	rflg;
Xint	fflg;
Xint	hflg;
X#ifndef	BSD
Xstruct	termio	termio;
X#endif
X
X#ifndef	MAXENV
X#define	MAXENV	64
X#endif
X
X/*
X * Global variables.
X */
X
Xchar	*newenvp[MAXENV];
Xchar	*Prog;
Xint	newenvc = 0;
Xint	maxenv = MAXENV;
X
X/*
X * External identifiers.
X */
X
Xextern	char	*getenv ();
Xextern	char	*getpass ();
Xextern	void	checkutmp ();
Xextern	void	addenv ();
Xextern	void	setenv ();
Xextern	unsigned alarm ();
Xextern	void	login ();
Xextern	void	entry ();
Xextern	void	setutmp ();
Xextern	void	subsystem ();
Xextern	void	log ();
Xextern	void	setup ();
Xextern	int	expire ();
Xextern	void	motd ();
Xextern	void	mailcheck ();
Xextern	void	shell ();
Xextern	long	a64l ();
Xextern	int	c64i ();
Xextern	int	optind;
Xextern	char	*optarg;
Xextern	char	**environ;
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
X#ifdef	FTMP
Xstruct	utmp	failent;
X#endif
X
X#ifndef	UMASK
X#define	UMASK	0
X#endif
X
X#ifndef	ULIMIT
X#define	ULIMIT	(1L<<21)
X#endif
X
X#define	NO_SHADOW	"no shadow password for `%s' on `%s'\n"
X#define	BAD_PASSWD	"invalid password for `%s' on `%s'\n"
X#define	BAD_DIALUP	"invalid dialup password for `%s' on `%s'\n"
X#define	BAD_TIME	"invalid login time for `%s' on `%s'\n"
X#define	BAD_ROOT_LOGIN	"ILLEGAL ROOT LOGIN ON TTY `%s'\n"
X#define	ROOT_LOGIN	"ROOT LOGIN ON TTY `%s'\n"
X#define	FAILURE_CNT	"exceeded failure limit for `%s' on `%s'\n"
X#define	NOT_A_TTY	"not a tty\n"
X#define	NOT_ROOT	"-r or -f flag and not ROOT on `%s'\n"
X
X/*
X * usage - print login command usage and exit
X */
X
Xusage ()
X{
X	fprintf (stderr, "usage: login [ -p ] [ name ]\n");
X#ifdef	UT_HOST
X	fprintf (stderr, "       login -r name\n");
X	fprintf (stderr, "       login [ -p ] -f name [ -h host ]\n");
X#else
X	fprintf (stderr, "       login [ -p ] -f name\n");
X#endif
X	exit (1);
X}
X
X/*
X * login - create a new login session for a user
X *
X *	login is typically called by getty as the second step of a
X *	new user session.  getty is responsible for setting the line
X *	characteristics to a reasonable set of values and getting
X *	the name of the user to be logged in.  login may also be
X *	called to create a new user session on a pty for a variety
X *	of reasons, such as X servers or network logins.
X *
X *	the flags which login supports are
X *	
X *	-p - preserve the environment
X *	-r - perform autologin protocol for rlogin
X *	-f - do not perform authentication, user is preauthenticated
X *	-h - the name of the remote host
X */
X
Xint
Xmain (argc, argv, envp)
Xint	argc;
Xchar	**argv;
Xchar	**envp;
X{
X	char	name[32];
X	char	pass[32];
X	char	hush[BUFSIZ];
X	char	tty[BUFSIZ];
X	int	retries;
X	int	failed;
X	int	flag;
X	int	subroot = 0;
X	char	*cp;
X	struct	passwd	*pwd;
X	struct	spwd	*spwd;
X	struct	spwd	*getspnam();
X#ifdef	CONSOLE
X	int	conflag;
X	char	console[BUFSIZ];
X	FILE	*fp;
X	struct	stat	statbuf;
X#endif	/* CONSOLE */
X
X	/*
X	 * Some quick initialization.
X	 */
X
X	name[0] = '\0';
X
X	/*
X	 * Get the utmp file entry and get the tty name from it.  The
X	 * current process ID must match the process ID in the utmp
X	 * file if there are no additional flags on the command line.
X	 */
X
X	checkutmp (argc > 1 && argv[1][0] != '-');
X	strncpy (tty, utent.ut_line, sizeof tty);
X	tty[sizeof tty - 1] = '\0';
X
X	if (Prog = strrchr (argv[0], '/'))
X		Prog++;
X	else
X		Prog = argv[0];
X
X#ifdef	UT_HOST
X	while ((flag = getopt (argc, argv, "pr:f:h:")) != EOF)
X#else
X	while ((flag = getopt (argc, argv, "pf:")) != EOF)
X#endif
X	{
X		switch (flag) {
X			case 'p': pflg++;
X				break;
X			case 'f': fflg++;
X				strncpy (name, optarg, sizeof name);
X				break;
X#ifdef	UT_HOST
X			case 'r': rflg++;
X				strncpy (name, optarg, sizeof name);
X				break;
X			case 'h': hflg++;
X				strncpy (host, optarg, sizeof host);
X				strncpy (utmp.ut_host, host,
X							sizeof utmp.ut_host);
X				break;
X#endif
X			default:
X				usage ();
X		}
X	}
X
X	/*
X	 * The -r option is not valid with any other flags
X	 */
X
X	if (rflg && (hflg || fflg || pflg))
X		usage ();
X
X	openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
X
X	/*
X	 * The -r and -f flags both require the real UID to be
X	 * zero.  No authentication may be required for these
X	 * flags, so the user must already be root.
X	 */
X
X	if ((rflg || fflg) && getuid () != 0)
X		exit (1);		/* only root can use -r or -f */
X
X	if (! isatty (0) || ! isatty (1) || ! isatty (2))
X		exit (1);		/* must be a terminal */
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	/* !BSD */
X	umask (UMASK);			/* set the default umask */
X	ulimit (2, (long) ULIMIT);	/* set the default ulimit */
X
X	/*
X	 * The entire environment will be preserved if the -p flag
X	 * is used.
X	 */
X
X	if (pflg)
X		while (*envp)		/* add inherited environment, */
X			addenv (*envp++); /* some variables change later */
X
X#ifdef	TZ
X	if (! pflg) {
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	}
X#endif	/* TZ */
X#ifdef	HZ
X	if (! pflg)
X		addenv (HZ);		/* set the default $HZ, if one */
X#endif	/* HZ */
X	if (optind < argc) {	/* now set command line variables */
X		if (optind + 1 < argc)
X			setenv (argc - optind - 1, &argv[optind + 1]);
X
X		(void) strncpy (name, argv[optind], sizeof name);
X	}
Xtop:
X	(void) alarm (ALARM);		/* only allow ALARM sec. for login */
X
X	retries = RETRIES;
X	while (1) {	/* repeatedly get login/password pairs */
X		pass[0] = '\0';
X
X		if (! name[0]) {	/* need to get a login id */
X			if (subroot)
X				exit (1);
X
X			rflg = fflg = 0;
X			login (name);
X			continue;
X		}
X		if (! (pwd = getpwnam (name)))
X			pwent.pw_name = (char *) 0;
X		else
X			pwent = *pwd;
X
X		if (pwent.pw_name) {
X			if (! (spwd = getspnam (name)))
X				syslog (LOG_WARN, NO_SHADOW, name, tty);
X			else
X				pwent.pw_passwd = spwd->sp_pwdp;
X			failed = 0;	/* hasn't failed validation yet */
X		} else
X			failed = 1;	/* will never pass validation */
X
X		/*
X		 * The -r and -f flags provide a name which has already
X		 * been authenticated by some server.
X		 */
X
X		if (pwent.pw_name && (rflg || fflg))
X			goto have_name;
X
X	/*
X	 * Get the user's password.  One will only be prompted for
X	 * if the pw_passwd (or sp_passwd) field is non-blank.  It
X	 * will then be checked against the password entry, along
X	 * with other options which prevent logins.
X	 */
X		cp = 0;
X		if ((! pwent.pw_name || (strlen (pwent.pw_passwd) > 0))
X				&& ! (cp = getpass ("Password:")))
X			continue;
X
X		if (cp)
X			strncpy (pass, cp, sizeof pass);
X
X		if (! valid (pass, &pwent)) { /* check encrypted passwords */
X			syslog (LOG_WARN, BAD_PASSWD, name, tty);
X			failed = 1;
X		}
X		bzero (pass, sizeof pass);
X
X		/*
X		 * This is the point where password-authenticated users
X		 * wind up.  If you reach this far, your password has
X		 * been authenticated and so on.
X		 */
X
Xhave_name:
X#ifdef	DIALUP
X		alarm (30);
X		if (pwent.pw_name && ! dialcheck (tty,
X				pwent.pw_shell[0] ? pwent.pw_shell:"/bin/sh")) {
X			syslog (LOG_WARN, BAD_DIALUP, name, tty);
X			failed = 1;
X		}
X#endif	/* DIALUP */
X#ifdef	PORTTIME
X		if (pwent.pw_name &&
X			! isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
X			syslog (LOG_WARN, BAD_TIME, name, tty);
X			failed = 1;
X		}
X#endif	/* PORTTIME */
X#ifdef	CONSOLE
X		if (! failed && pwent.pw_name &&
X			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, tty))
X						break;
X				}
X				if (! fp || feof (fp))
X					failed = 1;
X
X				fclose (fp);
X			} else {
X				if (strcmp (CONSOLE, tty))
X					failed = 1;
X			}
X			if (failed)
X				syslog (LOG_CRIT, BAD_ROOT_LOGIN, tty);
X		}
X#endif	/* CONSOLE */
X#ifdef	FAILLOG
X		if (pwent.pw_name &&
X			! failcheck (pwent.pw_uid, &faillog, failed)) {
X			syslog (LOG_CRIT, FAILURE_CNT, name, tty);
X			failed = 1;
X		}
X#endif	/* FAILLOG */
X		if (! failed)
X			break;
X
X		puts ("Login incorrect");
X		if (rflg || fflg)
X			exit (1);
X#ifdef	FAILLOG
X		if (pwent.pw_name)	/* don't log non-existent users */
X			failure (pwent.pw_uid, tty, &faillog);
X#endif	/* FAILLOG */
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	/* !UNKNOWNS */
X			strcpy (failent.ut_name, "UNKNOWN");
X#endif	/* UNKNOWNS */
X		time (&failent.ut_time);
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		bzero (name, sizeof name);
X		bzero (pass, sizeof pass);
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		FILE	*fp;
X		int	c;
X
X		if (fp = fopen (NOLOGINS, "r")) {
X			while ((c = getc (fp)) != EOF) {
X				if (c == '\n')
X					putchar ('\r');
X
X				putchar (c);
X			}
X			fflush (stdout);
X			fclose (fp);
X		} else
X			printf ("\r\nSystem closed for routine maintenance\n");
X
X		exit (0);
X	}
X#endif	/* NOLOGINS */
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 (name, tty);		/* make entry in utmp & wtmp files */
X	if (pwent.pw_shell[0] == '*') {	/* subsystem root */
X		subsystem (&pwent);	/* figure out what to execute */
X		subroot++;		/* say i was here again */
X		endpwent ();		/* close all of the file which were */
X		endgrent ();		/* open in the original rooted file */
X		endspent ();		/* system.  they will be re-opened */
X		endsgent ();		/* in the new rooted file system */
X		goto top;		/* go do all this all over again */
X	}
X
X#ifdef	LASTLOG
X	log ();				/* give last login and log this one */
X#endif	/* LASTLOG */
X	setup (&pwent);			/* set UID, GID, HOME, etc ... */
X#ifdef	AGING
X	if (spwd) {			/* check for age of password */
X		if (expire (&pwent, spwd)) {
X			spwd = getspnam (name);
X			pwd = getpwnam (name);
X			pwent = *pwd;
X		}
X	}
X#ifdef	ATT_AGE
X	else if (pwent.pw_age && pwent.pw_age[0]) {
X		if (expire (&pwent, (void *) 0)) {
X			pwd = getpwnam (name);
X			pwent = *pwd;
X		}
X	}
X#endif	/* ATT_AGE */
X#endif	/* AGING */
X#ifdef	HUSHLOGIN
X	sprintf (hush, "%s/.hushlogin", pwent.pw_dir, 0);
X	hushed = access (hush, 0) == 0;
X#endif	/* HUSHLOGIN */
X#ifdef	MOTD
X	if (! hushed)
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	/* FAILLOG */
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	/* LASTLOG */
X#ifdef	AGING
X	if (! hushed)
X		agecheck (&pwent, spwd);
X#endif	/* AGING */
X#ifdef	MAILCHECK
X	if (! hushed)
X		mailcheck ();		/* report on the status of mail */
X#endif	/* MAILCHECK */
X#ifdef	TTYTYPE
X	if (! pflg)
X		ttytype (tty);
X#endif	/* TTYTYPE */
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	endpwent ();			/* stop access to password file */
X	endgrent ();			/* stop access to group file */
X	endspent ();			/* stop access to shadow passwd file */
X	endsgent ();			/* stop access to shadow group file */
X
X	if (pwent.pw_uid == 0)
X		syslog (LOG_INFO, ROOT_LOGIN, tty);
X
X	shell (pwent.pw_shell, (char *) 0); /* exec the shell finally. */
X	/*NOTREACHED*/
X}
SHAR_EOF
if test 13146 -ne "`wc -c < 'lmain.c'`"
then
	echo shar: "error transmitting 'lmain.c'" '(should have been 13146 characters)'
fi
fi
echo shar: "extracting 'mkpasswd.c'" '(8207 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
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#define	strchr	index
X#define	strrchr	rindex
X#else
X#include <string.h>
X#endif
X
X#if !defined(DBM) && !defined(NDBM)
XWhat 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#ifdef	NDBM
X#include <ndbm.h>
X#include <grp.h>
X#include "shadow.h"
X
XDBM	*pw_dbm;
XDBM	*gr_dbm;
XDBM	*sp_dbm;
XDBM	*sgr_dbm;
X#endif
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)mkpasswd.c	3.4	11:29:08	12/19/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_REC =	"adding record for name \"%s\"\n";
Xchar	*ADD_REC_ERR =	"%s: error adding record for \"%s\"\n";
Xchar	*INFO =		"added %d entries, longest was %d\n";
X#ifdef	NDBM
Xchar	*USAGE =	"Usage: %s [ -vf ] [ -p|g|sp|sg ] file\n";
X#else
Xchar	*USAGE =	"Usage: %s [ -vf ] file\n";
X#endif
X
Xchar	*Progname;
Xint	vflg = 0;
Xint	fflg = 0;
X#ifdef	NDBM
Xint	gflg = 0;
Xint	sflg = 0;
Xint	pflg = 0;
X#endif
X
Xvoid	usage();
X
Xextern	char	*malloc();
Xextern	struct	passwd	*sgetpwent();
X#ifdef	NDBM
Xextern	struct	group	*sgetgrent();
Xextern	struct	spwd	*sgetspent();
Xextern	struct	sgrp	*sgetsgent();
X#endif
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 * if NDBM is defined this command will also create look-aside files for
X * /etc/group, /etc/shadow, and /etc/gshadow.
X */
X
Xint
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	extern	int	optind;
X	extern	char	*optarg;
X	FILE	*fp;			/* File pointer for input file        */
X	char	*file;			/* Name of input file                 */
X	char	*dir;			/* Name of .dir file                  */
X	char	*pag;			/* 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	len;			/* Length of input line               */
X	int	errors = 0;		/* Count of errors processing file    */
X	char	buf[BUFSIZ*8];		/* Input line from file               */
X	struct	passwd	*passwd;	/* Pointer to password file entry     */
X#ifdef	NDBM
X	struct	group	*group;		/* Pointer to group file entry        */
X	struct	spwd	*shadow;	/* Pointer to shadow passwd entry     */
X	struct	sgrp	*gshadow;	/* Pointer to shadow group entry      */
X	DBM	*dbm;			/* Pointer to new NDBM files          */
X#endif
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#ifdef	NDBM
X	while ((flag = getopt (argc, argv, "fvpgs")) != EOF)
X#else
X	while ((flag = getopt (argc, argv, "fv")) != EOF)
X#endif
X	{
X		switch (flag) {
X			case 'v':
X				vflg++;
X				break;
X			case 'f':
X				fflg++;
X				break;
X#ifdef	NDBM
X			case 'g':
X				gflg++;
X				if (pflg)
X					usage ();
X
X				break;
X			case 's':
X				sflg++;
X				break;
X			case 'p':
X				pflg++;
X				if (gflg)
X					usage ();
X
X				break;
X#endif
X			default:
X				usage ();
X		}
X	}
X
X	/*
X	 * Backwards compatibility fix for -p flag ...
X	 */
X
X	if (! sflg && ! gflg)
X		pflg++;
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	file = argv[optind];
X
X	if (! (fp = fopen (file, "r"))) {
X		fprintf (stderr, CANT_OPEN, Progname, file);
X		exit (1);
X	}
X
X	/*
X	 * Make the filenames for the two DBM files.
X	 */
X
X	dir = malloc (strlen (file) + 5);	/* space for .dir file */
X	strcat (strcpy (dir, file), ".dir");
X
X	pag = malloc (strlen (file) + 5);	/* space for .pag file */
X	strcat (strcpy (pag, file), ".pag");
X
X	/*
X	 * Remove existing files if requested.
X	 */
X
X	if (fflg) {
X		(void) unlink (dir);
X		(void) unlink (pag);
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 (dir, 0) == 0) {
X		fprintf (stderr, CANT_OVERWRITE, Progname, dir);
X		exit (1);
X	}
X	if (access (pag, 0) == 0) {
X		fprintf (stderr, CANT_OVERWRITE, Progname, pag);
X		exit (1);
X	}
X
X#ifdef	NDBM
X	if (sflg)
X		umask (077);
X	else
X#endif
X	umask (0);
X#ifdef	DBM
X	if ((fd = open (dir, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
X		fprintf (stderr, CANT_CREATE, Progname, dir);
X		exit (1);
X	} else
X		close (fd);
X
X	if ((fd = open (pag, O_RDWR|O_CREAT|O_EXCL, 0644)) == -1) {
X		fprintf (stderr, CANT_CREATE, Progname, pag);
X		unlink (dir);
X		exit (1);
X	} else
X		close (fd);
X#endif
X
X	/*
X	 * Now the DBM database gets initialized
X	 */
X
X#ifdef	DBM
X	if (dbminit (file) == -1) {
X		fprintf (stderr, DBM_OPEN_ERR, Progname, file);
X		exit (1);
X	}
X#endif
X#ifdef	NDBM
X	if (! (dbm = dbm_open (file, O_RDWR|O_CREAT, 0644))) {
X		fprintf (stderr, DBM_OPEN_ERR, Progname, file);
X		exit (1);
X	}
X	if (gflg) {
X		if (sflg)
X			sgr_dbm = dbm;
X		else
X			gr_dbm = dbm;
X	} else {
X		if (sflg)
X			sp_dbm = dbm;
X		else
X			pw_dbm = dbm;
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#ifdef	NDBM
X	while (fgetsx (buf, BUFSIZ, fp) != NULL)
X#else
X	while (fgets (buf, BUFSIZ, fp) != NULL)
X#endif
X	{
X
X		/*
X		 * Get the next line and strip off the trailing newline
X		 * character.
X		 */
X
X		buf[sizeof buf - 1] = '\0';
X		if (! (cp = strchr (buf, '\n'))) {
X			fprintf (stderr, LINE_TOO_LONG, Progname, buf);
X			exit (1);
X		}
X		*cp = '\0';
X		len = strlen (buf);
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#ifdef	DBM
X		if (! (passwd = sgetpwent (buf)))
X#endif
X#ifdef	NDBM
X		if (! (((! sflg && pflg) && (passwd = sgetpwent (buf)))
X			|| ((sflg && pflg) && (shadow = sgetspent (buf)))
X			|| ((! sflg && gflg) && (group = sgetgrent (buf)))
X			|| ((sflg && gflg) && (gshadow = sgetsgent (buf)))))
X#endif
X		{
X			fprintf (stderr, PARSE_ERR, Progname, buf);
X			errors++;
X			continue;
X		}
X#ifdef	DBM
X		if (vflg)
X			printf (ADD_REC, passwd->pw_name);
X
X		if (! pw_dbm_update (passwd))
X			fprintf (stderr, ADD_REC_ERR,
X				Progname, passwd->pw_name);
X#endif
X#ifdef	NDBM
X		if (vflg) {
X			if (!sflg && pflg) printf (ADD_REC, passwd->pw_name);
X			if (sflg && pflg) printf (ADD_REC, shadow->sp_namp);
X			if (!sflg && gflg) printf (ADD_REC, group->gr_name);
X			if (sflg && gflg) printf (ADD_REC, gshadow->sg_name);
X		}
X		if (! sflg && pflg && ! pw_dbm_update (passwd))
X			fprintf (stderr, ADD_REC_ERR,
X				Progname, passwd->pw_name);
X
X		if (sflg && pflg && ! sp_dbm_update (shadow))
X			fprintf (stderr, ADD_REC_ERR,
X				Progname, shadow->sp_namp);
X
X		if (! sflg && gflg && ! gr_dbm_update (group))
X			fprintf (stderr, ADD_REC_ERR,
X				Progname, group->gr_name);
X
X		if (sflg && gflg && ! sgr_dbm_update (gshadow))
X			fprintf (stderr, ADD_REC_ERR,
X				Progname, gshadow->sg_name);
X#endif
X
X		/*
X		 * Update the longest record and record count
X		 */
X
X		if (len > longest)
X			longest = len;
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 8207 -ne "`wc -c < 'mkpasswd.c'`"
then
	echo shar: "error transmitting 'mkpasswd.c'" '(should have been 8207 characters)'
fi
fi
echo shar: "extracting 'sulogin.c'" '(3501 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include "pwd.h"
X#include <utmp.h>
X#ifdef	BSD
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#else
X#include <string.h>
X#include <memory.h>
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)sulogin.c	3.3	12:31:35	12/12/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[BUFSIZ] = 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) || ! isatty (1) || ! isatty (2))
X		exit (1);		/* must be a terminal */
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	/* TZ */
X#ifdef	HZ
X	addenv (HZ);			/* set the default $HZ, if one */
X#endif	/* HZ */
X	(void) strcpy (name, "root");	/* KLUDGE!!! */
X
X	alarm (ALARM);		/* only wait so long ... */
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 (! (cp = getpass ("Type control-d for normal startup,\n\
X(or give root password for system maintenance):")))
X			exit (0);
X		else
X			strcpy (pass, cp);
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, (char *) 0); /* exec the shell finally. */
X	/*NOTREACHED*/
X}
SHAR_EOF
if test 3501 -ne "`wc -c < 'sulogin.c'`"
then
	echo shar: "error transmitting 'sulogin.c'" '(should have been 3501 characters)'
fi
fi
echo shar: "extracting 'pwpack.c'" '(2994 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <stdio.h>
X#include "pwd.h"
X#ifdef	BSD
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#else
X#include <string.h>
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)pwpack.c	3.3	12:31:23	12/12/90";
X#endif
X
X/*
X * pw_pack - convert a (struct pwd) to a packed record
X */
X
Xint
Xpw_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#ifdef	ATT_AGE
X	if (passwd->pw_age[0]) {
X		*cp++ = ',';
X		strcat (cp, passwd->pw_age);
X	}
X#endif
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#ifdef	BSD_QUOTAS
X	memcpy (cp, (void *) &passwd->pw_quota, sizeof passwd->pw_quota);
X	cp += sizeof passwd->pw_quota;
X#endif
X#ifdef	ATT_COMMENT
X	if (passwd->pw_comment) {
X		strcpy (cp, passwd->pw_comment);
X		cp += strlen (cp) + 1;
X	} else
X		*cp++ = '\0';
X#endif
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
X/*
X * pw_unpack - convert a packed (struct pwd) record to a (struct pwd)
X */
X
Xint
Xpw_unpack (buf, len, passwd)
Xchar	*buf;
Xint	len;
Xstruct	passwd	*passwd;
X{
X	char	*org = buf;
X	char	*cp;
X
X	memset ((void *) passwd, 0, sizeof *passwd);
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#ifdef	ATT_AGE
X	if (cp = strchr (passwd->pw_passwd, ',')) {
X		*cp++ = '\0';
X		passwd->pw_age = cp;
X	} else
X		passwd->pw_age = "";
X#endif
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#ifdef	BSD_QUOTAS
X	memcpy ((void *) &passwd->pw_quota, (void *) buf,
X		sizeof passwd->pw_quota);
X	buf += sizeof passwd->pw_quota;
X	if (buf - org > len)
X		return -1;
X#endif
X#ifdef	ATT_COMMENT
X	passwd->pw_comment = buf;
X	buf += strlen (buf) + 1;
X	if (buf - org > len)
X		return -1;
X#endif
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 2994 -ne "`wc -c < 'pwpack.c'`"
then
	echo shar: "error transmitting 'pwpack.c'" '(should have been 2994 characters)'
fi
fi
echo shar: "extracting 'dialup.c'" '(2631 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
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	3.3	19:44:20	12/10/90";
X#endif
X
Xstatic	FILE	*dialpwd;
X
Xvoid
Xsetduent ()
X{
X	if (dialpwd)
X		rewind (dialpwd);
X	else
X		dialpwd = fopen (DIALPWD, "r");
X}
X
Xvoid
Xendduent ()
X{
X	if (dialpwd)
X		fclose (dialpwd);
X
X	dialpwd = (FILE *) 0;
X}
X
Xstruct dialup *
Xfgetduent (fp)
XFILE	*fp;
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 (! fp)
X		return 0;
X
X	if (! fp || feof (fp))
X		return ((struct dialup *) 0);
X
X	while (fgets (buf, BUFSIZ, fp) == buf && buf[0] == '#')
X		;
X
X	if (feof (fp))
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 *
Xgetduent ()
X{
X	if (! dialpwd)
X		setduent ();
X
X	return fgetduent (dialpwd);
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}
X
Xint
Xputduent (dial, fp)
Xstruct	dialup	*dial;
XFILE	*fp;
X{
X	if (! fp || ! dial)
X		return -1;
X
X	if (fprintf (fp, "%s:%s\n", dial->du_shell, dial->du_passwd) == EOF)
X		return -1;
X
X	return 0;
X}
SHAR_EOF
if test 2631 -ne "`wc -c < 'dialup.c'`"
then
	echo shar: "error transmitting 'dialup.c'" '(should have been 2631 characters)'
fi
fi
echo shar: "extracting 'sulog.c'" '(1168 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	3.1	09:22:38	11/21/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 1168 -ne "`wc -c < 'sulog.c'`"
then
	echo shar: "error transmitting 'sulog.c'" '(should have been 1168 characters)'
fi
fi
echo shar: "extracting 'getpass.c'" '(3390 characters)'
if test -f 'getpass.c'
then
	echo shar: "will not over-write existing file 'getpass.c'"
else
sed 's/^X//' << \SHAR_EOF > 'getpass.c'
X/*
X * Copyright 1990, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <sys/signal.h>
X#include <stdio.h>
X#include "config.h"
X
X#ifdef	BSD
X#include <sgtty.h>
X#include <strings.h>
X#else
X#include <termio.h>
X#include <string.h>
X#endif
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)getpass.c	3.2	08:19:03	2/5/91";
X#endif
X
X/*
X * limits.h may be kind enough to specify the length of a prompted
X * for password.
X */
X
X#if defined(__STDC__) || defined(_POSIX_SOURCE)
X#include <limits.h>
X#endif
X
X/*
X * This is really a giant mess.  On the one hand, it would be nice
X * if PASS_MAX were real big so that DOUBLESIZE isn't needed.  But
X * if it is defined we must honor it because some idiot might use
X * this in a routine expecting some standard behavior.
X */
X
X#ifndef	PASS_MAX
X#ifdef	DOUBLESIZE
X#define	PASS_MAX	16
X#else
X#define	PASS_MAX	8
X#endif
X#endif
X
X#ifdef	BSD
X#define	STTY(fd,termio)	stty(fd, termio)
X#define	GTTY(fd,termio) gtty(fd, termio)
X#define	TERMIO	struct	sgttyb
X#define	INDEX	index
X#else
X#define	STTY(fd,termio) ioctl(fd, TCSETA, termio)
X#define	GTTY(fd,termio) ioctl(fd, TCGETA, termio)
X#define	TERMIO	struct	termio
X#define	INDEX	strchr
X#endif
X
Xstatic	int	sig_caught;
X
Xstatic void
Xsig_catch ()
X{
X	sig_caught = 1;
X}
X
Xchar *
Xgetpass (prompt)
Xchar	*prompt;
X{
X	static	char	input[PASS_MAX+1];
X	char	*return_value = 0;
X	char	*cp;
X	FILE	*fp;
X	int	tty_opened = 0;
X	void	(*old_signal)();
X	TERMIO	new_modes;
X	TERMIO	old_modes;
X
X	/*
X	 * set a flag so the SIGINT signal can be re-sent if it
X	 * is caught
X	 */
X
X	sig_caught = 0;
X
X	/*
X	 * if /dev/tty can't be opened, getpass() needs to read
X	 * from stdin instead.
X	 */
X
X	if ((fp = fopen ("/dev/tty", "r")) == 0) {
X		fp = stdin;
X		setbuf (fp, (char *) 0);
X	} else {
X		tty_opened = 1;
X	}
X
X	/*
X	 * the current tty modes must be saved so they can be
X	 * restored later on.  echo will be turned off, except
X	 * for the newline character (BSD has to punt on this)
X	 */
X
X	if (GTTY (fileno (fp), &new_modes))
X		return 0;
X
X	old_modes = new_modes;
X	old_signal = signal (SIGINT, sig_catch);
X
X#ifdef	BSD
X	new_modes.sg_flags &= ~ECHO ;
X#else
X	new_modes.c_lflag &= ~(ECHO|ECHOE|ECHOK);
X	new_modes.c_lflag |= ECHONL;
X#endif
X
X	if (STTY (fileno (fp), &new_modes))
X		goto out;
X
X	/*
X	 * the prompt is output, and the response read without
X	 * echoing.  the trailing newline must be removed.  if
X	 * the fgets() returns an error, a NULL pointer is
X	 * returned.
X	 */
X
X	if (fputs (prompt, stdout) == EOF)
X		goto out;
X
X	if (fgets (input, sizeof input, fp) == input) {
X		if (cp = INDEX (input, '\n'))
X			*cp = '\0';
X		else
X			input[sizeof input - 1] = '\0';
X
X		return_value = input;
X#ifdef	BSD
X		putc ('\n', stdout);
X#endif
X	}
Xout:
X	/*
X	 * the old SIGINT handler is restored after the tty
X	 * modes.  then /dev/tty is closed if it was opened in
X	 * the beginning.  finally, if a signal was caught it
X	 * is sent to this process for normal processing.
X	 */
X
X	if (STTY (fileno (fp), &old_modes))
X		return_value = 0;
X
X	signal (SIGINT, old_signal);
X
X	if (tty_opened)
X		fclose (fp);
X
X	if (sig_caught) {
X		kill (getpid (), SIGINT);
X		return_value = 0;
X	}
X	return return_value;
X}
SHAR_EOF
if test 3390 -ne "`wc -c < 'getpass.c'`"
then
	echo shar: "error transmitting 'getpass.c'" '(should have been 3390 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
John F. Haugh II        | Distribution to  | UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) |  Domain: jfh at rpp386.cactus.org
"If liberals interpreted the 2nd Amendment the same way they interpret the
 rest of the Constitution, gun ownership would be mandatory."



More information about the Alt.sources mailing list