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

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


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	gpmain.c
#	chage.c
#	pwent.c
#	valid.c
#	setup.c
#	entry.c
#	ttytype.c
#	port.h
# This archive created: Sun Mar  3 13:27:23 1991
# By:	John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'gpmain.c'" '(9448 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include "pwd.h"
X#include <grp.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <errno.h>
X#ifndef	BSD
X#include <termio.h>
X#ifdef SYS3
X#include <sys/ioctl.h>
X#endif
X#include <string.h>
X#ifndef	SYS3
X#include <memory.h>
X#endif
X#else
X#include <sgtty.h>
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifndef	PASSLENGTH
X#define	PASSLENGTH	5
X#endif
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)gpmain.c	3.4	12:30:43	12/12/90";
X#endif
X
Xchar	name[BUFSIZ];
Xchar	pass[BUFSIZ];
Xchar	pass2[BUFSIZ];
X
Xstruct	group	grent;
X
Xchar	*Prog;
Xchar	*user;
Xchar	*group;
Xint	aflg;
Xint	dflg;
Xint	rflg;
Xint	Rflg;
X
X#ifndef	RETRIES
X#define	RETRIES	3
X#endif
X
Xextern	char	*l64a ();
Xextern	char	*crypt ();
Xextern	char	*pw_encrypt ();
Xextern	int	errno;
Xextern	long	a64l ();
Xextern	void	entry ();
Xextern	time_t	time ();
X
X/*
X * usage - display usage message
X */
X
Xvoid
Xusage ()
X{
X	fprintf (stderr, "usage: %s [ -r|R ] group\n", Prog);
X	fprintf (stderr, "       %s [ -a user ] group\n", Prog);
X	fprintf (stderr, "       %s [ -d user ] group\n", Prog);
X	exit (1);
X}
X
X/*
X * add_list - add a member to a list of group members
X *
X *	the array of member names is searched for the new member
X *	name, and if not present it is added to a freshly allocated
X *	list of users.
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
X	tmp[i] = (char *) 0;
X	return tmp;
X}
X
X/*
X * del_list - delete a group member from a list of members
X *
X *	del_list searches a list of group members, copying the
X *	members which do not match "member" to a newly allocated
X *	list.
X */
X
Xchar **
Xdel_list (list, member)
Xchar	**list;
Xchar	*member;
X{
X	int	i, j;
X	char	**tmp;
X
X	for (j = i = 0;list[i] != (char *) 0;i++)
X		if (strcmp (list[i], member))
X			j++;
X
X	tmp = (char **) malloc ((j + 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	retries;
X	int	ruid = getuid();
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
X	/*
X	 * Make a note of whether or not this command was invoked
X	 * by root.  This will be used to bypass certain checks
X	 * later on.  Also, set the real user ID to match the
X	 * effective user ID.  This will prevent the invoker from
X	 * issuing signals which would interfer with this command.
X	 */
X
X	amroot = getuid () == 0;
X	setuid (geteuid ());
X	Prog = argv[0];
X	setbuf (stdout, (char *) 0);
X	setbuf (stderr, (char *) 0);
X
X	while ((flag = getopt (argc, argv, "a:d:grR")) != EOF) {
X		switch (flag) {
X			case 'a':	/* add a user */
X				aflg++;
X				user = optarg;
X				break;
X			case 'd':	/* delete a user */
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			case 'R':	/* restrict group password */
X				Rflg++;
X				break;
X			default:
X				usage ();
X		}
X	}
X
X	/*
X	 * Make sure exclusive flags are exclusive
X	 */
X
X	if (aflg + dflg + rflg + Rflg > 1)
X		usage ();
X
X	/*
X	 * Unless the mode is -a, -d or -r, the input and output must
X	 * both be a tty.  The typical keyboard signals are caught
X	 * so the termio modes can be restored.
X	 */
X
X	if (! aflg && ! dflg && ! rflg && ! Rflg) {
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
X	/*
X	 * Determine the name of the user that invoked this command.
X	 * This is really hit or miss because there are so many ways
X	 * that command can be executed and so many ways to trip up
X	 * the routines that report the user name.
X	 */
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	/*
X	 * Get the name of the group that is being affected.  The group
X	 * entry will be completely replicated so it may be modified
X	 * later on.
X	 */
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	/*
X	 * The policy for changing a group is that 1) you must be root
X	 * or 2) you must be the first listed member of the group.  The
X	 * first listed member of a group can do anything to that group
X	 * that the root user can.
X	 */
X
X	if (! amroot) {
X		if (grent.gr_mem[0] == (char *) 0)
X			goto failure;
X
X		if (strcmp (grent.gr_mem[0], name) != 0)
X			goto failure;
X	}
X
X	/*
X	 * Removing a password is straight forward.  Just set the
X	 * password field to a "".
X	 */
X
X	if (rflg) {
X		grent.gr_passwd = "";
X		goto output;
X	} else if (Rflg) {
X		grent.gr_passwd = "!";
X		goto output;
X	}
X
X	/*
X	 * Adding a member to a member list is pretty straightforward
X	 * as well.  Call the appropriate routine and split.
X	 */
X
X	if (aflg) {
X		if (getpwnam (user) == (struct passwd *) 0) {
X			fprintf (stderr, "%s: unknown user %s\n", Prog, user);
X			exit (1);
X		}
X		printf ("Adding user %s to group %s\n", user, group);
X		grent.gr_mem = add_list (grent.gr_mem, user);
X		goto output;
X	}
X
X	/*
X	 * Removing a member from the member list is the same deal
X	 * as adding one, except the routine is different.
X	 */
X
X	if (dflg) {
X		for (i = 0;grent.gr_mem[i];i++)
X			if (strcmp (user, grent.gr_mem[i]) == 0)
X				break;
X
X		if (grent.gr_mem[i] == (char *) 0) {
X			fprintf (stderr, "%s: unknown member %s\n", Prog, user);
X			exit (1);
X		}
X		printf ("Removing user %s from group %s\n", user, group);
X		grent.gr_mem = del_list (grent.gr_mem, user);
X		goto output;
X	}
X
X	/*
X	 * A new password is to be entered and it must be encrypted,
X	 * etc.  The password will be prompted for twice, and both
X	 * entries must be identical.  There is no need to validate
X	 * the old password since the invoker is either the group
X	 * owner, or root.
X	 */
X
X	printf ("Changing the password for group %s\n", group);
X
X	for (retries = 0;retries < RETRIES;retries++) {
X		if (! (cp = getpass ("New Password:")))
X			exit (1);
X		else
X			strcpy (pass, cp);
X
X		if (! (cp = getpass ("Re-enter new password:")))
X			exit (1);
X		else
X			strcpy (pass2, cp);
X
X		if (strcmp (pass, pass2) == 0)
X			break;
X
X		if (retries + 1 < RETRIES)
X			puts ("They don't match; try again");
X	}
X	if (retries == RETRIES) {
X		fprintf (stderr, "%s: Try again later\n", Prog);
X		exit (1);
X	}
X	grent.gr_passwd = pw_encrypt (pass, (char *) 0);
X
X	/*
X	 * This is the common arrival point to output the new group
X	 * file.  The freshly crafted entry is in allocated space.
X	 * The group file will be locked and opened for writing.  The
X	 * new entry will be output, etc.
X	 */
X
Xoutput:
X	signal (SIGHUP, SIG_IGN);
X	signal (SIGINT, SIG_IGN);
X	signal (SIGQUIT, SIG_IGN);
X
X	if (! gr_lock ()) {
X		fprintf (stderr, "%s: can't get lock\n", Prog);
X		exit (1);
X	}
X	if (! gr_open (O_RDWR)) {
X		fprintf (stderr, "%s: can't open file\n", Prog);
X		exit (1);
X	}
X	if (! gr_update (&grent)) {
X		fprintf (stderr, "%s: can't update entry\n", Prog);
X		exit (1);
X	}
X	if (! gr_close ()) {
X		fprintf (stderr, "%s: can't re-write file\n", Prog);
X		exit (1);
X	}
X	if (! gr_unlock ()) {
X		fprintf (stderr, "%s: can't unlock file\n", Prog);
X		exit (1);
X	}
X#ifdef	NDBM
X	if (! gr_dbm_update (&grent)) {
X		fprintf (stderr, "%s: can't update DBM files\n", Prog);
X		exit (1);
X	}
X#endif
X	exit (0);
X	/*NOTREACHED*/
X
Xfailure:
X	fprintf (stderr, "Permission denied.\n");
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 9448 -ne "`wc -c < 'gpmain.c'`"
then
	echo shar: "error transmitting 'gpmain.c'" '(should have been 9448 characters)'
fi
fi
echo shar: "extracting 'chage.c'" '(15243 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <sys/types.h>
X#include <syslog.h>
X#include <stdio.h>
X#include <fcntl.h>
X#include <signal.h>
X#include <ctype.h>
X#include <time.h>
X
X#ifndef	lint
Xstatic	char	sccsid[] = "%W%	%U%	%G%";
X#endif
X
X/*
X * Set up some BSD defines so that all the BSD ifdef's are
X * kept right here 
X */
X
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#define	bzero(a,n)	memset(a, 0, n)
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X
X#include "config.h"
X#include "pwd.h"
X#include "shadow.h"
X
X/*
X * Global variables
X */
X
Xchar	*Prog;
Xlong	mindays;
Xlong	maxdays;
Xlong	lastday;
Xlong	warndays;
Xlong	inactdays;
Xlong	expdays;
Xvoid	cleanup();
X
X/*
X * External identifiers
X */
X
Xextern	long	a64l();
Xextern	int	pw_lock(), pw_open(),
X		pw_unlock(), pw_close(),
X		pw_update();
Xextern	struct	passwd	*pw_locate();
Xextern	int	spw_lock(), spw_open(),
X		spw_unlock(), spw_close(),
X		spw_update();
Xextern	struct	spwd	*spw_locate();
Xextern	int	optind;
Xextern	char	*optarg;
Xextern	char	*getlogin ();
X#ifdef	NDBM
Xextern	int	pw_dbm_mode;
Xextern	int	sp_dbm_mode;
X#endif
X
X/*
X * Password aging constants
X *
X *	DAY - seconds in a day
X *	WEEK - seconds in a week
X *	SCALE - convert from clock to aging units
X */
X
X#define	DAY	(24L*3600L)
X#define	WEEK	(7*DAY)
X
X#ifdef	ITI_AGING
X#define	SCALE	(1)
X#else
X#define	SCALE	(DAY)
X#endif
X
X/*
X * days and juldays are used to compute the number of days in the
X * current month, and the cummulative number of days in the preceding
X * months.  they are declared so that january is 1, not 0.
X */
X
Xstatic	short	days[13] = { 0,
X	31,	28,	31,	30,	31,	30,	/* JAN - JUN */
X	31,	31,	30,	31,	30,	31 };	/* JUL - DEC */
X
Xstatic	short	juldays[13] = { 0,
X	0,	31,	59,	90,	120,	151,	/* JAN - JUN */
X	181,	212,	243,	273,	304,	334 };	/* JUL - DEC */
X
X/*
X * #defines for messages.  This facilities foreign language conversion
X * since all messages are defined right here.
X */
X
X#define	USAGE \
X"Usage: %s [ -l ] [ -m min_days ] [ -M max_days ] [ -W warn ]\n\
X       [ -I inactive ] [ -E expire ] [ -d last_day ] user\n"
X#define	DBMERROR	"Error updating the DBM password entry.\n"
X#define	DBMERROR2	"error updating DBM shadow entry.\n"
X
X/*
X * usage - print command line syntax and exit
X */
X
Xvoid
Xusage ()
X{
X	fprintf (stderr, USAGE, Prog);
X	exit (1);
X}
X
X/*
X * strtoday - compute the number of days since 1970.
X *
X * the total number of days prior to the current date is
X * computed.  january 1, 1970 is used as the origin with
X * it having a day number of 0.  the gmtime() routine is
X * used to prevent confusion regarding time zones.
X */
X
Xlong
Xstrtoday (str)
Xchar	*str;
X{
X	char	slop[2];
X	int	month;
X	int	day;
X	int	year;
X	long	total;
X
X	/*
X	 * start by separating the month, day and year.  this is
X	 * a chauvanistic program - it only takes date input in
X	 * the standard USA format.
X	 */
X
X	if (sscanf (str, "%d/%d/%d%c", &month, &day, &year, slop) != 3)
X		return -1;
X
X	/*
X	 * the month, day of the month, and year are checked for
X	 * correctness and the year adjusted so it falls between
X	 * 1970 and 2069.
X	 */
X
X	if (month < 1 || month > 12)
X		return -1;
X
X	if (day < 1)
X		return -1;
X
X	if ((month != 2 || (year % 4) != 0) && day > days[month])
X		return -1;
X	else if ((month == 2 && (year % 4) == 0) && day > 29)
X		return -1;
X
X	if (year < 0)
X		return -1;
X	else if (year < 69)
X		year += 2000;
X	else if (year < 99)
X		year += 1900;
X
X	if (year < 1970 || year > 2069)
X		return -1;
X
X	/*
X	 * the total number of days is the total number of days in all
X	 * the whole years, plus the number of leap days, plus the
X	 * number of days in the whole months preceding, plus the number
X	 * of days so far in the month.
X	 */
X
X	total = ((year - 1970) * 365) + (((year + 1) - 1970) / 4);
X	total += juldays[month] + (month > 2 && (year % 4) == 0 ? 1:0);
X	total += day - 1;
X
X	return total;
X}
X
X/*
X * new_fields - change the user's password aging information interactively.
X *
X * prompt the user for all of the password age values.  set the fields
X * from the user's response, or leave alone if nothing was entered.  the
X * value (-1) is used to indicate the field should be removed if possible.
X * any other negative value is an error.  very large positive values will
X * be handled elsewhere.
X */
X
Xint
Xnew_fields ()
X{
X	char	buf[BUFSIZ];
X	char	*cp;
X	long	value;
X	struct	tm	*tp;
X
X	printf ("Enter the new value, or press return for the default\n\n");
X
X	sprintf (buf, "%ld", mindays);
X	change_field (buf, "Minimum Password Age");
X	if (((mindays = strtol (buf, &cp, 10)) == 0 && *cp) || mindays < -1)
X		return 0;
X
X	sprintf (buf, "%ld", maxdays);
X	change_field (buf, "Maximum Password Age");
X	if (((maxdays = strtol (buf, &cp, 10)) == 0 && *cp) || maxdays < -1)
X		return 0;
X
X	value = lastday * SCALE;
X	tp = gmtime (&value);
X	sprintf (buf, "%02d/%02d/%02d",
X		tp->tm_mon + 1, tp->tm_mday, tp->tm_year);
X	change_field (buf, "Last Password Change (MM/DD/YY)");
X	if (strcmp (buf, "12/31/69") == 0)
X		lastday = -1;
X	else if ((lastday = strtoday (buf)) == -1)
X		return 0;
X
X	sprintf (buf, "%ld", warndays);
X	change_field (buf, "Password Expiration Warning");
X	if (((warndays = strtol (buf, &cp, 10)) == 0 && *cp) || warndays < -1)
X		return 0;
X
X	sprintf (buf, "%ld", inactdays);
X	change_field (buf, "Password Inactive");
X	if (((inactdays = strtol (buf, &cp, 10)) == 0 && *cp) || inactdays < -1)
X		return 0;
X
X	value = expdays * SCALE;
X	tp = gmtime (&value);
X	sprintf (buf, "%02d/%02d/%02d",
X		tp->tm_mon + 1, tp->tm_mday, tp->tm_year);
X	change_field (buf, "Account Expiration Date (MM/DD/YY)");
X	if (strcmp (buf, "12/31/69") == 0)
X		expdays = -1;
X	else if ((expdays = strtoday (buf)) == -1)
X		return 0;
X
X	return 1;
X}
X
X/*
X * list_fields - display the current values of the expiration fields
X *
X * display the password age information from the password fields.  date
X * values will be displayed as a calendar date, or the word "Never" if
X * the date is 1/1/70, which is day number 0.
X */
X
Xvoid
Xlist_fields ()
X{
X	struct	tm	*tp;
X	char	*cp;
X	long	changed;
X	long	expires;
X
X	/*
X	 * Start with the easy numbers - the number of days before the
X	 * password can be changed, the number of days after which the
X	 * password must be chaged, the number of days before the
X	 * password expires that the user is told, and the number of
X	 * days after the password expires that the account becomes
X	 * unusable.
X	 */
X
X	printf ("Minimum:\t%d\n", mindays);
X	printf ("Maximum:\t%d\n", maxdays);
X	printf ("Warning:\t%d\n", warndays);
X	printf ("Inactive:\t%d\n", inactdays);
X
X	/*
X	 * The "last change" date is either "Never" or the date the
X	 * password was last modified.  The date is the number of
X	 * days since 1/1/1970.
X	 */
X
X	printf ("Last Change:\t\t");
X	if (changed <= 0) {
X		printf ("Never\n");
X	} else {
X		changed = lastday * SCALE;
X		tp = gmtime (&changed);
X		cp = asctime (tp);
X		printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X	}
X
X	/*
X	 * The password expiration date is determined from the last
X	 * change date plus the number of days the password is valid
X	 * for.
X	 */
X
X	printf ("Password Expires:\t");
X	if (changed <= 0 || maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
X		printf ("Never\n");
X	} else {
X		expires = changed + maxdays * SCALE;
X		tp = gmtime (&expires);
X		cp = asctime (tp);
X		printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X	}
X
X	/*
X	 * The account becomes inactive if the password is expired
X	 * for more than "inactdays".  The expiration date is calculated
X	 * and the number of inactive days is added.  The resulting date
X	 * is when the active will be disabled.
X	 */
X
X	printf ("Password Inactive:\t");
X	if (changed <= 0 || inactdays <= 0 ||
X			maxdays >= 10000*(DAY/SCALE) || maxdays <= 0) {
X		printf ("Never\n");
X	} else {
X		expires = changed + (maxdays + inactdays) * SCALE;
X		tp = gmtime (&expires);
X		cp = asctime (tp);
X		printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X	}
X
X	/*
X	 * The account will expire on the given date regardless of the
X	 * password expiring or not.
X	 */
X
X	printf ("Account Expires:\t");
X	if (expdays <= 0) {
X		printf ("Never\n");
X	} else {
X		expires = expdays * SCALE;
X		tp = gmtime (&expires);
X		cp = asctime (tp);
X		printf ("%6.6s, %4.4s\n", cp + 4, cp + 20);
X	}
X}
X
X/*
X * chage - change a user's password aging information
X *
X *	This command controls the password aging information.
X *
X *	The valid options are
X *
X *	-m	minimum number of days before password change (*)
X *	-M	maximim number of days before password change (*)
X *	-d	last password change date (*)
X *	-l	last password change date
X *	-W	expiration warning days (*)
X *	-I	password inactive after expiration (*)
X *	-E	account expiration date (*)
X *
X *	(*) requires root permission to execute.
X *
X *	All of the time fields are entered in the internal format
X *	which is either seconds or days.
X */
X
Xint
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	int	flag;
X	int	lflg;
X	int	mflg;
X	int	Mflg;
X	int	dflg;
X	int	Wflg;
X	int	Iflg;
X	int	Eflg;
X	int	ruid = getuid ();
X	struct	passwd	*pw;
X	struct	passwd	pwent;
X	struct	spwd	*sp;
X	struct	spwd	spwd;
X	char	name[BUFSIZ];
X
X	/*
X	 * Get the program name so that error messages can use it.
X	 */
X
X	if (Prog = strrchr (argv[0], '/'))
X		Prog++;
X	else
X		Prog = argv[0];
X
X	openlog (Prog, LOG_PID|LOG_CONS|LOG_NOWAIT, LOG_AUTH);
X#ifdef	NDBM
X	sp_dbm_mode = O_RDWR;
X	pw_dbm_mode = O_RDWR;
X#endif
X
X	/*
X	 * Parse the flags.  The difference between password file
X	 * formats includes the number of fields, and whether the
X	 * dates are entered as days or weeks.  Shadow password
X	 * file info =must= be entered in days, while regular
X	 * password file info =must= be entered in weeks.
X	 */
X
X	while ((flag = getopt (argc, argv, "lm:M:W:I:E:d:")) != 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				Wflg++;
X				warndays = strtol (optarg, 0, 10);
X				break;
X			case 'I':
X				Iflg++;
X				inactdays = strtol (optarg, 0, 10);
X				break;
X			case 'E':
X				Eflg++;
X				expdays = strtol (optarg, 0, 10);
X				break;
X			default:
X				usage ();
X		}
X	}
X
X	/*
X	 * Make certain the flags do not conflict and that there is
X	 * a user name on the command line.
X	 */
X
X	if (argc != optind + 1)
X		usage ();
X
X	if (lflg && (mflg || Mflg || dflg || Wflg || Iflg || Eflg)) {
X		fprintf (stderr, "%s: do not include \"l\" with other flags\n",
X			Prog);
X		usage ();
X	}
X
X	/*
X	 * An unprivileged user can ask for their own aging information,
X	 * but only root can change it, or list another user's aging
X	 * information.
X	 */
X
X	if (ruid != 0 && ! lflg) {
X		fprintf (stderr, "%s: permission denied\n", Prog);
X		exit (1);
X	}
X
X	/*
X	 * Lock and open the password file.  This loads all of the
X	 * password file entries into memory.  Then we get a pointer
X	 * to the password file entry for the requested user.
X	 */
X
X	if (! pw_lock ()) {
X		fprintf (stderr, "%s: can't lock password file\n", Prog);
X		exit (1);
X	}
X	if (! pw_open (ruid != 0 || lflg ? O_RDONLY:O_RDWR)) {
X		fprintf (stderr, "%s: can't open password file\n", Prog);
X		cleanup (1);
X		exit (1);
X	}
X	if (! (pw = pw_locate (argv[optind]))) {
X		fprintf (stderr, "%s: unknown user: %s\n", Prog, argv[optind]);
X		cleanup (1);
X		exit (1);
X	}
X
X	/*
X	 * For shadow password files we have to lock the file and
X	 * read in the entries as was done for the password file.
X	 * The user entries does not have to exist in this case;
X	 * a new entry will be created for this user if one does
X	 * not exist already.
X	 */
X
X	if (! spw_lock ()) {
X		fprintf (stderr, "%s: can't lock shadow file\n", Prog);
X		cleanup (1);
X		exit (1);
X	}
X	if (! spw_open ((ruid != 0 || lflg) ? O_RDONLY:O_RDWR)) {
X		fprintf (stderr, "%s: can't open shadow file\n", Prog);
X		cleanup (2);
X		exit (1);
X	}
X	if (sp = spw_locate (argv[optind]))
X		spwd = *sp;
X
X	strcpy (name, pw->pw_name);
X	pwent = *pw;
X
X	/*
X	 * Set the fields that aren't being set from the command line
X	 * from the password file.
X	 */
X
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		if (! Wflg)
X			warndays = spwd.sp_warn;
X		if (! Iflg)
X			inactdays = spwd.sp_inact;
X		if (! Eflg)
X			expdays = spwd.sp_expire;
X	} else
X#ifdef	ATT_AGE
X	{
X		if (pwent.pw_age && strlen (pwent.pw_age) >= 2) {
X			if (! Mflg)
X				maxdays = c64i (pwent.pw_age[0]) * (WEEK/SCALE);
X			if (! mflg)
X				mindays = c64i (pwent.pw_age[1]) * (WEEK/SCALE);
X			if (! dflg && strlen (pwent.pw_age) == 4)
X				lastday = a64l (pwent.pw_age+2) * (WEEK/SCALE);
X		} else {
X			mindays = 0;
X			maxdays = 10000L * (DAY/SCALE);
X			lastday = -1;
X		}
X		warndays = inactdays = expdays = -1;
X	}
X#endif
X
X	/*
X	 * Print out the expiration fields if the user has
X	 * requested the list option.
X	 */
X
X	if (lflg) {
X		if (ruid != 0 && ruid != pw->pw_uid) {
X			fprintf (stderr, "%s: permission denied\n", Prog);
X			exit (1);
X		}
X		list_fields ();
X		cleanup (2);
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 && ! Wflg && ! Iflg && ! Eflg) {
X		printf ("Changing the aging information for %s\n", name);
X		if (! new_fields ()) {
X			fprintf (stderr, "%s: error changing fields\n", Prog);
X			cleanup (2);
X			exit (1);
X		}
X	}
X
X	/*
X	 * There was no shadow entry.  The new entry will have the
X	 * encrypted password transferred from the normal password
X	 * file along with the aging information.
X	 */
X
X	if (sp == 0) {
X		sp = &spwd;
X		bzero (&spwd, sizeof spwd);
X
X		sp->sp_namp = pw->pw_name;
X		sp->sp_pwdp = pw->pw_passwd;
X		sp->sp_flag = -1;
X
X		pwent.pw_passwd = "!";
X#ifdef	ATT_AGE
X		pwent.pw_age = "";
X#endif
X		if (! pw_update (&pwent)) {
X			fprintf (stderr, "%s: can't update password file\n",
X				Prog);
X			cleanup (2);
X			exit (1);
X		}
X#if defined(DBM) || defined(NDBM)
X		(void) pw_dbm_update (&pwent);
X#endif
X	}
X
X	/*
X	 * Copy the fields back to the shadow file entry and
X	 * write the modified entry back to the shadow file.
X	 * Closing the shadow and password files will commit
X	 * any changes that have been made.
X	 */
X
X	sp->sp_max = maxdays;
X	sp->sp_min = mindays;
X	sp->sp_lstchg = lastday;
X	sp->sp_warn = warndays;
X	sp->sp_inact = inactdays;
X	sp->sp_expire = expdays;
X
X	if (! spw_update (sp)) {
X		fprintf (stderr, "%s: can't update shadow file\n", Prog);
X		cleanup (2);
X		exit (1);
X	}
X#ifdef	NDBM
X	if (access ("/etc/shadow.pag", 0) == 0 && ! sp_dbm_update (sp)) {
X		fprintf (stderr, DBMERROR);
X		syslog (LOG_ERR, DBMERROR2);
X		(void) spw_unlock ();
X		exit (1);
X	}
X#endif	/* NDBM */
X	if (! spw_close ()) {
X		fprintf (stderr, "%s: can't rewrite shadow file\n", Prog);
X		cleanup (2);
X		exit (1);
X	}
X	(void) pw_close ();
X	cleanup (2);
X	exit (0);
X	/*NOTREACHED*/
X}
X
X/*
X * cleanup - unlock any locked password files
X */
X
Xvoid
Xcleanup (state)
Xint	state;
X{
X	switch (state) {
X		case 2:
X			spw_unlock ();
X		case 1:
X			pw_unlock ();
X		case 0:
X			break;
X	}
X}
SHAR_EOF
if test 15243 -ne "`wc -c < 'chage.c'`"
then
	echo shar: "error transmitting 'chage.c'" '(should have been 15243 characters)'
fi
fi
echo shar: "extracting 'pwent.c'" '(9715 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <stdio.h>
X#include "pwd.h"
X#ifdef	BSD
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#else
X#include <string.h>
X#endif
X#include "config.h"
X
X/*
X * If AUTOSHADOW is enable, the getpwnam and getpwuid calls will
X * fill in the pw_passwd and pw_age fields from the passwd and
X * shadow files.
X */
X
X#if defined(AUTOSHADOW) && !defined(SHADOWPWD)
X#undef	AUTOSHADOW
X#endif
X#ifdef	AUTOSHADOW
X#include "shadow.h"
X#endif
X
X/*
X * If DBM or NDBM is enabled, the getpwnam and getpwuid calls will
X * go to the database files to look for the requested entries.
X */
X
X#ifdef	DBM
X#include <dbm.h>
X#endif
X#ifdef	NDBM
X#include <ndbm.h>
X#include <fcntl.h>
XDBM	*pw_dbm;
Xint	pw_dbm_mode = -1;
X#endif
X
X/*
X * ITI-style aging uses time_t's as the time fields, while
X * AT&T-style aging uses long numbers of days.
X */
X
X#ifdef	ITI_AGING
X#define	WEEK	(7L*24L*3600L)
X#else
X#define	WEEK	7
X#endif
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)pwent.c	3.5	12:53:57	12/19/90";
X#endif
X
X#define	SBUFSIZ	64
X#define	NFIELDS	7
X
Xstatic	FILE	*pwdfp;
Xstatic	char	pwdbuf[BUFSIZ];
Xstatic	char	*pwdfile = PWDFILE;
X#if defined(DBM) || defined(NDBM)
Xstatic	int	dbmopened;
Xstatic	int	dbmerror;
X#endif
Xstatic	char	*pwdfields[NFIELDS];
Xstatic	struct	passwd	pwent;
X
X#if defined(AUTOSHADOW) && defined(ATT_AGE)
X/*
X * sptopwage - convert shadow ages to AT&T-style pw_age ages
X *
X *	sptopwage() converts the values in the shadow password
X *	entry to the format used in the old-style password
X *	entry.
X */
X
Xstatic char *
Xsptopwage (spwd)
Xstruct	spwd	*spwd;
X{
X	static	char	age[5];
X	long	min;
X	long	max;
X	long	last;
X
X	if ((min = (spwd->sp_min / WEEK)) < 0)
X		min = 0;
X	else if (min >= 64)
X		min = 63;
X
X	if ((max = (spwd->sp_max / WEEK)) < 0)
X		max = 0;
X	else if (max >= 64)
X		max = 63;
X
X	if ((last = (spwd->sp_lstchg / WEEK)) < 0)
X		last = 0;
X	else if (last >= 4096)
X		last = 4095;
X
X	age[0] = i64c (max);
X	age[1] = i64c (min);
X	age[2] = i64c (last % 64);
X	age[3] = i64c (last / 64);
X	age[4] = '\0';
X	return age;
X}
X#endif
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 *
Xsgetpwent (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#ifdef	ATT_AGE
X	if (cp = strchr (pwent.pw_passwd, ',')) {
X		pwent.pw_age = cp + 1;
X		*cp = '\0';
X	} else
X		pwent.pw_age = "";
X#endif
X	pwent.pw_gecos = pwdfields[4];
X#ifdef	ATT_COMMENT
X	pwent.pw_comment = "";
X#endif
X	pwent.pw_dir = pwdfields[5];
X	pwent.pw_shell = pwdfields[6];
X
X	return (&pwent);
X}
X
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 *
Xfgetpwent (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
X/*
X * endpwent - close a password file
X *
X * endpwent() closes the password file if open.  if autoshadowing is
X * enabled the system must also end access to the shadow files since
X * the user is probably unaware it was ever accessed.
X */
X
Xint
Xendpwent ()
X{
X	if (pwdfp)
X		if (fclose (pwdfp))
X			return -1;
X
X	pwdfp = 0;
X#ifdef	NDBM
X	if (dbmopened && pw_dbm) {
X		dbm_close (pw_dbm);
X		dbmopened = 0;
X		dbmerror = 0;
X		pw_dbm = 0;
X	}
X#endif
X#ifdef	AUTOSHADOW
X	endspent ();
X#endif
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 *
Xgetpwent ()
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 *
Xgetpwuid (uid)
Xint	uid;
X{
X	struct	passwd	*pwd;
X#if defined(DBM) || defined(NDBM)
X	datum	key;
X	datum	content;
X#endif
X#ifdef	AUTOSHADOW
X	struct	spwd	*spwd;
X#endif
X
X	if (setpwent ())
X		return 0;
X
X#if defined(DBM) || defined(NDBM)
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#ifdef	DBM
X		content = fetch (key);
X#endif
X#ifdef	NDBM
X		content = dbm_fetch (pw_dbm, key);
X#endif
X		if (content.dptr != 0) {
X			memcpy (pwdbuf, content.dptr, content.dsize);
X			pw_unpack (pwdbuf, content.dsize, &pwent);
X#ifdef	AUTOSHADOW
X			if (spwd = getspnam (pwent.pw_name)) {
X				pwent.pw_passwd = spwd->sp_pwdp;
X#ifdef	ATT_AGE
X				pwent.pw_age = sptopwage (spwd);
X#endif
X			}
X#endif
X			return &pwent;
X		}
X	}
X#endif
X	/*
X	 * Search for an entry which matches the UID.  Return the
X	 * entry when a match is found.
X	 */
X
X	while (pwd = getpwent ())
X		if (pwd->pw_uid == uid)
X			break;
X
X#ifdef	AUTOSHADOW
X	if (pwd && (spwd = getspnam (pwd->pw_name))) {
X		pwd->pw_passwd = spwd->sp_pwdp;
X#ifdef	ATT_AGE
X		pwd->pw_age = sptopwage (spwd);
X#endif
X	}
X#endif
X	return pwd;
X}
X
X/*
X * getpwnam - locate the password entry for a given name
X *
X * getpwnam() locates the first password file entry for the given name.
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 name.
X */
X
Xstruct passwd *
Xgetpwnam (name)
Xchar	*name;
X{
X	struct	passwd	*pwd;
X#if defined(DBM) || defined(NDBM)
X	datum	key;
X	datum	content;
X#endif
X#ifdef	AUTOSHADOW
X	struct	spwd	*spwd;
X#endif
X
X	if (setpwent ())
X		return 0;
X
X#if defined(DBM) || defined(NDBM)
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#ifdef	DBM
X		content = fetch (key);
X#endif
X#ifdef	NDBM
X		content = dbm_fetch (pw_dbm, key);
X#endif
X		if (content.dptr != 0) {
X			memcpy (pwdbuf, content.dptr, content.dsize);
X			pw_unpack (pwdbuf, content.dsize, &pwent);
X#ifdef	AUTOSHADOW
X			if (spwd = getspnam (pwent.pw_name)) {
X				pwent.pw_passwd = spwd->sp_pwdp;
X#ifdef	ATT_AGE
X				pwent.pw_age = sptopwage (spwd);
X#endif
X			}
X#endif
X			return &pwent;
X		}
X	}
X#endif
X	/*
X	 * Search for an entry which matches the name.  Return the
X	 * entry when a match is found.
X	 */
X
X	while (pwd = getpwent ())
X		if (strcmp (pwd->pw_name, name) == 0)
X			break;
X
X#ifdef	AUTOSHADOW
X	if (pwd && (spwd = getspnam (pwd->pw_name))) {
X		pwd->pw_passwd = spwd->sp_pwdp;
X#ifdef	ATT_AGE
X		pwd->pw_age = sptopwage (spwd);
X#endif
X	}
X#endif
X	return pwd;
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
Xsetpwent ()
X{
X#ifdef	NDBM
X	int	mode;
X#endif
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
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 defined (DBM) || defined (NDBM)
X	if (! dbmerror && ! dbmopened) {
X		char	dbmfiles[BUFSIZ];
X
X		strcpy (dbmfiles, pwdfile);
X		strcat (dbmfiles, ".pag");
X#ifdef	NDBM
X		if (pw_dbm_mode == -1)
X			mode = O_RDONLY;
X		else
X			mode = (pw_dbm_mode == O_RDONLY ||
X				pw_dbm_mode == O_RDWR) ? pw_dbm_mode:O_RDONLY;
X#endif
X#ifdef	DBM
X		if (access (dbmfiles, 0) || dbminit (pwdfile))
X#endif
X#ifdef	NDBM
X		if (access (dbmfiles, 0) ||
X			(! (pw_dbm = dbm_open (pwdfile, mode, 0))))
X#endif
X			dbmerror = 1;
X		else
X			dbmopened = 1;
X	}
X#endif
X	return 0;
X}
SHAR_EOF
if test 9715 -ne "`wc -c < 'pwent.c'`"
then
	echo shar: "error transmitting 'pwent.c'" '(should have been 9715 characters)'
fi
fi
echo shar: "extracting 'valid.c'" '(2336 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, 1991, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <stdio.h>
X#include "pwd.h"
X#ifdef	BSD
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#else
X#include <string.h>
X#include <memory.h>
X#endif
X#include "config.h"
X
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)valid.c	3.3	08:00:20	2/6/91";
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.  Entries which do
X *	not have a password file entry have a NULL pw_name field and this
X *	is used to indicate that a dummy salt must be used to encrypt the
X *	password anyway.
X */
X
Xint	valid (password, entry)
Xchar	*password;
Xstruct	passwd	*entry;
X{
X	char	*encrypt;
X	char	*salt;
X	char	*pw_encrypt ();
X	char	*shell;
X
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 && ! entry->pw_passwd[0]) {
X		if (! password[0])
X			return (1);	/* user entered nothing */
X		else
X			return (0);	/* user entered something! */
X	}
X
X	/*
X	 * If there is no entry then we need a salt to use.
X	 */
X
X	if (entry->pw_name == (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 = pw_encrypt (password, salt);
X
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.
X	 */
X
X	if (entry->pw_name && strcmp (encrypt, entry->pw_passwd) == 0)
X		return (1);
X	else
X		return (0);
X}
SHAR_EOF
if test 2336 -ne "`wc -c < 'valid.c'`"
then
	echo shar: "error transmitting 'valid.c'" '(should have been 2336 characters)'
fi
fi
echo shar: "extracting 'setup.c'" '(3560 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, 1991, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include <sys/types.h>
X#include <stdio.h>
X#include <utmp.h>
X#include <syslog.h>
X
X#ifdef	BSD
X#include <strings.h>
X#define	strchr	index
X#else
X#include <string.h>
X#include <memory.h>
X#endif
X
X#include "config.h"
X#include "pwd.h"
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)setup.c	3.3	07:46:41	2/6/91";
X#endif
X
X#ifndef	PATH
X#define	PATH	"PATH=/bin:/usr/bin"
X#endif
X
X#ifndef	SUPATH
X#define	SUPATH	"PATH=/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
X/*
X * setup - initialize login environment
X *
X *	setup() performs the following steps -
X *
X *	set the login tty to be owned by the new user ID with TTYPERM modes
X *	change to the user's home directory
X *	set the process nice, ulimit, and umask from the password file entry
X *	set the group ID to the value from the password file entry
X *	set the user ID to the value from the password file entry
X *	set the HOME, SHELL, MAIL, PATH, and LOGNAME environmental variables
X */
X
Xvoid	setup (info)
Xstruct	passwd	*info;
X{
X	extern	int	errno;
X	char	buf[BUFSIZ];
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) || chmod (tty, TTYPERM)) {
X		(void) sprintf (buf, "Unable to change tty %s", tty);
X		syslog (LOG_WARN, "unable to change tty `%s' for user `%s'",
X			tty, info->pw_name);
X		perror (buf);
X		exit (errno);
X	}
X#endif
X	if (chdir (info->pw_dir) == -1) {
X		(void) sprintf (buf, "Unable to cd to \"%s\"", info->pw_dir);
X		syslog (LOG_WARN, "unable to cd to `%s' for user `%s'",
X			info->pw_dir, info->pw_name);
X		perror (buf);
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		syslog (LOG_WARN, "bad group ID `%d' for user `%s'",
X			info->pw_gid, info->pw_name);
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		syslog (LOG_WARN, "bad user ID `%d' for user `%s'",
X			info->pw_uid, info->pw_name);
X		exit (errno);
X	}
X	(void) strcat (strcpy (buf, "HOME="), info->pw_dir);
X	addenv (buf);
X
X	if (info->pw_shell == (char *) 0)
X		info->pw_shell = "/bin/sh";
X
X	(void) strcat (strcpy (buf, "SHELL="), info->pw_shell);
X	addenv (buf);
X
X	if (info->pw_uid == 0)
X		addenv (SUPATH);
X	else
X		addenv (PATH);
X
X	(void) strcat (strcpy (buf, "LOGNAME="), info->pw_name);
X	addenv (buf);
X
X	(void) strcat (strcat (strcpy (buf, "MAIL="), MAILDIR), info->pw_name);
X	addenv (buf);
X}
SHAR_EOF
if test 3560 -ne "`wc -c < 'setup.c'`"
then
	echo shar: "error transmitting 'setup.c'" '(should have been 3560 characters)'
