Created
March 3, 2014 20:59
-
-
Save raidzero/9334503 to your computer and use it in GitHub Desktop.
Password generator. Takes password requirements as arguments using getopt()
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* USAGE: passgen [-u UPPER] [-l LOWER] [-n NUMBER] -s [SPECIAL] -a LENGTH | |
* The approach is take the desired length, and set aside positions in the result | |
* string for the required characters, then fill in the other positions | |
* with random characters | |
*/ | |
#include <stdio.h> | |
#include <sys/time.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <stdarg.h> | |
//#define DEBUG 1 | |
// define the selection of characters to choose from each category | |
#define UCC "ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
#define LCC "abcdefghijklmnopqrstuvwxyz" | |
#define NCC "0123456789" | |
#define SCC "~!@#$%^&*-)(|,.?" | |
//prototypes | |
int checkUsedLocs(int, int*, int); | |
int getRandInt(int, int, int*); | |
char getRandChar(char*); | |
void printdbg(char* fmt, ...); // only print stuff if DEBUG is defined | |
int main(int argc, char* argv[]) | |
{ | |
char* uc_min = NULL; | |
char* lc_min = NULL; | |
char* nc_min = NULL; | |
char* sc_min = NULL; | |
// these all default to 0, so the default behavior is no requirements | |
int UC_MIN = 0; | |
int LC_MIN = 0; | |
int NC_MIN = 0; | |
int SC_MIN = 0; | |
int length = 0; | |
// these are needed for getopt() | |
extern char* optarg; | |
extern int optind; | |
int o, opterr = 0; | |
static char usage[] = "usage: passgen [-u UPPER] [-l LOWER] [-n NUMBER] -s [SPECIAL] -a LENGTH\n"; | |
// use getopt to parse args | |
while ((o = getopt(argc, argv, "u:l:n:s:a:")) != -1) | |
{ | |
switch(o) | |
{ | |
case 'u': | |
UC_MIN = atoi(optarg); | |
printdbg("UC_MIN: %d\n", UC_MIN); | |
break; | |
case 'l': | |
LC_MIN = atoi(optarg); | |
printdbg("LC_MIN: %d\n", LC_MIN); | |
break; | |
case 'n': | |
NC_MIN = atoi(optarg); | |
printdbg("NC_MIN: %d\n", NC_MIN); | |
break; | |
case 's': | |
SC_MIN = atoi(optarg); | |
printdbg("SC_MIN: %d\n", SC_MIN); | |
break; | |
case 'a': | |
printdbg("length str: %s\n", optarg); | |
length = atoi(optarg); | |
break; | |
default: | |
printf("%s", usage); | |
opterr = 1; // set this to 1 to cause getopt() to fail | |
return 1; | |
} | |
} | |
// only required param is length | |
if (length == 0) | |
{ | |
printf("Length required! pass with -a LENGTH.\n"); | |
return 1; | |
} | |
// the sum of the number of all required characters | |
int min_length = UC_MIN + LC_MIN + NC_MIN + SC_MIN; | |
if (length < min_length) | |
{ | |
printf("Invalid length. Must be greater than %d.\n", min_length); | |
return -1; | |
} | |
printdbg("Length: %d.\n", length); | |
// allocate some memory for the result & the location map | |
char* res = malloc(length * sizeof(char) + 1); | |
int* usedLocs = malloc(length* sizeof(int)); | |
// fill usedLocs with -1 - so checkUsedLocs() works correctly | |
memset(usedLocs, -1, sizeof(int) * length); | |
int i; // good old iterator | |
int locsCount = 0; // remember how many locations we have reserved | |
// lets determine the positions of the required characters | |
if (UC_MIN > 0) | |
{ | |
// uppercase requirement | |
int *upperLocs = malloc(UC_MIN * sizeof(int)); | |
for (i=0; i<UC_MIN; i++) | |
{ | |
upperLocs[i] = getRandInt(0, locsCount, usedLocs); | |
char c = getRandChar(UCC); | |
res[upperLocs[i]] = c; | |
printdbg("UC: %c[%d]\n", c, upperLocs[i]); | |
usedLocs[locsCount++] = upperLocs[i]; | |
} | |
free(upperLocs); | |
} | |
if (LC_MIN > 0) | |
{ | |
// lowercase requirement | |
int *lowerLocs = malloc(LC_MIN * sizeof(int)); | |
for (i=0; i<LC_MIN; i++) | |
{ | |
lowerLocs[i] = getRandInt(0, locsCount, usedLocs); | |
char c = getRandChar(LCC); | |
res[lowerLocs[i]] = c; | |
printdbg("LC: %c[%d]\n", c, lowerLocs[i]); | |
usedLocs[locsCount++] = lowerLocs[i]; | |
} | |
free(lowerLocs); | |
} | |
if (NC_MIN > 0) | |
{ | |
// numeric requirement | |
int *numberLocs = malloc(NC_MIN * sizeof(int)); | |
for (i=0; i<NC_MIN; i++) | |
{ | |
numberLocs[i] = getRandInt(0, locsCount, usedLocs); | |
char c = getRandChar(NCC); | |
res[numberLocs[i]] = c; | |
printdbg("NC: %c[%d]\n", c, numberLocs[i]); | |
usedLocs[locsCount++] = numberLocs[i]; | |
} | |
free(numberLocs); | |
} | |
if (SC_MIN > 0) | |
{ | |
// special requirement | |
int *specialLocs = malloc(SC_MIN * sizeof(int)); | |
for (i=0; i<SC_MIN; i++) | |
{ | |
specialLocs[i] = getRandInt(0, locsCount, usedLocs); | |
char c = getRandChar(SCC); | |
res[specialLocs[i]] = c; | |
printdbg("SC: %c[%d]\n", c, specialLocs[i]); | |
usedLocs[locsCount++] = specialLocs[i]; | |
} | |
free(specialLocs); | |
} | |
// make pool of all chars from each category | |
char* allChars = malloc(strlen(UCC) + strlen(LCC) + strlen(NCC) + strlen(SCC) + 1 * sizeof(char)); | |
strcat(allChars, UCC); strcat(allChars, LCC); strcat(allChars, NCC); strcat(allChars, SCC); | |
printdbg("all chars: %s\n", allChars); | |
for (i=0; i<length; i++) | |
{ | |
printdbg("usedLocs[%d]: %d\n", i, usedLocs[i]); | |
} | |
// fill in the rest | |
for (i=0; i<length; i++) | |
{ | |
if (!checkUsedLocs(i, usedLocs, length)) | |
{ | |
res[i] = getRandChar(allChars); | |
} | |
} | |
printf("%s\n", res); | |
free(usedLocs); | |
free(allChars); | |
free(res); | |
return 0; | |
} | |
int checkUsedLocs(int loc, int* usedLocs, int size) | |
{ | |
int i; | |
for (i=0; i<size; i++) | |
{ | |
if (usedLocs[i] == -1) | |
{ | |
return 0; // this hasnt been set at all | |
} | |
if (usedLocs[i] == loc) | |
{ | |
return 1; | |
} | |
} | |
return 0; | |
} | |
int getRandInt(int min, int max, int* usedLocs) | |
{ | |
// sleep for 1 usec , to ensure a new random number next time | |
usleep(1); | |
// structs for time | |
struct timezone tz; | |
struct tm *tm; | |
struct timeval tv; | |
gettimeofday (&tv, &tz); | |
tm = (struct tm*) localtime (&tv.tv_sec); | |
srand (tv.tv_usec); // seed random number generator with microsenconds | |
int r = (rand() % (max+1-min))+min; | |
if (!usedLocs) // we are just pulling what will be a character | |
{ | |
printdbg("getRandInt(%d, %d) returning %d\n", min, max, r); | |
return r; | |
} | |
// get a valid location to store this soon-to-be character in | |
while (checkUsedLocs(r, usedLocs, max)) | |
{ | |
r = (rand() % (max+1-min))+min; | |
} | |
printdbg(">>getRandInt(%d, %d) returning %d\n", min, max, r); | |
return r; | |
} | |
char getRandChar(char* str) | |
{ | |
int len = (strlen(str)) - 1; // 0-indexed | |
int pos = getRandInt(0, len, 0); | |
char r = str[pos]; | |
return r; | |
} | |
void printdbg(char* fmt, ...) | |
{ | |
#ifdef DEBUG | |
va_list args; | |
va_start(args, fmt); | |
vprintf(fmt, args); | |
va_end(args); | |
#endif | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment