diff options
-rw-r--r-- | toys/pending/pwgen.c | 157 |
1 files changed, 51 insertions, 106 deletions
diff --git a/toys/pending/pwgen.c b/toys/pending/pwgen.c index c63ebee7..d3e17e58 100644 --- a/toys/pending/pwgen.c +++ b/toys/pending/pwgen.c @@ -2,29 +2,29 @@ * * Copyright 2020 Moritz Röhrich <moritz@ildefons.de> -USE_PWGEN(NEWTOY(pwgen, ">2?r(remove):c(capitalize)n(numerals)y(symbols)s(secure)B(ambiguous)h(help)C1vA(no-capitalize)0(no-numerals)[-cA][-n0]", TOYFLAG_USR|TOYFLAG_BIN)) +USE_PWGEN(NEWTOY(pwgen, ">2r(remove):c(capitalize)n(numerals)y(symbols)s(secure)B(ambiguous)h(help)C1vA(no-capitalize)0(no-numerals)[-cA][-n0][-C1]", TOYFLAG_USR|TOYFLAG_BIN)) config PWGEN bool "pwgen" default n help - usage: pwgen [ OPTIONS ] [ length ] [ number ] - - A password generator. - - Options supported by pwgen: - -c --capitalize Permit capital letters. - -A --no-capitalize Don't include capital letters. - -n --numerals Permit numbers. - -0 --no-numerals Don't include numbers. - -y --symbols Permit special characters ($#%...). - -r <chars> --remove=<chars> Don't include the given characters. - -s --secure Generate more random passwords. - -B --ambiguous Avoid ambiguous characters (e.g. 0, O). - -h --help Print this help message. - -C Print the output in columns. - -1 Print the output one line each. - -v Don't include vowels. + usage: pwgen [-cAn0yrsBhC1v] [LENGTH] [COUNT] + + Generate human-readable random passwords. When output is to tty produces + a screenfull to defeat shoulder surfing (pick one and clear the screen). + + -c --capitalize Permit capital letters. + -A --no-capitalize Don't include capital letters. + -n --numerals Permit numbers. + -0 --no-numerals Don't include numbers. + -y --symbols Permit special characters ($#%...). + -r <chars> --remove=<chars> Don't include the given characters. + -s --secure Generate more random passwords. + -B --ambiguous Avoid ambiguous characters (e.g. 0, O). + -h --help Print this help message. + -C Print the output in columns. + -1 Print the output one line each. + -v Don't include vowels. */ #define FOR_pwgen @@ -34,97 +34,42 @@ GLOBALS( char *r; ) -// Generate one random printable/typeable ascii character. -char get_rand_chr() { - return (char) (33 + (rand() % 93)); -} - -// Uses get_rand_chr to generate a character that conforms the requirements set -// by the argument flags. -char get_valid_chr(const char *illegal) { - char c = get_rand_chr(); - - while (strchr(illegal, c) != NULL) - c = get_rand_chr(); - - return c; -} - -char * get_illegal_chars() { - char* illegal = malloc(94 * sizeof(char)); - memset(illegal, 0, 94 * sizeof(char)); - if (toys.optflags & FLAG(A)) - strcat(illegal, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - if (toys.optflags & FLAG(0)) - strcat(illegal, "1234567890"); - if (toys.optflags & FLAG(B)) - strcat(illegal, "0O1lI'`.,"); - if (toys.optflags & FLAG(v)) - strcat(illegal, "ieaouIEAOU"); - if (!(toys.optflags & FLAG(y))) - strcat(illegal, "!@#$%^&*()-_=+`~{}[];:'\",.<>/?\\|"); - if (TT.r){ - strcat(illegal, TT.r); - } - return illegal; -} - -// Generate a new password of length l. -char * get_pw(const unsigned long l, const char *illegal) { - char *pw = malloc((l+1) * sizeof(char)); - memset(pw, 0, (l+1) * sizeof(char)); // zero out memory for new password. - unsigned long i; - for (i = 0; i < l; i++){ - pw[i] = get_valid_chr(illegal); - } - - return pw; -} - void pwgen_main(void) { - // seed the (pseudo) RNG. - time_t t; - srand((unsigned) time(&t)); - - int length = 8; - int count = 160; - int num_columns = 8; - if (toys.optc > 0) { - length = atoi(toys.optargs[0]); - num_columns = 80 / (length+1); - if (toys.optc > 1) { - count = atoi(toys.optargs[1]); - } else if (toys.optflags & FLAG(1)) { - count = 1; - } else { - count = 20 * num_columns; - } - } - - char *illegal = get_illegal_chars(); - char **passwords = malloc(count * sizeof(char*)); - int c; - for (c = 0; c < count; c++) - passwords[c] = get_pw(length, illegal); - - if (toys.optflags & FLAG(1)){ - for (c = 0; c < count; c++) - xprintf("%s\n", passwords[c]); - } else { - int col; - c = 0; - while(c < count){ - for (col = 0; c < count && col < num_columns; col++){ - xprintf("%s ", passwords[c]); - c += 1; + int length = 8, count, ii, jj, c, rand = 0, x = 0; + unsigned xx = 80, yy = 24; + char janice[16]; + + if (isatty(1)) terminal_size(&xx, &yy); + else toys.optflags |= FLAG_1; + + if (toys.optc && (length = atolx(*toys.optargs))>sizeof(toybuf)) + error_exit("bad length"); + if (toys.optc>1) count = atolx(toys.optargs[1]); + else count = FLAG(1) ? 1 : (xx/(length+1))*(yy-1); + + for (jj = 0; jj<count; jj++) { + for (ii = 0; ii<length;) { + // Don't fetch more random than necessary, give each byte 2 tries to fit + if (!rand) xgetrandom(janice, rand = sizeof(janice), 0); + c = 33+janice[--rand]%93; // remainder 69 makes >102 less likely + + if (c>='A' && c<='Z') { + if (FLAG(A)) continue; + // take out half the capital letters to be more human readable + else c |= (0x80&janice[rand])>>2; } - xprintf("\n"); + if (FLAG(0) && c>='0' && c<='9') continue; + if (FLAG(B) && strchr("0O1lI'`.,", c)) continue; + if (FLAG(v) && strchr("aeiou", tolower(c))) continue; + if (!FLAG(y) || (0x80&janice[rand])) + if (c<'0' || (c>'9' && c<'A') || (c>'Z' && c<'a') || c>'z') continue; + if (TT.r && strchr(TT.r, c)) continue; + + toybuf[ii++] = c; } + if (FLAG(1) || (x += length+1)+length>=xx) x = 0; + xprintf("%.*s%c", length, toybuf, x ? ' ' : '\n'); } - - for (c = 0; c < count; c++) - free(passwords[c]); - free(passwords); - free(illegal); + if (x) xputc('\n'); } |