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

John F Haugh II jfh at rpp386.cactus.org
Fri May 17 02:31:58 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:
#	pwio.c
#	encrypt.c
#	chpasswd.c
#	newusers.c
#	rad64.c
#	dialchk.c
#	faillog.h
#	pwdbm.c
#	grdbm.c
#	gshadow.c
#	sppack.c
# This archive created: Sun Mar  3 13:27:28 1991
# By:	John F Haugh II (River Parishes Programming, Austin TX)
export PATH; PATH=/bin:/usr/bin:$PATH
echo shar: "extracting 'pwio.c'" '(11009 characters)'
if test -f 'pwio.c'
then
	echo shar: "will not over-write existing file 'pwio.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwio.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 *	This file implements a transaction oriented password database
X *	library.  The password file is updated one entry at a time.
X *	After each transaction the file must be logically closed and
X *	transferred to the existing password file.  The sequence of
X *	events is
X *
X *	pw_lock				-- lock password file
X *	pw_open				-- logically open password file
X *	while transaction to process
X *		pw_(locate,update,remove) -- perform transaction
X *	done
X *	pw_close			-- commit transactions
X *	pw_unlock			-- remove password lock
X */
X
X#include <sys/stat.h>
X#include <fcntl.h>
X#include <errno.h>
X#include "pwd.h"
X#include <stdio.h>
X
X#ifndef lint
Xstatic	char	sccsid[] = "@(#)pwio.c	3.6	12:31:19	12/12/90";
X#endif
X
Xstatic	int	islocked;
Xstatic	int	isopen;
Xstatic	int	open_modes;
Xstatic	FILE	*pwfp;
X
Xstruct	pw_file_entry {
X	char	*pwf_line;
X	int	pwf_changed;
X	struct	passwd	*pwf_entry;
X	struct	pw_file_entry *pwf_next;
X};
X
Xstatic	struct	pw_file_entry	*pwf_head;
Xstatic	struct	pw_file_entry	*pwf_tail;
Xstatic	struct	pw_file_entry	*pwf_cursor;
Xstatic	int	pw_changed;
Xstatic	int	lock_pid;
X
X#define	PW_LOCK	"/etc/passwd.lock"
X#define	PW_TEMP "/etc/pwd.%d"
X#define	PASSWD	"/etc/passwd"
X
Xstatic	char	pw_filename[BUFSIZ] = PASSWD;
X
Xextern	char	*strdup();
Xextern	struct	passwd	*sgetpwent();
X
X/*
X * pw_dup - duplicate a password file entry
X *
X *	pw_dup() accepts a pointer to a password file entry and
X *	returns a pointer to a password file entry in allocated
X *	memory.
X */
X
Xstatic struct passwd *
Xpw_dup (pwent)
Xstruct	passwd	*pwent;
X{
X	struct	passwd	*pw;
X
X	if (! (pw = (struct passwd *) malloc (sizeof *pw)))
X		return 0;
X
X	if ((pw->pw_name = strdup (pwent->pw_name)) == 0 ||
X			(pw->pw_passwd = strdup (pwent->pw_passwd)) == 0 ||
X#ifdef	ATT_AGE
X			(pw->pw_age = strdup (pwent->pw_age)) == 0 ||
X#endif	/* ATT_AGE */
X#ifdef	ATT_COMMENT
X			(pw->pw_comment = strdup (pwent->pw_comment)) == 0 ||
X#endif	/* ATT_COMMENT */
X			(pw->pw_gecos = strdup (pwent->pw_gecos)) == 0 ||
X			(pw->pw_dir = strdup (pwent->pw_dir)) == 0 ||
X			(pw->pw_shell = strdup (pwent->pw_shell)) == 0)
X		return 0;
X
X	pw->pw_uid = pwent->pw_uid;
X	pw->pw_gid = pwent->pw_gid;
X
X	return pw;
X}
X
X/*
X * pw_free - free a dynamically allocated password file entry
X *
X *	pw_free() frees up the memory which was allocated for the
X *	pointed to entry.
X */
X
Xstatic void
Xpw_free (pwent)
Xstruct	passwd	*pwent;
X{
X	free (pwent->pw_name);
X	free (pwent->pw_passwd);
X	free (pwent->pw_gecos);
X	free (pwent->pw_dir);
X	free (pwent->pw_shell);
X}
X
X/*
X * pw_name - change the name of the password file
X */
X
Xint
Xpw_name (name)
Xchar	*name;
X{
X	if (isopen || strlen (name) > (BUFSIZ-10))
X		return -1;
X
X	strcpy (pw_filename, name);
X	return 0;
X}
X
X/*
X * pw_lock - lock a password file
X *
X *	pw_lock() encapsulates the lock operation.  it returns
X *	TRUE or FALSE depending on the password file being
X *	properly locked.  the lock is set by creating a semaphore
X *	file, PW_LOCK.
X */
X
Xint
Xpw_lock ()
X{
X	int	fd;
X	int	pid;
X	int	len;
X	char	file[BUFSIZ];
X	char	buf[32];
X	struct	stat	sb;
X
X	if (islocked)
X		return 1;
X
X	if (strcmp (pw_filename, PASSWD) != 0)
X		return 0;
X
X	/*
X	 * Create a lock file which can be switched into place
X	 */
X
X	sprintf (file, PW_TEMP, lock_pid = getpid ());
X	if ((fd = open (file, O_CREAT|O_EXCL|O_WRONLY, 0600)) == -1)
X		return 0;
X
X	sprintf (buf, "%d", lock_pid);
X	if (write (fd, buf, strlen (buf) + 1) != strlen (buf) + 1) {
X		(void) close (fd);
X		(void) unlink (file);
X		return 0;
X	}
X	close (fd);
X
X	/*
X	 * Simple case first -
X	 *	Link fails (in a sane environment ...) if the target
X	 *	exists already.  So we try to switch in a new lock
X	 *	file.  If that succeeds, we assume we have the only
X	 *	valid lock.  Needs work for NFS where this assumption
X	 *	may not hold.  The simple hack is to check the link
X	 *	count on the source file, which should be 2 iff the
X	 *	link =really= worked.
X	 */
X
X	if (link (file, PW_LOCK) == 0) {
X		if (stat (file, &sb) != 0)
X			return 0;
X
X		if (sb.st_nlink != 2)
X			return 0;
X
X		(void) unlink (file);
X		islocked = 1;
X		return 1;
X	}
X
X	/*
X	 * Invalid lock test -
X	 *	Open the lock file and see if the lock is valid.
X	 *	The PID of the lock file is checked, and if the PID
X	 *	is not valid, the lock file is removed.  If the unlink
X	 *	of the lock file fails, it should mean that someone
X	 *	else is executing this code.  They will get success,
X	 *	and we will fail.
X	 */
X
X	if ((fd = open (PW_LOCK, O_RDWR)) == -1 ||
X			(len = read (fd, buf, BUFSIZ)) <= 0) {
X		errno = EINVAL;
X		return 0;
X	}
X	buf[len] = '\0';
X	if ((pid = strtol (buf, (char **) 0, 10)) == 0) {
X		errno = EINVAL;
X		return 0;
X	}
X	if (kill (pid, 0) == 0)  {
X		errno = EEXIST;
X		return 0;
X	}
X	if (unlink (PW_LOCK)) {
X		(void) close (fd);
X		(void) unlink (file);
X
X		return 0;
X	}
X
X	/*
X	 * Re-try lock -
X	 *	The invalid lock has now been removed and I should
X	 *	be able to acquire a lock for myself just fine.  If
X	 *	this fails there will be no retry.  The link count
X	 *	test here makes certain someone executing the previous
X	 *	block of code didn't just remove the lock we just
X	 *	linked to.
X	 */
X
X	if (link (file, PW_LOCK) == 0) {
X		if (stat (file, &sb) != 0)
X			return 0;
X
X		if (sb.st_nlink != 2)
X			return 0;
X
X		(void) unlink (file);
X		islocked = 1;
X		return 1;
X	}
X	(void) unlink (file);
X	return 0;
X}
X
X/*
X * pw_unlock - logically unlock a password file
X *
X *	pw_unlock() removes the lock which was set by an earlier
X *	invocation of pw_lock().
X */
X
Xint
Xpw_unlock ()
X{
X	if (isopen) {
X		open_modes = O_RDONLY;
X		if (! pw_close ())
X			return 0;
X	}
X  	if (islocked) {
X  		islocked = 0;
X		if (lock_pid != getpid ())
X			return 0;
X
X		(void) unlink (PW_LOCK);
X  		return 1;
X	}
X	return 0;
X}
X
X/*
X * pw_open - open a password file
X *
X *	pw_open() encapsulates the open operation.  it returns
X *	TRUE or FALSE depending on the password file being
X *	properly opened.
X */
X
Xint
Xpw_open (mode)
Xint	mode;
X{
X	char	buf[8192];
X	char	*cp;
X	struct	pw_file_entry	*pwf;
X	struct	passwd	*pwent;
X
X	if (isopen || (mode != O_RDONLY && mode != O_RDWR))
X		return 0;
X
X	if (mode != O_RDONLY && ! islocked &&
X			strcmp (pw_filename, PASSWD) == 0)
X		return 0;
X
X	if ((pwfp = fopen (pw_filename, mode == O_RDONLY ? "r":"r+")) == 0)
X		return 0;
X
X	pwf_head = pwf_tail = pwf_cursor = 0;
X	pw_changed = 0;
X
X	while (fgets (buf, sizeof buf, pwfp) != (char *) 0) {
X		if (cp = strrchr (buf, '\n'))
X			*cp = '\0';
X
X		if (! (pwf = (struct pw_file_entry *) malloc (sizeof *pwf)))
X			return 0;
X
X		pwf->pwf_changed = 0;
X		pwf->pwf_line = strdup (buf);
X		if ((pwent = sgetpwent (buf)) && ! (pwent = pw_dup (pwent)))
X			return 0;
X
X		pwf->pwf_entry = pwent;
X
X		if (pwf_head == 0) {
X			pwf_head = pwf_tail = pwf;
X			pwf->pwf_next = 0;
X		} else {
X			pwf_tail->pwf_next = pwf;
X			pwf->pwf_next = 0;
X			pwf_tail = pwf;
X		}
X	}
X	isopen++;
X	open_modes = mode;
X
X	return 1;
X}
X
X/*
X * pw_close - close the password file
X *
X *	pw_close() outputs any modified password file entries and
X *	frees any allocated memory.
X */
X
Xint
Xpw_close ()
X{
X	char	backup[BUFSIZ];
X	int	fd;
X	int	mask;
X	int	c;
X	int	i;
X	int	errors = 0;
X	FILE	*bkfp;
X	struct	pw_file_entry *pwf;
X	struct	pw_file_entry *opwf;
X
X	if (! isopen) {
X		errno = EINVAL;
X		return 0;
X	}
X	if (islocked && lock_pid != getpid ()) {
X		isopen = 0;
X		islocked = 0;
X		errno = EACCES;
X		return 0;
X	}
X	strcpy (backup, pw_filename);
X	strcat (backup, "-");
X
X	if (open_modes == O_RDWR && pw_changed) {
X		mask = umask (022);
X		if ((bkfp = fopen (backup, "w")) == 0) {
X			umask (mask);
X			return 0;
X		}
X		umask (mask);
X
X		rewind (pwfp);
X		while ((c = getc (pwfp)) != EOF) {
X			if (putc (c, bkfp) == EOF) {
X				fclose (bkfp);
X				return 0;
X			}
X		}
X		if (fclose (bkfp))
X			return 0;
X
X		isopen = 0;
X		(void) fclose (pwfp);
X
X		mask = umask (022);
X		if (! (pwfp = fopen (pw_filename, "w"))) {
X			umask (mask);
X			return 0;
X		}
X		umask (mask);
X
X		for (pwf = pwf_head;errors == 0 && pwf;pwf = pwf->pwf_next) {
X			if (pwf->pwf_changed) {
X				if (putpwent (pwf->pwf_entry, pwfp))
X					errors++;
X			} else {
X				if (fputs (pwf->pwf_line, pwfp) == EOF)
X					errors++;
X				if (putc ('\n', pwfp) == EOF)
X					errors++;
X			}
X		}
X		if (fflush (pwfp))
X			errors++;
X
X		if (errors) {
X			unlink (pw_filename);
X			link (backup, pw_filename);
X			unlink (backup);
X			return 0;
X		}
X	}
X	if (fclose (pwfp))
X		return 0;
X
X	pwfp = 0;
X
X	while (pwf_head != 0) {
X		pwf = pwf_head;
X		pwf_head = pwf->pwf_next;
X
X		if (pwf->pwf_entry) {
X			pw_free (pwf->pwf_entry);
X			free (pwf->pwf_entry);
X		}
X		if (pwf->pwf_line)
X			free (pwf->pwf_line);
X
X		free (pwf);
X	}
X	pwf_tail = 0;
X	return 1;
X}
X
Xint
Xpw_update (pwent)
Xstruct	passwd	*pwent;
X{
X	struct	pw_file_entry	*pwf;
X	struct	passwd	*npw;
X
X	if (! isopen || open_modes == O_RDONLY) {
X		errno = EINVAL;
X		return 0;
X	}
X	for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) {
X		if (pwf->pwf_entry == 0)
X			continue;
X
X		if (strcmp (pwent->pw_name, pwf->pwf_entry->pw_name) != 0)
X			continue;
X
X		if (! (npw = pw_dup (pwent)))
X			return 0;
X		else {
X			pw_free (pwf->pwf_entry);
X			*(pwf->pwf_entry) = *npw;
X		}
X		pwf->pwf_changed = 1;
X		pwf_cursor = pwf;
X		return pw_changed = 1;
X	}
X	pwf = (struct pw_file_entry *) malloc (sizeof *pwf);
X	if (! (pwf->pwf_entry = pw_dup (pwent)))
X		return 0;
X
X	pwf->pwf_changed = 1;
X	pwf->pwf_next = 0;
X	pwf->pwf_line = 0;
X
X	if (pwf_tail)
X		pwf_tail->pwf_next = pwf;
X
X	if (! pwf_head)
X		pwf_head = pwf;
X
X	pwf_tail = pwf;
X
X	return pw_changed = 1;
X}
X
Xint
Xpw_remove (name)
Xchar	*name;
X{
X	struct	pw_file_entry	*pwf;
X	struct	pw_file_entry	*opwf;
X
X	if (! isopen || open_modes == O_RDONLY) {
X		errno = EINVAL;
X		return 0;
X	}
X	for (opwf = 0, pwf = pwf_head;pwf != 0;
X			opwf = pwf, pwf = pwf->pwf_next) {
X		if (! pwf->pwf_entry)
X			continue;
X
X		if (strcmp (name, pwf->pwf_entry->pw_name) != 0)
X			continue;
X
X		if (pwf == pwf_cursor)
X			pwf_cursor = opwf;
X
X		if (opwf != 0)
X			opwf->pwf_next = pwf->pwf_next;
X		else
X			pwf_head = pwf->pwf_next;
X
X		if (pwf == pwf_tail)
X			pwf_tail = opwf;
X
X		return pw_changed = 1;
X	}
X	errno = ENOENT;
X	return 0;
X}
X
Xstruct passwd *
Xpw_locate (name)
Xchar	*name;
X{
X	struct	pw_file_entry	*pwf;
X
X	if (! isopen) {
X		errno = EINVAL;
X		return 0;
X	}
X	for (pwf = pwf_head;pwf != 0;pwf = pwf->pwf_next) {
X		if (pwf->pwf_entry == 0)
X			continue;
X
X		if (strcmp (name, pwf->pwf_entry->pw_name) == 0) {
X			pwf_cursor = pwf;
X			return pwf->pwf_entry;
X		}
X	}
X	errno = ENOENT;
X	return 0;
X}
X
Xint
Xpw_rewind ()
X{
X	if (! isopen) {
X		errno = EINVAL;
X		return 0;
X	}
X	pwf_cursor = 0;
X	return 1;
X}
X
Xstruct passwd *
Xpw_next ()
X{
X	if (! isopen) {
X		errno = EINVAL;
X		return 0;
X	}
X	if (pwf_cursor == 0)
X		pwf_cursor = pwf_head;
X	else
X		pwf_cursor = pwf_cursor->pwf_next;
X
X	while (pwf_cursor) {
X		if (pwf_cursor->pwf_entry)
X			return pwf_cursor->pwf_entry;
X
X		pwf_cursor = pwf_cursor->pwf_next;
X	}
X	return 0;
X}
SHAR_EOF
if test 11009 -ne "`wc -c < 'pwio.c'`"
then
	echo shar: "error transmitting 'pwio.c'" '(should have been 11009 characters)'
