/*
 * genpwd -- generate random passwords
 *
 * This program generates a number of triplets
 *	(encrypted password, salt, plaintext password)
 * the number of triplets being the first argument or NPASS, if none given.
 * This should be linked using the standard UNIX password encryption
 * algorithm (slow, but accurate), since this is used to generate input
 * for the password checker and timer.
 * Usage:
 *	genpwd [ -d ] [ -s number ] [ <number> ]
 * Options are:
 *	-d	give each triplet the same salt; this is useful for
 *		feeding through certain statistical tests and vectorized
 *		systems
 *	-s number
 *		initialize the pseudorandom numbe generator using the
 *		number as the seed; by default, the low-order bits of
 *		the time are used
 * The number (last) argument says how many triplets are to be generated;
 * the default is 100.
 */
/****************************************************************
 * Copyright notice.						*
 * This software is copyrighted (c) 1991 by Matt Bishop and the *
 * Trustees of Dartmouth College.  All rights reserved.		*
 *								*
 * Author:	Matt Bishop					*
 * Address:	Department of Mathematics and Computer Science	*
 *		Dartmouth College				*
 *		Hanover, NH  03755-1831				*
 *		USA						*
 * telephone:	+1 603 646 3267					*
 * fax:		+1 603 646 1312					*
 * internet:	Matt.Bishop@dartmouth.edu			*
 * usenet:	...!decvax!dartvax!Matt.Bishop			*
 ****************************************************************/
 
#ifndef lint
static char *version = "Version GAMMA 6/31/91 Matt.Bishop@dartmouth.edu";
#endif

#include <ctype.h>
#include <stdio.h>

/*
 * the default number of passwords generated
 */
#define NPASS	100

/*
 * the Berkeley interface is simpler, so we
 * put it on top of the System V stuff
 */
#if defined(SYSV) || defined(UTS) || defined(CRAY1) || defined(CRAY2)
#	define random()		lrand48()
#	define srandom(x)	srand48((long) (x))
#endif

/*
 * the random number generator (normalized)
 */
#define randm(low, high)	(low + (random() % (high - low + 1)))

/*
 * useful globals
 */
char *progname;		/* program name */
char saltlist[] = 	/* list of legal chars in the salt */
	"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

/*
 * library functions and variables
 */
extern char *optarg;	/* pointer to option's argument */
extern int optind;	/* number of next arg to be processed */
char *crypt();		/* password hasher */

main(argc, argv)
int argc;
char *argv[];
{
	register int i;		/* counter in a for loop */
	int pwds = NPASS;	/* number of passwords to generate */
	int samesalt = 0;	/* same salt for all passwords */

	/*
	 * initialize the pseudorandom number generator
	 * and get the program name
	 */
	srandom(time(0));
	progname = argv[0];

	/*
	 * process the argument list
	 */
	while((i = getopt(argc, argv, "ds:")) != EOF){
		switch(i){
		case 's':		/* reseed the RNG */
			if (isnum(optarg))
				srandom(atoi(optarg));
			else
				fprintf(stderr, "%s: -s needs a number\n",
								   progname);
			break;
		case 'd':	 	/* generate one salts */
			samesalt = 1;
			break;
		case '?':	 	/* ??? */
		default:
			fprintf(stderr, "Usage: %s [-d] [-s<n>] [number]\n",
				progname);
			exit(1);
		}
	}

	/*
	 * process the final argument, if present
	 */
	if (optind + 1 == argc && isnum(argv[optind]))
		pwds = atoi(argv[optind]);
	else if (optind != argc){
		fprintf(stderr, "Usage: %s [-d] [-s<n>] [number]\n", progname);
		exit(1);
	}

	/*
	 * generate the password triplets and die
	 */
	genpwd(pwds, samesalt);
	exit(0);
}

/*
 * return 1 if this is an integer, 0 if not
 */
int isnum(s)
char *s;		/* the string to be checked */
{
	/*
	 * eat leading sign
	 */
	if (*s == '+' || *s == '-')
		s++;

	/*
	 * ignore digits
	 */
	while(isdigit(*s))
		s++;

	/*
	 * non-digit better be end of string!
	 */
	return(*s == '\0');
}

/*
 * generate the passwords
 */
genpwd(n, samesalt)
int n;		/* number of password triplets to generate */
int samesalt;	/* 0 if a random salt should be used on each password */
{
	register int i;		/* counter in a for loop */
	register int len;	/* length of password */
	char *p;		/* points to hashed password */
	char passwd[9];		/* the plaintext password */
	char salt[3];		/* the salt */
	
	/*
	 * be sure the number to print is reasonable
	 */
	if (n <= 0){
		fprintf(stderr, "%s: number of passwords must be positive\n",
								 progname);
		exit(1);
	}
	
	/*
	 *if the passwords are to use the same salt, generate the salt here
	 */
	if (samesalt){
		salt[0] = saltlist[randm(0,sizeof(saltlist))];
		salt[1] = saltlist[randm(0,sizeof(saltlist))];
		salt[2] = '\0';
	}

	/*
	 * generate the requisite number of passwords
	 */
	for(i = 0; i < n; i++){
		len = randm(1, 8);		/* generate the password */
		passwd[len] = '\0';
		while(len-- > 0)
			passwd[len] = randm(0x21, 0x7e);
		if (!samesalt){			/* generate the salt */
						/* -1 as arrays are 0-based */
						/* -1 as last byte is NUL */
			salt[0] = saltlist[randm(0,sizeof(saltlist)-2)];
			salt[1] = saltlist[randm(0,sizeof(saltlist)-2)];
			salt[2] = '\0';
		}
		p = crypt(passwd, salt);	/* encrypt the sucker */
		printf("%s %s %s\n", p, salt, passwd);
	}
}

