#! /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 
X#include 
X#include 
X#include 
X#include 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifdef	DBM
X#include 
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 
X#include 
X#include 
X#include 
X#include 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifdef	DBM
X#include 
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 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#include 
X#else
X#include 
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include 
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 
X#include 
X#include 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X#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 
X#include 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#else
X#define	strchr	index
X#define	strrchr	rindex
X#include 
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 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "faillog.h"
X#include "config.h"
X
X#ifdef	FTMP
X#include 
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 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include 
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 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
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 
X#include 
X#include 
X#include 
X#include 
X#ifndef	BSD
X#include 
X#include 
X#else
X#include 
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)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