fi
fi
echo shar: "extracting 'encrypt.c'" '(1287 characters)'
if test -f 'encrypt.c'
then
	echo shar: "will not over-write existing file 'encrypt.c'"
else
sed 's/^X//' << \SHAR_EOF > 'encrypt.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 <string.h>
X#include "config.h"
X
X#ifndef lint
Xstatic	char	sccsid[] = "@(#)encrypt.c	3.4	19:44:23	12/10/90";
X#endif
X
Xextern	char	*crypt();
X
Xchar *
Xpw_encrypt (clear, salt)
Xchar	*clear;
Xchar	*salt;
X{
X	static	char	cipher[32];
X	static	int	count;
X	char	newsalt[2];
X	char	*cp;
X	long	now;
X
X	/*
X	 * See if a new salt is needed and get a few random
X	 * bits of information.  The amount of randomness is
X	 * probably not all that crucial since the salt only
X	 * serves to thwart a dictionary attack.
X	 */
X
X	if (salt == (char *) 0) {
X		now = time ((long *) 0) + count++;
X		now ^= clock ();
X		now ^= getpid ();
X		now = ((now >> 12) ^ (now)) & 07777;
X		newsalt[0] = i64c ((now >> 6) & 077);
X		newsalt[1] = i64c (now & 077);
X		salt = newsalt;
X	}
X	cp = crypt (clear, salt);
X	strcpy (cipher, cp);
X
X#ifdef	DOUBLESIZE
X	if (strlen (clear) > 8) {
X		cp = crypt (clear + 8, salt);
X		strcat (cipher, cp + 2);
X	}
X#endif
X	return cipher;
X}
SHAR_EOF
if test 1287 -ne "`wc -c < 'encrypt.c'`"
then
	echo shar: "error transmitting 'encrypt.c'" '(should have been 1287 characters)'
fi
fi
echo shar: "extracting 'chpasswd.c'" '(5114 characters)'
if test -f 'chpasswd.c'
then
	echo shar: "will not over-write existing file 'chpasswd.c'"
else
sed 's/^X//' << \SHAR_EOF > 'chpasswd.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 * chpass - update passwords in batch
X *
X *	chpass reads standard input for a list of colon separated
X *	user names and new passwords.  the appropriate password
X *	files are updated to reflect the changes.  because the
X *	changes are made in a batch fashion, the user must run
X *	the mkpasswd command after this command terminates since
X *	no password updates occur until the very end.
X */
X
X#include <stdio.h>
X#include "pwd.h"
X#include <fcntl.h>
X#include <string.h>
X#include "config.h"
X#ifdef	SHADOWPWD
X#include "shadow.h"
X#endif
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)chpasswd.c	3.2	12:30:30	12/12/90";
X#endif
X
Xchar	*Prog;
X
Xextern	char	*pw_encrypt();
X
X/* 
X * If it weren't for the different structures and differences in how
X * certain fields were manipulated, I could just use macros to replace
X * the function calls for the different file formats.  So I make the
X * best of things and just use macros to replace a few of the calls.
X */
X
X#ifdef	SHADOWPWD
X#define	pw_lock		spw_lock
X#define	pw_open		spw_open
X#define	pw_close	spw_close
X#define	pw_unlock	spw_unlock
X#endif
X
X/*
X * usage - display usage message and exit
X */
X
Xusage ()
X{
X	fprintf (stderr, "usage: %s\n", Prog);
X	exit (1);
X}
X
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	char	buf[BUFSIZ];
X	char	*name;
X	char	*newpwd;
X	char	*cp;
X#ifdef	SHADOWPWD
X	struct	spwd	*sp;
X	struct	spwd	newsp;
X	struct	spwd	*spw_locate();
X#else
X	struct	passwd	*pw;
X	struct	passwd	newpw;
X	struct	passwd	*pw_locate();
X	char	newage[5];
X#endif
X	int	errors = 0;
X	int	line = 0;
X	long	now = time ((long *) 0) / (24L*3600L);
X
X	if (Prog = strrchr (argv[0], '/'))
X		Prog++;
X	else
X		Prog = argv[0];
X
X	if (argc != 1)
X		usage ();
X
X	/*
X	 * Lock the password file and open it for reading.  This will
X	 * bring all of the entries into memory where they may be
X	 * updated.
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 (O_RDWR)) {
X		fprintf (stderr, "%s: can't open password file\n", Prog);
X		exit (1);
X	}
X
X	/*
X	 * Read each line, separating the user name from the password.
X	 * The password entry for each user will be looked up in the
X	 * appropriate file (shadow or passwd) and the password changed.
X	 * For shadow files the last change date is set directly, for
X	 * passwd files the last change date is set in the age only if
X	 * aging information is present.
X	 */
X
X	while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
X		line++;
X		if (cp = strrchr (buf, '\n')) {
X			*cp = '\0';
X		} else {
X			fprintf (stderr, "%s: line %d: line too long\n",
X				Prog, line);
X			errors++;
X			continue;
X		}
X
X		/*
X		 * The username is the first field.  It is separated
X		 * from the password with a ":" character which is
X		 * replaced with a NUL to give the new password.  The
X		 * new password will then be encrypted in the normal
X		 * fashion with a new salt generated.
X		 */
X
X		name = buf;
X		if (cp = strchr (name, ':')) {
X			*cp++ = '\0';
X		} else {
X			fprintf (stderr, "%s: line %d: missing new password\n",
X				Prog, line);
X			errors++;
X			continue;
X		}
X		newpwd = cp;
X		cp = pw_encrypt (newpwd, (char *) 0);
X
X		/*
X		 * Get the password file entry for this user.  The user
X		 * must already exist.
X		 */
X
X#ifdef	SHADOWPWD
X		if (! (sp = spw_locate (name)))
X#else
X		if (! (pw = pw_locate (name)))
X#endif
X		{
X			fprintf (stderr, "%s: line %d: unknown user %s\n",
X				Prog, line, name);
X			errors++;
X			continue;
X		}
X
X		/*
X		 * The freshly encrypted new password is merged into
X		 * the user's password file entry and the last password
X		 * change date is set to the current date.
X		 */
X
X#ifdef	SHADOWPWD
X		newsp = *sp;
X		newsp.sp_pwdp = cp;
X		newsp.sp_lstchg = now;
X#else
X		newpw = *pw;
X		newpw.pw_passwd = cp;
X#ifdef	ATT_AGE
X		if (newpw.pw_age[0]) {
X			strcpy (newage, newpw.pw_age);
X			strcpy (newage + 2, l64a (now / 7));
X			newpw.pw_age = newage;
X		}
X#endif
X#endif
X
X		/* 
X		 * The updated password file entry is then put back
X		 * and will be written to the password file later, after
X		 * all the other entries have been updated as well.
X		 */
X
X#ifdef	SHADOWPWD
X		if (! spw_update (&newsp))
X#else
X		if (! pw_update (&newpw))
X#endif
X		{
X			fprintf (stderr, "%s: line %d: cannot update password entry\n",
X				Prog, line);
X			errors++;
X			continue;
X		}
X	}
X
X	/*
X	 * Any detected errors will cause the entire set of changes
X	 * to be aborted.  Unlocking the password file will cause
X	 * all of the changes to be ignored.  Otherwise the file is
X	 * closed, causing the changes to be written out all at
X	 * once, and then unlocked afterwards.
X	 */
X
X	if (errors) {
X		fprintf ("%s: error detected, changes ignored\n", Prog);
X		pw_unlock ();
X		exit (1);
X	}
X	if (! pw_close ()) {
X		fprintf ("%s: error updating password file\n", Prog);
X		exit (1);
X	}
X	(void) pw_unlock ();
X}
SHAR_EOF
if test 5114 -ne "`wc -c < 'chpasswd.c'`"
then
	echo shar: "error transmitting 'chpasswd.c'" '(should have been 5114 characters)'
fi
fi
echo shar: "extracting 'newusers.c'" '(13360 characters)'
if test -f 'newusers.c'
then
	echo shar: "will not over-write existing file 'newusers.c'"
else
sed 's/^X//' << \SHAR_EOF > 'newusers.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 *	newusers - create users from a batch file
X *
X *	newusers creates a collection of entries in /etc/passwd
X *	and related files by reading a passwd-format file and
X *	adding entries in the related directories.
X */
X
X#include <stdio.h>
X#include "pwd.h"
X#include <grp.h>
X#include <fcntl.h>
X#include <string.h>
X#include "config.h"
X#ifdef	SHADOWPWD
X#include "shadow.h"
X#endif
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)newusers.c	3.2	12:31:02	12/12/90";
X#endif
X
Xchar	*Prog;
X
Xextern	char	*pw_encrypt();
X
Xint	pw_lock(), gr_lock();
Xint	pw_open(), gr_open();
Xstruct	passwd	*pw_locate(), *pw_next();
Xstruct	group	*gr_locate(), *gr_next();
Xint	pw_update(), gr_update();
Xint	pw_close(), gr_close();
Xint	pw_unlock(), gr_unlock();
X
X#ifdef	SHADOWPWD
Xint	spw_lock(), spw_open(), spw_update(), spw_close(), spw_unlock();
Xstruct	spwd	*spw_locate(), *spw_next();
X#endif
X
X#ifndef	MKDIR
X
X/*
X * mkdir - for those of us with no mkdir() system call.
X */
X
Xmkdir (dir, mode)
Xchar	*dir;
Xint	mode;
X{
X	int	mask;
X	int	status;
X	int	pid;
X	int	i;
X	char	buf[BUFSIZ];
X
X	mode = (~mode & 0777);
X	mask = umask (mode);
X	if ((pid = fork ()) == 0) {
X		execl ("/bin/mkdir", "mkdir", dir, (char *) 0);
X		perror ("/bin/mkdir");
X		_exit (1);
X	} else {
X		while ((i = wait (&status)) != pid && i != -1)
X			;
X	}
X	umask (mask);
X	return status;
X}
X#endif
X
X/*
X * usage - display usage message and exit
X */
X
Xusage ()
X{
X	fprintf (stderr, "Usage: %s [ input ]\n", Prog);
X	exit (1);
X}
X
X/*
X * add_group - create a new group or add a user to an existing group
X */
X
Xint
Xadd_group (name, uid, gid, ngid)
Xchar	*name;
Xchar	*uid;
Xchar	*gid;
Xint	*ngid;
X{
X	struct	passwd	*pwd;
X	struct	group	*grp;
X	struct	group	grent;
X	char	*members[2];
X	int	i;
X
X	/*
X	 * Start by seeing if the named group already exists.  This
X	 * will be very easy to deal with if it does.
X	 */
X
X	if (grp = gr_locate (gid)) {
Xadd_member:
X		grent = *grp;
X		*ngid = grent.gr_gid;
X		for (i = 0;grent.gr_mem[i] != (char *) 0;i++)
X			if (strcmp (grent.gr_mem[i], name) == 0)
X				return 0;
X
X		if (! (grent.gr_mem = (char **)
X				malloc (sizeof (char *) * (i + 2)))) {
X			fprintf (stderr, "%s: Out of Memory\n", Prog);
X			return -1;
X		}
X		memcpy (grent.gr_mem, grp->gr_mem, sizeof (char *) * (i + 2));
X		grent.gr_mem[i] = strdup (name);
X		grent.gr_mem[i + 1] = (char *) 0;
X
X		return ! gr_update (&grent);
X	}
X
X	/*
X	 * The group did not exist, so I try to figure out what the
X	 * GID is going to be.  The gid parameter is probably "", meaning
X	 * I figure out the GID from the password file.  I want the UID
X	 * and GID to match, unless the GID is already used.
X	 */
X
X	if (gid[0] == '\0') {
X		i = 100;
X		for (pw_rewind ();pwd = pw_next ();) {
X			if (pwd->pw_uid >= i)
X				i = pwd->pw_uid + 1;
X		}
X		for (gr_rewind ();grp = gr_next ();) {
X			if (grp->gr_gid == i) {
X				i = -1;
X				break;
X			}
X		}
X	} else if (gid[0] >= '0' && gid[0] <= '9') {
X
X	/*
X	 * The GID is a number, which means either this is a brand new
X	 * group, or an existing group.  For existing groups I just add
X	 * myself as a member, just like I did earlier.
X	 */
X
X		i = atoi (gid);
X		for (gr_rewind ();grp = gr_next ();)
X			if (grp->gr_gid == i)
X				goto add_member;
X	} else
X
X	/*
X	 * The last alternative is that the GID is a name which is not
X	 * already the name of an existing group, and I need to figure
X	 * out what group ID that group name is going to have.
X	 */
X
X		i = -1;
X
X	/*
X	 * If I don't have a group ID by now, I'll go get the
X	 * next one.
X	 */
X
X	if (i == -1) {
X		for (i = 100, gr_rewind;grp = gr_next ();)
X			if (grp->gr_gid >= i)
X				i = grp->gr_gid + 1;
X	}
X
X	/*
X	 * Now I have all of the fields required to create the new
X	 * group.
X	 */
X
X	if (gid[0] && (gid[0] <= '0' || gid[0] >= '9'))
X		grent.gr_name = gid;
X	else
X		grent.gr_name = name;
X
X	grent.gr_passwd = "!";
X	grent.gr_gid = i;
X	members[0] = name;
X	members[1] = (char *) 0;
X	grent.gr_mem = members;
X
X	*ngid = grent.gr_gid;
X	return ! gr_update (&grent);
X}
X
X/*
X * add_user - create a new user ID
X */
X
Xadd_user (name, uid, nuid, gid)
Xchar	*name;
Xchar	*uid;
Xint	*nuid;
Xint	gid;
X{
X	struct	passwd	*pwd;
X	struct	passwd	pwent;
X	int	i;
X
X	/*
X	 * The first guess for the UID is either the numerical UID
X	 * that the caller provided, or the next available UID.
X	 */
X
X	if (uid[0] >= '0' && uid[0] <= '9') {
X		i = atoi (uid);
X	} if (uid[0] && (pwd = pw_locate (uid))) {
X		i = pwd->pw_uid;
X	} else {
X		i = 100;
X		for (pw_rewind ();pwd = pw_next ();)
X			if (pwd->pw_uid >= i)
X				i = pwd->pw_uid + 1;
X	}
X
X	/*
X	 * I don't want to fill in the entire password structure
X	 * members JUST YET, since there is still more data to be
X	 * added.  So, I fill in the parts that I have.
X	 */
X
X	pwent.pw_name = name;
X	pwent.pw_passwd = "!";
X#ifdef	ATT_AGE
X	pwent.pw_age = "";
X#endif
X#ifdef	ATT_COMMENT
X	pwent.pw_comment = "";
X#endif
X#ifdef	BSD_QUOTAS
X	pwent.pw_quota = 0;
X#endif
X	pwent.pw_uid = i;
X	pwent.pw_gid = gid;
X	pwent.pw_gecos = "";
X	pwent.pw_dir = "";
X	pwent.pw_shell = "";
X
X	*nuid = i;
X	return ! pw_update (&pwent);
X}
X
X/*
X * add_passwd - add or update the encrypted password
X */
X
Xadd_passwd (pwd, passwd)
Xstruct	passwd	*pwd;
Xchar	*passwd;
X{
X#ifdef	SHADOWPWD
X	struct	spwd	*sp;
X	struct	spwd	spent;
X#endif
X	struct	passwd	*pw;
X	struct	passwd	pwent;
X	static	char	newage[5];
X
X	/*
X	 * In the case of regular password files, this is real
X	 * easy - pwd points to the entry in the password file.
X	 * Shadow files are harder since there are zillions of
X	 * things to do ...
X	 */
X
X#ifndef	SHADOWPWD
X	pwd->pw_passwd = pw_encrypt (passwd, (char *) 0);
X#ifdef	ATT_AGE
X	if (strlen (pwd->pw_age) == 4) {
X		strcpy (newage, pwd->pw_age);
X		strcpy (newage + 2,
X			l64a (time ((long *) 0) / (7L*24L*3600L)));
X		pwd->pw_age = newage;
X	}
X#endif	/* ATT_AGE */
X	return 0;
X#else
X
X	/*
X	 * Do the first and easiest shadow file case.  The user
X	 * already exists in the shadow password file.
X	 */
X
X	if (sp = spw_locate (pwd->pw_name)) {
X		spent = *sp;
X		spent.sp_pwdp = pw_encrypt (passwd, (char *) 0);
X		return ! spw_update (sp);
X	}
X
X	/*
X	 * Pick the next easiest case - the user has an encrypted
X	 * password which isn't equal to "!".  The password was set
X	 * to "!" earlier when the entry was created, so this user
X	 * would have to have had the password set someplace else.
X	 */
X
X	if (strcmp (pwd->pw_passwd, "!") != 0) {
X		pwd->pw_passwd = pw_encrypt (passwd, (char *) 0);
X#ifdef	ATT_AGE
X		if (strlen (pwd->pw_age) == 4) {
X			strcpy (newage, pwd->pw_age);
X			strcpy (newage + 2,
X				l64a (time ((long *) 0) / (7L*24L*3600L)));
X			pwd->pw_age = newage;
X		}
X#endif	/* ATT_AGE */
X		return 0;
X	}
X
X	/*
X	 * Now the really hard case - I need to create an entirely
X	 * shadow password file entry.
X	 */
X
X	spent.sp_namp = pwd->pw_name;
X	spent.sp_pwdp = pw_encrypt (passwd, (char *) 0);
X	spent.sp_lstchg = time ((long *) 0) / (24L*3600L);
X#ifdef	MINDAYS
X	spent.sp_min = MINDAYS;
X#else
X	spent.sp_min = 0;
X#endif
X#ifdef	MAXDAYS
X	spent.sp_max = MAXDAYS;
X#else
X	spent.sp_max = 10000;		/* 10000 is infinity this week */
X#endif
X#ifdef	WARNAGE
X	spent.sp_warn = WARNAGE;
X#else
X	spent.sp_warn = -1;
X#endif
X	spent.sp_inact = -1;
X	spent.sp_expire = -1;
X	spent.sp_flag = -1;
X
X	return ! spw_update (&spent);
X#endif
X}
X
Xmain (argc, argv)
Xint	argc;
Xchar	**argv;
X{
X	char	buf[BUFSIZ];
X	char	*fields[8];
X	int	nfields;
X	char	*name;
X	char	*newpwd;
X	char	*cp;
X#ifdef	SHADOWPWD
X	struct	spwd	*sp;
X	struct	spwd	newsp;
X	struct	spwd	*spw_locate();
X#endif
X	struct	passwd	*pw;
X	struct	passwd	newpw;
X	struct	passwd	*pw_locate();
X	char	newage[5];
X	int	errors = 0;
X	int	line = 0;
X	long	now = time ((long *) 0) / (24L*3600L);
X	int	uid;
X	int	gid;
X	int	i;
X
X	if (Prog = strrchr (argv[0], '/'))
X		Prog++;
X	else
X		Prog = argv[0];
X
X	if (argc > 1 && argv[1][0] == '-')
X		usage ();
X
X	if (argc == 2) {
X		if (! freopen (argv[1], "r", stdin)) {
X			sprintf (buf, "%s: %s", Prog, argv[1]);
X			perror (buf);
X			exit (1);
X		}
X	}
X
X	/*
X	 * Lock the password files and open them for update.  This will
X	 * bring all of the entries into memory where they may be
X	 * searched for an modified, or new entries added.  The password
X	 * file is the key - if it gets locked, assume the others can
X	 * be locked right away.
X	 */
X
X	for (i = 0;i < 30;i++) {
X		if (pw_lock ())
X			break;
X	}
X	if (i == 30) {
X		fprintf (stderr, "%s: can't lock /etc/passwd.\n", Prog);
X		exit (1);
X	}
X#ifdef	SHADOWPWD
X	if (! spw_lock () || ! gr_lock ())
X#else
X	if (! gr_lock ())
X#endif
X	{
X		fprintf (stderr, "%s: can't lock files, try again later\n",
X			Prog);
X		(void) pw_unlock ();
X#ifdef	SHADOWPWD
X		(void) spw_unlock ();
X#endif
X		exit (1);
X	}
X#ifdef	SHADOWPWD
X	if (! pw_open (O_RDWR) || ! spw_open (O_RDWR) || ! gr_open (O_RDWR))
X#else
X	if (! pw_open (O_RDWR) || ! gr_open (O_RDWR))
X#endif
X	{
X		fprintf (stderr, "%s: can't open files\n", Prog);
X		(void) pw_unlock ();
X#ifdef	SHADOWPWD
X		(void) spw_unlock ();
X#endif
X		(void) gr_unlock ();
X		exit (1);
X	}
X
X	/*
X	 * Read each line.  The line has the same format as a password
X	 * file entry, except that certain fields are not contrained to
X	 * be numerical values.  If a group ID is entered which does
X	 * not already exist, an attempt is made to allocate the same
X	 * group ID as the numerical user ID.  Should that fail, the
X	 * next available group ID over 100 is allocated.  The pw_gid
X	 * field will be updated with that value.
X	 */
X
X	while (fgets (buf, sizeof buf, stdin) != (char *) 0) {
X		line++;
X		if (cp = strrchr (buf, '\n')) {
X			*cp = '\0';
X		} else {
X			fprintf (stderr, "%s: line %d: line too long\n",
X				Prog, line);
X			errors++;
X			continue;
X		}
X
X		/*
X		 * Break the string into fields and screw around with
X		 * them.  There MUST be 7 colon separated fields,
X		 * although the values aren't that particular.
X		 */
X
X		for (cp = buf, nfields = 0;nfields < 7;nfields++) {
X			fields[nfields] = cp;
X			if (cp = strchr (cp, ':'))
X				*cp++ = '\0';
X			else
X				break;
X		}
X		if (*cp || nfields != 6) {
X			fprintf (stderr, "%s: line %d: invalid line\n",
X				Prog, line);
X			continue;
X		}
X
X		/*
X		 * Now the fields are processed one by one.  The first
X		 * field to be processed is the group name.  A new
X		 * group will be created if the group name is non-numeric
X		 * and does not already exist.  The named user will be
X		 * the only member.  If there is no named group to be a
X		 * member of, the UID will be figured out and that value
X		 * will be a candidate for a new group, if that group ID
X		 * exists, a whole new group ID will be made up.
X		 */
X		
X		if (! (pw = pw_locate (fields[0])) &&
X			add_group (fields[0], fields[2], fields[3], &gid)) {
X			fprintf (stderr, "%s: %d: can't create GID\n",
X				Prog, line);
X			errors++;
X			continue;
X		}
X
X		/*
X		 * Now we work on the user ID.  It has to be specified
X		 * either as a numerical value, or left blank.  If it
X		 * is a numerical value, that value will be used, otherwise
X		 * the next available user ID is computed and used.  After
X		 * this there will at least be a (struct passwd) for the
X		 * user.
X		 */
X
X		if (! pw && add_user (fields[0], fields[2], &uid, gid)) {
X			fprintf (stderr, "%s: line %d: can't create UID\n",
X				Prog, line);
X			errors++;
X			continue;
X		}
X
X		/*
X		 * The password, gecos field, directory, and shell fields
X		 * all come next.
X		 */
X
X		if (! (pw = pw_locate (fields[0]))) {
X			fprintf (stderr, "%s: line %d: cannot find user %s\n",
X				Prog, line, fields[0]);
X			errors++;
X			continue;
X		}
X		newpw = *pw;
X
X		if (add_passwd (&newpw, fields[1])) {
X			fprintf (stderr, "%s: line %d: can't update password\n",
X				Prog, line);
X			errors++;
X			continue;
X		}
X		if (fields[4][0])
X			newpw.pw_gecos = fields[4];
X
X		if (fields[5][0])
X			newpw.pw_dir = fields[5];
X
X		if (fields[6][0])
X			newpw.pw_shell = fields[6];
X
X		if (newpw.pw_dir[0] && access (newpw.pw_dir, 0)) {
X#ifdef	UMASK
X			if (mkdir (newpw.pw_dir, 0777 & (~UMASK)))
X#else
X			if (mkdir (newpw.pw_dir, 0777))
X#endif
X				fprintf (stderr, "%s: line %d: mkdir failed\n",
X					Prog, line);
X			else if (chown (newpw.pw_dir,
X					newpw.pw_uid, newpw.pw_gid))
X				fprintf (stderr, "%s: line %d: chown failed\n",
X					Prog, line);
X		}
X
X		/*
X		 * Update the password entry with the new changes made.
X		 */
X
X		if (! pw_update (&newpw)) {
X			fprintf (stderr, "%s: line %d: can't update entry\n",
X				Prog, line);
X			errors++;
X			continue;
X		}
X	}
X
X	/*
X	 * Any detected errors will cause the entire set of changes
X	 * to be aborted.  Unlocking the password file will cause
X	 * all of the changes to be ignored.  Otherwise the file is
X	 * closed, causing the changes to be written out all at
X	 * once, and then unlocked afterwards.
X	 */
X
X	if (errors) {
X		fprintf ("%s: error detected, changes ignored\n", Prog);
X		(void) gr_unlock ();
X#ifdef	SHADOWPWD
X		(void) spw_unlock ();
X#endif
X		(void) pw_unlock ();
X		exit (1);
X	}
X#ifdef	SHADOWPWD
X	if (! pw_close () || ! spw_close () || ! gr_close ())
X#else
X	if (! pw_close () || ! gr_close ())
X#endif
X	{
X		fprintf ("%s: error updating files\n", Prog);
X		(void) gr_unlock ();
X#ifdef	SHADOWPWD
X		(void) spw_unlock ();
X#endif
X		(void) pw_unlock ();
X		exit (1);
X	}
X	(void) gr_unlock ();
X#ifdef	SHADOWPWD
X	(void) spw_unlock ();
X#endif
X	(void) pw_unlock ();
X
X	exit (0);
X}
SHAR_EOF
if test 13360 -ne "`wc -c < 'newusers.c'`"
then
	echo shar: "error transmitting 'newusers.c'" '(should have been 13360 characters)'
