/**************************************************
 * genpasswd2 -- generates a random password	  *
 * 		 consisting of random characters  *
 * 		 and numbers by using /dev/random.*
 *						  *
 * Usage					  *
 * genpasswd [-l<length>] [-c<chars>] [-a<chars>] *
 * 						  *
 * Options					  *
 * 						  * 
 **************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <time.h>

#define PNAME	"genpasswd2"	/* program name */
#define MAXBUF	128		/* max size of pwdstr and of the generated password */
#define DLENGTH	8		/* default length for password */
#define DCHARS	"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVQXYZ_"	/* default string of valid characters in password */

/**************************************************
 * void usage(void) -- output short usage message.*
 **************************************************/
void usage(void)
{
	fprintf(stderr, "Usage: %s [-l<length>] [-c<chars>] [-a<chars>]\n\n", PNAME);
}

/**************************************************
 * void susage(void) -- output small usage msg.	  *
 **************************************************/
void susage(void)
{
	usage();
	fprintf(stderr, "Try %s -h for more info.\n", PNAME);
}

/**************************************************
 * void lusage(void) -- output long usage msg.	  *
 **************************************************/
void lusage(void)
{
	usage();
	printf("Options\n");
	printf("-l<length>\t\tLength of password. Default is %d characters.\n", DLENGTH);
	printf("-c<chars>\t\tValid characters in password. Default is listed below.\n");
	printf("-a<chars>\t\tAdd chars to the default password character string.\n");
	printf("-v\t\t\t\tVerbose output.\n");
	printf("\n-h\t\t\t\tDisplay this help information and exit.\n");
	printf("\nDefault string of valid characters in password:\n");
	printf("%s\n", DCHARS);
}

/**************************************************
 * void genpasswd(char *dest, const char *pwdstr, *
 * const int length, FILE *randfeed)		  *
 * 						  *
 * generates a password getting random bytes from *
 * randfeed (/dev/random for example), putting it *
 * in dest.					  *
 **************************************************/
void genpasswd(char *dest, const char *pwdstr, int length, FILE *randfeed)
{
	int b;				/* random byte from randfeed */
	int len = strlen(pwdstr);	/* length of password character string */
	
	for(; length > 0; length--, dest++){
		b = fgetc(randfeed);
		*dest = pwdstr[b % len];
	}
	
	dest[length] = '\0'; /* close dest */
}



int main(int argc, char *argv[])
{
	int length = DLENGTH;		/* length of password */
	unsigned int verbose = 0;	/* verbose output */
	FILE *randfeed;			/* random byte feeder */
	char pwdstr[MAXBUF] = DCHARS;	/* password string */

	char passwd[MAXBUF]; /* the generated password */

	/* get arguments */
	while(argc > 1){
		if(argv[1][0] != '-'){
			fprintf(stderr, "%s: Invalid option %s specified.\n", PNAME, argv[1]);
			susage();
			return -1;
		}
		switch(argv[1][1]){
			case 'l':
				if(!argv[1][2]){
					fprintf(stderr, "%s: Option -%c requires an argument.\n", PNAME, argv[1][1]);
					susage();
					return -1;
				}
				
				sscanf(&argv[1][2], "%d", &length);
				
				if(length > MAXBUF){
					fprintf(stderr, "%s: Length of password too long. Maximum length of passwords is %d characters.\n", PNAME, MAXBUF);
					return -2;
				}
				
				break;
			case 'c':
				if(!argv[1][2]){
					fprintf(stderr, "%s: Option -%c requires an argument.\n", PNAME, argv[1][1]);
					susage();
					return -1;
				}

				if(strlen(&argv[1][2]) > MAXBUF){
					fprintf(stderr, "%s: Your valid characters string is too long (%d chars)! Maximum length of the string is %d characters.\n", PNAME, strlen(&argv[1][2]), MAXBUF);
					return -2;
				}
				
				strcpy(pwdstr, &argv[1][2]);
				break;
			case 'a':
				if(!argv[1][2]){
					fprintf(stderr, "%s: Option -%c requires an argument.\n", PNAME, argv[1][1]);
					susage();
					return -1;
				}

				strcpy(pwdstr, DCHARS);
				
				if((strlen(pwdstr) + strlen(&argv[1][2])) > MAXBUF){
					fprintf(stderr, "%s: Your valid characters string is too long (%d chars)! Maximum length of the string is %d characters.\n", PNAME, strlen(pwdstr) + strlen(&argv[1][2]), MAXBUF);
					return -2;
				}

				strcat(pwdstr, &argv[1][2]);
				break;
			case 'v':
				/* Verbose output */
				verbose = 1;
				break;
			case 'h':
				lusage();
				return 0;
			default:
				fprintf(stderr, "%s: Invalid option %s specified.\n", PNAME, argv[1]);
				susage();
				return -1;
				break;
		}
		argv++;
		argc--;
	}

	/* open the random byte feeder /dev/random */
	if(!(randfeed = fopen("/dev/random", "r"))){
		printf("%s: Could not open /dev/random.\n", PNAME);
		return 1;
	}

	/* generate password */
	genpasswd(passwd, pwdstr, length, randfeed);

	if(verbose){
		printf("Random %d characters password generated: ", length);
	}
	
	printf("%s\n", passwd);
	
	return 0;
}