fi
fi
echo shar: "extracting 'entry.c'" '(1946 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 * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X#include "pwd.h"
X#ifndef	BSD
X#include <string.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X#ifdef	SHADOWPWD
X#include "shadow.h"
X#endif
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)entry.c	3.2	12:30:39	12/12/90";
X#endif
X
Xstruct	passwd	*fgetpwent ();
X
Xvoid	entry (name, pwent)
Xchar	*name;
Xstruct	passwd	*pwent;
X{
X	struct	passwd	*passwd;
X#ifdef	SHADOWPWD
X	struct	spwd	*spwd;
X	char	*l64a ();
X#endif
X	char	*cp;
X
X	if (! (passwd = getpwnam (name))) {
X		pwent->pw_name = (char *) 0;
X		return;
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#ifdef	ATT_COMMENT
X		pwent->pw_comment = strdup (passwd->pw_comment);
X#endif
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#if defined(SHADOWPWD) && !defined(AUTOSHADOW)
X		setspent ();
X		if (spwd = getspnam (name)) {
X			pwent->pw_passwd = strdup (spwd->sp_pwdp);
X#ifdef	ATT_AGE
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#endif
X			endspent ();
X			return;
X		}
X		endspent ();
X#endif
X		pwent->pw_passwd = strdup (passwd->pw_passwd);
X#ifdef	ATT_AGE
X		pwent->pw_age = strdup (passwd->pw_age);
X#endif
X	}
X}
SHAR_EOF
if test 1946 -ne "`wc -c < 'entry.c'`"
then
	echo shar: "error transmitting 'entry.c'" '(should have been 1946 characters)'