fi
fi
echo shar: "extracting 'rad64.c'" '(1670 characters)'
if test -f 'rad64.c'
then
	echo shar: "will not over-write existing file 'rad64.c'"
else
sed 's/^X//' << \SHAR_EOF > 'rad64.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#ifndef	lint
Xstatic	char	sccsid[] = "@(#)rad64.c	3.2	19:44:25	12/10/90";
X#endif
X
X/*
X * c64i - convert a radix 64 character to an integer
X */
X
Xint	c64i (c)
Xchar	c;
X{
X	if (c == '.')
X		return (0);
X
X	if (c == '/')
X		return (1);
X
X	if (c >= '0' && c <= '9')
X		return (c - '0' + 2);
X
X	if (c >= 'A' && c <= 'Z')
X		return (c - 'A' + 12);
X
X	if (c >= 'a' && c <= 'z')
X		return (c - 'a' + 38);
X	else
X		return (-1);
X}
X
X/*
X * i64c - convert an integer to a radix 64 character
X */
X
Xint	i64c (i)
Xint	i;
X{
X	if (i < 0)
X		return ('.');
X	else if (i > 63)
X		return ('z');
X
X	if (i == 0)
X		return ('.');
X
X	if (i == 1)
X		return ('/');
X
X	if (i >= 2 && i <= 11)
X		return ('0' - 2 + i);
X
X	if (i >= 12 && i <= 37)
X		return ('A' - 12 + i);
X
X	if (i >= 38 && i <= 63)
X		return ('a' - 38 + i);
X
X	return ('\0');
X}
X
X/*
X * l64a - convert a long to a string of radix 64 characters
X */
X
Xchar	*l64a (l)
Xlong	l;
X{
X	static	char	buf[8];
X	int	i = 0;
X
X	if (i < 0L)
X		return ((char *) 0);
X
X	do {
X		buf[i++] = i64c ((int) (l % 64));
X		buf[i] = '\0';
X	} while (l /= 64L, l > 0 && i < 6);
X
X	return (buf);
X}
X
X/*
X * a64l - convert a radix 64 string to a long integer
X */
X
Xlong	a64l (s)
Xchar	*s;
X{
X	int	i;
X	long	value;
X	long	shift = 0;
X
X	for (i = 0, value = 0L;i < 6 && *s;s++) {
X		value += (c64i (*s) << shift);
X		shift += 6;
X	}
X	return (value);
X}
SHAR_EOF
if test 1670 -ne "`wc -c < 'rad64.c'`"
then
	echo shar: "error transmitting 'rad64.c'" '(should have been 1670 characters)'
