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