fi
fi
echo shar: "extracting 'ttytype.c'" '(1125 characters)'
if test -f 'ttytype.c'
then
	echo shar: "will not over-write existing file 'ttytype.c'"
else
sed 's/^X//' << \SHAR_EOF > 'ttytype.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#include <stdio.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X#include "config.h"
X
X#ifdef	TTYTYPE
X#ifndef	lint
Xstatic	char	_sccsid[] = "@(#)ttytype.c	2.2	19:24:24	7/29/90";
X#endif
X
X/*
X * ttytype - set ttytype from port to terminal type mapping database
X */
X
Xvoid	ttytype (line)
Xchar	*line;
X{
X	FILE	*fp;
X	char	buf[BUFSIZ];
X	char	termvar[BUFSIZ];
X	char	*cp;
X	char	*type;
X	char	*port;
X	char	*getenv ();
X
X	if (getenv ("TERM"))
X		return;
X
X	if (! (fp = fopen (TTYTYPE, "r")))
X		return;
X
X	while (fgets (buf, BUFSIZ, fp)) {
X		if (buf[0] == '#')
X			continue;
X
X		if (cp = strchr (buf, '\n'))
X			*cp = '\0';
X
X		if ((type = strtok (buf, " \t"))
X				&& (port = strtok ((char *) 0, " \t"))) {
X			if (strcmp (line, port) == 0)
X				break;
X		}
X	}
X	if (! feof (fp) && ! ferror (fp)) {
X		strcat (strcpy (termvar, "TERM="), type);
X		addenv (termvar);
X	}
X	fclose (fp);
X}
X#endif
SHAR_EOF
if test 1125 -ne "`wc -c < 'ttytype.c'`"
then
	echo shar: "error transmitting 'ttytype.c'" '(should have been 1125 characters)'