fi
fi
echo shar: "extracting 'dialchk.c'" '(1328 characters)'
if test -f 'dialchk.c'
then
	echo shar: "will not over-write existing file 'dialchk.c'"
else
sed 's/^X//' << \SHAR_EOF > 'dialchk.c'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * 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#ifdef	BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X#include "config.h"
X#include "dialup.h"
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)dialchk.c	3.2	19:44:18	12/10/90";
X#endif
X
Xextern	char	*pw_encrypt();
X
X/*
X * Check for dialup password
X *
X *	dialcheck tests to see if tty is listed as being a dialup
X *	line.  If so, a dialup password may be required if the shell
X *	is listed as one which requires a second password.
X */
X
Xint	dialcheck (tty, shell)
Xchar	*tty;
Xchar	*shell;
X{
X	char	*crypt ();
X	char	*getpass ();
X	struct	dialup	*dialup;
X	char	*pass;
X	char	*cp;
X
X	setduent ();
X
X	if (! isadialup (tty)) {
X		endduent ();
X		return (1);
X	}
X	if (! (dialup = getdushell (shell))) {
X		endduent ();
X		return (1);
X	}
X	endduent ();
X
X	if (dialup->du_passwd[0] == '\0')
X		return (1);
X
X	if (! (pass = getpass ("Dialup Password:")))
X		return (0);
X
X	cp = pw_encrypt (pass, dialup->du_passwd);
X	return (strcmp (cp, dialup->du_passwd) == 0);
X}
SHAR_EOF
if test 1328 -ne "`wc -c < 'dialchk.c'`"
then
	echo shar: "error transmitting 'dialchk.c'" '(should have been 1328 characters)'
fi
fi
echo shar: "extracting 'faillog.h'" '(715 characters)'
if test -f 'faillog.h'
then
	echo shar: "will not over-write existing file 'faillog.h'"
else
sed 's/^X//' << \SHAR_EOF > 'faillog.h'
X/*
X * Copyright 1989, 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X/*
X * faillog.h - login failure logging file format
X *
X *	@(#)faillog.h	2.2	19:23:46	7/29/90
X *
X * The login failure file is maintained by login(1) and fail(1L)
X * Each record in the file represents a separate UID and the file
X * is indexed in that fashion.
X */
X
X#define	FAILFILE	"/usr/adm/faillog"
X
Xstruct	faillog {
X	short	fail_cnt;	/* failures since last success */
X	short	fail_max;	/* failures before turning account off */
X	char	fail_line[12];	/* last failure occured here */
X	time_t	fail_time;	/* last failure occured then */
X};
SHAR_EOF
if test 715 -ne "`wc -c < 'faillog.h'`"
then
	echo shar: "error transmitting 'faillog.h'" '(should have been 715 characters)'
fi
fi
echo shar: "extracting 'pwdbm.c'" '(1637 characters)'
if test -f 'pwdbm.c'
then
	echo shar: "will not over-write existing file 'pwdbm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'pwdbm.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#ifndef	lint
Xstatic	char	sccsid[] = "@(#)pwdbm.c	3.3	12:31:13	12/12/90";
X#endif
X
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 <stdio.h>
X#include "pwd.h"
X#include "config.h"
X
X#ifdef	DBM
X#include <dbm.h>
X#endif
X#ifdef	NDBM
X#include <ndbm.h>
XDBM	*pw_dbm;
X#endif
X
X/*
X * pw_dbm_update
X *
X * Updates the DBM password files, if they exist.
X */
X
Xint
Xpw_dbm_update (pw)
Xstruct	passwd	*pw;
X{
X	datum	key;
X	datum	content;
X	char	data[BUFSIZ];
X	int	len;
X	static	int	once;
X
X	if (! once) {
X#ifdef	NDBM
X		if (! pw_dbm)
X			setpwent ();
X#else
X		setpwent ();
X#endif
X		once++;
X	}
X#ifdef	DBM
X	strcpy (data, PWDFILE);
X	strcat (data, ".pag");
X	if (access (data, 0))
X		return 0;
X#endif
X#ifdef	NDBM
X	if (! pw_dbm)
X		return 0;
X#endif
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#ifdef	DBM
X	if (store (key, content))
X		return 0;
X#endif
X#ifdef	NDBM
X	if (dbm_store (pw_dbm, key, content, DBM_REPLACE))
X		return 0;
X#endif
X
X	key.dsize = sizeof pw->pw_uid;
X	key.dptr = (char *) &pw->pw_uid;
X#ifdef	DBM
X	if (store (key, content))
X		return 0;
X#endif
X#ifdef	NDBM
X	if (dbm_store (pw_dbm, key, content, DBM_REPLACE))
X		return 0;
X#endif
X	return 1;
X}
SHAR_EOF
if test 1637 -ne "`wc -c < 'pwdbm.c'`"
then
	echo shar: "error transmitting 'pwdbm.c'" '(should have been 1637 characters)'
fi
fi
echo shar: "extracting 'grdbm.c'" '(2117 characters)'
if test -f 'grdbm.c'
then
	echo shar: "will not over-write existing file 'grdbm.c'"
else
sed 's/^X//' << \SHAR_EOF > 'grdbm.c'
X/*
X * Copyright 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X */
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)grdbm.c	3.1	08:11:52	11/21/90";
X#endif
X
X#include <string.h>
X#include <stdio.h>
X#include <grp.h>
X#include "config.h"
X
X#ifdef	NDBM
X#include <ndbm.h>
XDBM	*gr_dbm;
X
X#define	GRP_FRAG	256
X
X/*
X * gr_dbm_update
X *
X * Updates the DBM password files, if they exist.
X */
X
Xint
Xgr_dbm_update (gr)
Xstruct	group	*gr;
X{
X	datum	key;
X	datum	content;
X	char	data[BUFSIZ*8];
X	char	grpkey[60];
X	char	*cp;
X	int	len;
X	int	i;
X	int	cnt;
X	static	int	once;
X
X	if (! once) {
X		if (! gr_dbm)
X			setgrent ();
X
X		once++;
X	}
X	if (! gr_dbm)
X		return 0;
X
X	len = gr_pack (gr, data);
X
X	if (len <= GRP_FRAG) {
X		content.dsize = len;
X		content.dptr = data;
X
X		key.dsize = strlen (gr->gr_name);
X		key.dptr = gr->gr_name;
X		if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
X			return 0;
X
X		key.dsize = sizeof gr->gr_gid;
X		key.dptr = (char *) &gr->gr_gid;
X		if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
X			return 0;
X
X	} else {
X		content.dsize = sizeof cnt;
X		content.dptr = (char *) &cnt;
X		cnt = (len + (GRP_FRAG-1)) / GRP_FRAG;
X
X		key.dsize = strlen (gr->gr_name);
X		key.dptr = gr->gr_name;
X		if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
X			return 0;
X
X		key.dsize = sizeof gr->gr_gid;
X		key.dptr = (char *) &gr->gr_gid;
X		if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
X			return 0;
X
X		for (cp = data, i = 0;i < cnt;i++) {
X			content.dsize = len > GRP_FRAG ? GRP_FRAG:len;
X			len -= content.dsize;
X			content.dptr = cp;
X			cp += content.dsize;
X
X			key.dsize = sizeof i + strlen (gr->gr_name);
X			key.dptr = grpkey;
X			memcpy (grpkey, &i, sizeof i);
X			strcpy (grpkey + sizeof i, gr->gr_name);
X			if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
X				return 0;
X
X			key.dsize = sizeof i + sizeof gr->gr_gid;
X			key.dptr = grpkey;
X			memcpy (grpkey, &i, sizeof i);
X			memcpy (grpkey + sizeof i, &gr->gr_gid,
X				sizeof gr->gr_gid);
X			if (dbm_store (gr_dbm, key, content, DBM_REPLACE))
X				return 0;
X		}
X	}
X	return 1;
X}
X#endif
SHAR_EOF
if test 2117 -ne "`wc -c < 'grdbm.c'`"
then
	echo shar: "error transmitting 'grdbm.c'" '(should have been 2117 characters)'
fi
fi
echo shar: "extracting 'gshadow.c'" '(4652 characters)'
if test -f 'gshadow.c'
then
	echo shar: "will not over-write existing file 'gshadow.c'"