fi
fi
echo shar: "extracting 'port.h'" '(1743 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 1989, 1990, 1991, John F. Haugh II
X * All rights reserved.
X *
X * Permission is granted to copy and create derivative works for any
X * non-commercial purpose, provided this copyright notice is preserved
X * in all copies of source code, or included in human readable form
X * and conspicuously displayed on all copies of object code or
X * distribution media.
X */
X
X/*
X * port.h - structure of /etc/porttime
X *
X *	@(#)port.h	3.1	08:59:36	2/8/91
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_TTY - Allowable number of TTYs 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_TTY	64
X#define	PORT_TIMES	24
X#define	PORT_DAY(day)	(1<<(day))
X
X/*
X *	pt_names - pointer to array of device names 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_names;
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 1743 -ne "`wc -c < 'port.h'`"
then
	echo shar: "error transmitting 'port.h'" '(should have been 1743 characters)'
fi
fi
exit 0
#	End of shell archive
-- 
John F. Haugh II        | Distribution to  | UUCP: ...!cs.utexas.edu!rpp386!jfh
Ma Bell: (512) 255-8251 | GEnie PROHIBITED :-) |  Domain: jfh at rpp386.cactus.org
"If liberals interpreted the 2nd Amendment the same way they interpret the
 rest of the Constitution, gun ownership would be mandatory."



More information about the Alt.sources mailing list