else
sed 's/^X//' << \SHAR_EOF > 'gshadow.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 "shadow.h"
X#include "config.h"
X#include <stdio.h>
X#ifndef	BSD
X#include <string.h>
X#include <memory.h>
X#else
X#include <strings.h>
X#define	strchr	index
X#define	strrchr	rindex
X#endif
X
X#ifdef	NDBM
X#include <ndbm.h>
X#include <fcntl.h>
XDBM	*sg_dbm;
Xint	sg_dbm_mode;
Xstatic	int	dbmopened;
Xstatic	int	dbmerror;
X#endif
X
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)gshadow.c	3.3	11:25:55	12/19/90";
X#endif
X
X#define	MAXMEM	1024
X
Xstatic	FILE	*shadow;
Xstatic	char	*sgrpfile = "/etc/gshadow";
Xstatic	char	sgrbuf[BUFSIZ*4];
Xstatic	char	*members[MAXMEM+1];
Xstatic	char	*admins[MAXMEM+1];
Xstatic	struct	sgrp	sgroup;
X
Xextern	char	*fgetsx();
Xextern	int	fputsx();
X
X#define	FIELDS	4
X
Xstatic char **
Xlist (s, l)
Xchar	*s;
Xchar	**l;
X{
X	int	nmembers = 0;
X
X	while (*s) {
X		l[nmembers++] = s;
X		if (s = strchr (s, ','))
X			*s++ = '\0';
X	}
X	l[nmembers] = (char *) 0;
X	return l;
X}
X
Xvoid
Xsetsgent ()
X{
X#ifdef	NDBM
X	int	mode;
X#endif	/* NDBM */
X
X	if (shadow)
X		rewind (shadow);
X	else
X		shadow = fopen (GSHADOW, "r");
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#ifdef NDBM
X	if (! dbmerror && ! dbmopened) {
X		char	dbmfiles[BUFSIZ];
X
X		strcpy (dbmfiles, sgrpfile);
X		strcat (dbmfiles, ".pag");
X		if (sg_dbm_mode != -1)
X			mode = O_RDONLY;
X		else
X			mode = (sg_dbm_mode == O_RDONLY ||
X				sg_dbm_mode == O_RDWR) ? sg_dbm_mode:O_RDONLY;
X
X		if (access (dbmfiles, 0) ||
X			(! (sg_dbm = dbm_open (sgrpfile, mode, 0))))
X			dbmerror = 1;
X		else
X			dbmopened = 1;
X	}
X#endif	/* NDBM */
X}
X
Xvoid
Xendsgent ()
X{
X	if (shadow)
X		(void) fclose (shadow);
X
X	shadow = (FILE *) 0;
X#ifdef	NDBM
X	if (dbmopened && sg_dbm) {
X		dbm_close (sg_dbm);
X		dbmopened = 0;
X		sg_dbm = 0;
X	}
X#endif
X}
X
Xstruct sgrp *
Xsgetsgent (string)
Xchar	*string;
X{
X	char	*fields[FIELDS];
X	char	*cp;
X	char	*cpp;
X	int	atoi ();
X	long	atol ();
X	int	i;
X
X	strncpy (sgrbuf, string, sizeof sgrbuf - 1);
X	sgrbuf[sizeof sgrbuf - 1] = '\0';
X
X	if (cp = strrchr (sgrbuf, '\n'))
X		*cp = '\0';
X
X	for (cp = sgrbuf, i = 0;*cp && i < FIELDS;i++) {
X		fields[i] = cp;
X		while (*cp && *cp != ':')
X			cp++;
X
X		if (*cp)
X			*cp++ = '\0';
X	}
X	if (*cp || i != FIELDS)
X		return 0;
X
X	sgroup.sg_name = fields[0];
X	sgroup.sg_passwd = fields[1];
X	sgroup.sg_adm = list (fields[2], admins);
X	sgroup.sg_mem = list (fields[3], members);
X
X	return &sgroup;
X}
X
Xstruct sgrp
X*fgetsgent (fp)
XFILE	*fp;
X{
X	char	buf[sizeof sgrbuf];
X
X	if (! fp)
X		return (0);
X
X	if (fgetsx (buf, sizeof buf, fp) == (char *) 0)
X		return (0);
X
X	return sgetsgent (buf);
X}
X
Xstruct sgrp
X*getsgent ()
X{
X	if (! shadow)
X		setsgent ();
X
X	return (fgetsgent (shadow));
X}
X
Xstruct sgrp *
Xgetsgnam (name)
Xchar	*name;
X{
X	struct	sgrp	*sgrp;
X#ifdef NDBM
X	datum	key;
X	datum	content;
X#endif
X
X	setsgent ();
X
X#ifdef NDBM
X
X	/*
X	 * If the DBM file are now open, create a key for this group 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
X		content = dbm_fetch (sg_dbm, key);
X		if (content.dptr != 0) {
X			memcpy (sgrbuf, content.dptr, content.dsize);
X			sgroup.sg_mem = members;
X			sgroup.sg_adm = admins;
X			sgr_unpack (sgrbuf, content.dsize, &sgroup);
X			return &sgroup;
X		}
X	}
X#endif
X	while ((sgrp = getsgent ()) != (struct sgrp *) 0) {
X		if (strcmp (name, sgrp->sg_name) == 0)
X			return (sgrp);
X	}
X	return (0);
X}
X
Xint
Xputsgent (sgrp, fp)
Xstruct	sgrp	*sgrp;
XFILE	*fp;
X{
X	char	buf[sizeof sgrbuf];
X	char	*cp = buf;
X	int	errors = 0;
X	int	i;
X
X	if (! fp || ! sgrp)
X		return -1;
X
X	/*
X	 * Copy the group name and passwd.
X	 */
X
X	strcpy (cp, sgrp->sg_name);
X	cp += strlen (cp);
X	*cp++ = ':';
X
X	strcpy (cp, sgrp->sg_passwd);
X	cp += strlen (cp);
X	*cp++ = ':';
X
X	/*
X	 * Copy the administrators, separating each from the other
X	 * with a ",".
X	 */
X
X	for (i = 0;sgrp->sg_adm[i];i++) {
X		if (i > 0)
X			*cp++ = ',';
X
X		strcpy (cp, sgrp->sg_adm[i]);
X		cp += strlen (cp);
X	}
X	*cp++ = ':';
X
X	/*
X	 * Now do likewise with the group members.
X	 */
X
X	for (i = 0;sgrp->sg_mem[i];i++) {
X		if (i > 0)
X			*cp++ = ',';
X
X		strcpy (cp, sgrp->sg_mem[i]);
X		cp += strlen (cp);
X	}
X	*cp++ = '\n';
X	*cp = '\0';
X
X	/*
X	 * Output using the function which understands the line
X	 * continuation conventions.
X	 */
X
X	return fputsx (buf, fp);
X}
SHAR_EOF
if test 4652 -ne "`wc -c < 'gshadow.c'`"
then
	echo shar: "error transmitting 'gshadow.c'" '(should have been 4652 characters)'
fi
fi
echo shar: "extracting 'sppack.c'" '(2142 characters)'
if test -f 'sppack.c'
then
	echo shar: "will not over-write existing file 'sppack.c'"
else
sed 's/^X//' << \SHAR_EOF > 'sppack.c'
X/*
X * Copyright 1990, John F. Haugh II
X * All rights reserved.
X *
X * Use, duplication, and disclosure prohibited without
X * the express written permission of the author.
X *
X * Duplication is permitted for non-commercial [ profit making ]
X * purposes provided this and other copyright notices remain
X * intact.
X */
X
X#include <stdio.h>
X#ifdef	BSD
X#include <strings.h>
X#else
X#include <string.h>
X#endif
X
X#include "shadow.h"
X
X#ifndef	lint
Xstatic	char	sccsid[] = "@(#)sppack.c	3.1	08:16:27	11/21/90";
X#endif
X
Xint	spw_pack (spwd, buf)
Xstruct	spwd	*spwd;
Xchar	*buf;
X{
X	char	*cp;
X
X	cp = buf;
X	strcpy (cp, spwd->sp_namp);
X	cp += strlen (cp) + 1;
X
X	strcpy (cp, spwd->sp_pwdp);
X	cp += strlen (cp) + 1;
X
X	memcpy (cp, &spwd->sp_min, sizeof spwd->sp_min);
X	cp += sizeof spwd->sp_min;
X
X	memcpy (cp, &spwd->sp_max, sizeof spwd->sp_max);
X	cp += sizeof spwd->sp_max;
X
X	memcpy (cp, &spwd->sp_lstchg, sizeof spwd->sp_lstchg);
X	cp += sizeof spwd->sp_lstchg;
X
X	memcpy (cp, &spwd->sp_warn, sizeof spwd->sp_warn);
X	cp += sizeof spwd->sp_warn;
X
X	memcpy (cp, &spwd->sp_inact, sizeof spwd->sp_inact);
X	cp += sizeof spwd->sp_inact;
X
X	memcpy (cp, &spwd->sp_expire, sizeof spwd->sp_expire);
X	cp += sizeof spwd->sp_expire;
X
X	memcpy (cp, &spwd->sp_flag, sizeof spwd->sp_flag);
X	cp += sizeof spwd->sp_flag;
X
X	return cp - buf;
X}
X
Xint	spw_unpack (buf, len, spwd)
Xchar	*buf;
Xint	len;
Xstruct	spwd	*spwd;
X{
X	char	*org = buf;
X	char	*cp;
X
X	spwd->sp_namp = buf;
X	buf += strlen (buf) + 1;
X
X	spwd->sp_pwdp = buf;
X	buf += strlen (buf) + 1;
X
X	memcpy (&spwd->sp_min, buf, sizeof spwd->sp_min);
X	buf += sizeof spwd->sp_min;
X
X	memcpy (&spwd->sp_max, buf, sizeof spwd->sp_max);
X	buf += sizeof spwd->sp_max;
X
X	memcpy (&spwd->sp_lstchg, buf, sizeof spwd->sp_lstchg);
X	buf += sizeof spwd->sp_lstchg;
X
X	memcpy (&spwd->sp_warn, buf, sizeof spwd->sp_warn);
X	buf += sizeof spwd->sp_warn;
X
X	memcpy (&spwd->sp_inact, buf, sizeof spwd->sp_inact);
X	buf += sizeof spwd->sp_inact;
X
X	memcpy (&spwd->sp_expire, buf, sizeof spwd->sp_expire);
X	buf += sizeof spwd->sp_expire;
X
X	memcpy (&spwd->sp_flag, buf, sizeof spwd->sp_flag);
X	buf += sizeof spwd->sp_flag;
X
X	if (buf - org > len)
X		return -1;
X
X	return 0;
X}
SHAR_EOF
if test 2142 -ne "`wc -c < 'sppack.c'`"
then
	echo shar: "error transmitting 'sppack.c'" '(should have been 2142 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