diff options
author | Aaron Ball <nullspoon@oper.io> | 2019-08-30 20:52:31 -0600 |
---|---|---|
committer | Aaron Ball <nullspoon@oper.io> | 2019-08-30 20:52:31 -0600 |
commit | 5bdaa0d83810eeeb26630e188dc8052342256bdb (patch) | |
tree | 2c414d50f560c04947e96267eb9511c1d29dbf7d | |
parent | 4fc4a8a49eaecd5ac5d527a08438106c060dbfdd (diff) | |
parent | 4c68efc4ed4f4811f6b93e410e11378b2a9ae0a7 (diff) | |
download | upwgen-5bdaa0d83810eeeb26630e188dc8052342256bdb.tar.gz upwgen-5bdaa0d83810eeeb26630e188dc8052342256bdb.tar.xz |
Merge branch 'refactor-random-selection'
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | doc/upwgen.1 | 9 | ||||
-rw-r--r-- | src/i18n_cat.c | 2 | ||||
-rw-r--r-- | src/i18n_set.c | 185 | ||||
-rw-r--r-- | src/i18n_set.h | 43 | ||||
-rw-r--r-- | src/main.c | 138 |
6 files changed, 324 insertions, 59 deletions
@@ -1,5 +1,5 @@ CC = cc -CCOPTS = -Wall -std=gnu99 +CCOPTS = -Wall -std=gnu99 $(DBG) PREFIX = /usr/bin MANPREFIX = /usr/share/man @@ -13,6 +13,7 @@ VERSTR = "$(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL))$(EXTRAVERSION)" all: @if [ ! -d obj ]; then mkdir obj; fi $(CC) $(CCOPTS) -c src/i18n_cat.c -o obj/i18n_cat.o + $(CC) $(CCOPTS) -c src/i18n_set.c -o obj/i18n_set.o $(CC) $(CCOPTS) -DVERSTR=$(VERSTR) src/main.c obj/*.o -o upwgen # Interpolate the man page and compress sed \ @@ -20,6 +21,9 @@ all: -e "s/{{ RELDATE }}/$(RELDATE)/" \ doc/upwgen.1 | gzip -c > upwgen.1.gz +debug: + make DBG=-g + install: # Install the binary install -D -m 755 upwgen "$(DESTDIR)/$(PREFIX)/upwgen" diff --git a/doc/upwgen.1 b/doc/upwgen.1 index e919b22..3cc6bfa 100644 --- a/doc/upwgen.1 +++ b/doc/upwgen.1 @@ -25,12 +25,15 @@ character pool (94 characters total). .B .SH OPTIONS .TP +.B \-0,--no-numerals +Include at least one numeral in the password +.TP +.B \-A,--no-capitalize +Include at least one numeral in the password +.TP .B \-c, --capitalize Include at least one capital letter in the password. .TP -.B \-l, --lower -Include at least one lower case letter in the password. -.TP .B \-n, --numerals Include at least one number in the password. .TP diff --git a/src/i18n_cat.c b/src/i18n_cat.c index f8d9f05..7a5f18e 100644 --- a/src/i18n_cat.c +++ b/src/i18n_cat.c @@ -280,5 +280,5 @@ void i18n_dump_arr(unsigned int* arr) { printf("0x%04x %-7d [%lc]\n", arr[i], arr[i], arr[i]); i++; } - printf("\nCount: %d\n\n", i); + printf("\nSet count: %d\n\n", i); } diff --git a/src/i18n_set.c b/src/i18n_set.c new file mode 100644 index 0000000..af7e3b6 --- /dev/null +++ b/src/i18n_set.c @@ -0,0 +1,185 @@ +/** + * upwgen generates random internationalized passwords + * Copyright (C) 2019 Aaron Ball <nullspoon@oper.io> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include "i18n_set.h" + + +/** + * i18n_set_new: + * Constructor for an i18n_set struct. Allocates in heap and must be freed + * using i18n_set_free. Based on the @type passed in, will pre-fill the set + * object. + * + * @type Type of i18n set to instantiate + * + * @return The instantiated i18n_set struct + */ +struct i18n_set* i18n_set_new(int type) { + struct i18n_set* out = malloc(sizeof(struct i18n_set)); + + out->count = 0; + out->type = type; + out->next = NULL; + out->chars[0] = '\0'; + + switch(type) { + case I18N_TYPE_ASCII_LOWER: + out->count = i18n_cat_ascii_lower(out->chars); + break; + case I18N_TYPE_ASCII_UPPER: + out->count = i18n_cat_ascii_upper(out->chars); + break; + case I18N_TYPE_ASCII_NUMERALS: + out->count = i18n_cat_ascii_numerals(out->chars); + break; + case I18N_TYPE_ASCII_SYMBOLS: + out->count = i18n_cat_ascii_symbols(out->chars); + break; + case I18N_TYPE_ONE: + out->count = i18n_cat_one(out->chars); + break; + case I18N_TYPE_TWO: + out->count = i18n_cat_two(out->chars); + break; + case I18N_TYPE_THREE: + out->count = i18n_cat_three(out->chars); + break; + case I18N_TYPE_FOUR: + out->count = i18n_cat_four(out->chars); + break; + } + + return out; +} + + +/** + * i18n_set_add: + * Instantiates and appends an i18n_set struct to an existing one. Since + * i18n_sets can be linked lists, this appends to one. + * Note that if the i18n_set passed is already in a linked list, this function + * will traverse to the end of the list and append there. + * + * @set Existing i18n_set to append + * @type Type of new i18n_set to instantiate and append + * + * @return Pointer to the newly added i18n_set struct + */ +struct i18n_set* i18n_set_add(struct i18n_set* set, int type) { + struct i18n_set* cursor = set; + if(!set) + return i18n_set_new(type); + + while(cursor->next) + cursor = cursor->next; + + cursor->next = i18n_set_new(type); + return cursor->next; +} + + +/** + * i18n_set_exists: + * Checks the provided i18n_set linked list if it contains the specified set + * type. If it does, returns a pointer to that struct, otherwise returns NULL. + * + * @set Linked list in which to check for the existence of the specified type + * @type Type to check for + * + * @return Pointer to the i18n_set instance with type matching @type, otherwise + * NULL + */ +struct i18n_set* i18n_set_exists(struct i18n_set* set, int type) { + while(set) { + if(set->type == type) + break; + set = set->next; + } + return set; +} + + +/** + * i18n_set_rm_type: + * Traverses the provided i18n_set linked list, removing any instances matching + * type @type. + * Note that the return value of this function should always be used, as if the + * linked list starts with an object matching @type, the beginning of the + * linked list will need to be repointed. + * + * @set Set to remove objects matching @type + * @type Type of i18n_set to remove from linked list + * + * @return Pointer to the beginning of the i18n_set linked list + */ +struct i18n_set* i18n_set_rm_type(struct i18n_set* set, int type) { + struct i18n_set* cursor = set; + struct i18n_set* prev = NULL; + + while(cursor) { + if(cursor->type == type) { + if(cursor == set) + set = set->next; + else if(!cursor->next) + prev->next = NULL; + else + prev->next = cursor->next; + + free(cursor); + } + prev = cursor; + cursor = cursor->next; + } + return set; +} + + +/** + * i18n_set_dump: + * Traverses the provided i18n_set linked list and prints the contents of each + * to stdout, with some handy extra information. Useful for debugging. + * + * @set i18n_set to dump + */ +void i18n_set_dump(struct i18n_set* set) { + struct i18n_set* cursor = set; + unsigned int total = 0; + while(cursor) { + total += cursor->count; + i18n_dump_arr(cursor->chars); + cursor = cursor->next; + } + printf("Total: %u\n\n", total); +} + + +/** + * i18n_set_free: + * Destructor for i18n_set structs. Will completely traverse the linked list to + * the end, freeing each item. + * + * @set i18n_set linked list to be freed + */ +void i18n_set_free(struct i18n_set* set) { + struct i18n_set* next = NULL; + + while(set) { + next = set->next; + free(set); + set = next; + } +} diff --git a/src/i18n_set.h b/src/i18n_set.h new file mode 100644 index 0000000..77fd08f --- /dev/null +++ b/src/i18n_set.h @@ -0,0 +1,43 @@ +/** + * upwgen generates random internationalized passwords + * Copyright (C) 2019 Aaron Ball <nullspoon@oper.io> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ +#include <stdlib.h> +#include "i18n_cat.h" + +#define I18N_SETSIZE 1024 +#define I18N_TYPE_ASCII_LOWER 1000 +#define I18N_TYPE_ASCII_UPPER 1100 +#define I18N_TYPE_ASCII_NUMERALS 1200 +#define I18N_TYPE_ASCII_SYMBOLS 1300 +#define I18N_TYPE_ONE 2000 +#define I18N_TYPE_TWO 3000 +#define I18N_TYPE_THREE 4000 +#define I18N_TYPE_FOUR 5000 + +struct i18n_set { + int type; + int count; + unsigned int chars[I18N_SETSIZE]; + struct i18n_set* next; +}; + +struct i18n_set* i18n_set_new(int); +struct i18n_set* i18n_set_add(struct i18n_set*, int); +struct i18n_set* i18n_set_exists(struct i18n_set*, int); +struct i18n_set* i18n_set_rm_type(struct i18n_set*, int); +void i18n_set_dump(struct i18n_set*); +void i18n_set_free(struct i18n_set*); @@ -1,25 +1,27 @@ -// upwgen generates random internationalized passwords -// Copyright (C) 2019 Aaron Ball <nullspoon@oper.io> -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see <http://www.gnu.org/licenses/>. +/** + * upwgen generates random internationalized passwords + * Copyright (C) 2019 Aaron Ball <nullspoon@oper.io> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #include <stdlib.h> #include <stdio.h> #include <string.h> #include <time.h> #include <locale.h> -#include "i18n_cat.h" +#include "i18n_set.h" // Shamelessly ripped off from the GCC docs on stringizing // This (xstr) converts a macro to a string literal @@ -35,15 +37,16 @@ void usage() { "and symbols).\n\n" "Usage:\n upwgen [options] [length]\n\n" "Options:\n" - " -c,--capitalize Include at least one capital letter in output\n" - " -l,--lower Include at least one lower case letter in output\n" - " -n,--numerals Include at least one numeral in output\n" - " -y,--symbols Include at least one symbol in output\n" - " -i,--i18n Include at least one international letter in output\n" - " -1 Include chars from the most used scripts in the world\n" - " -2 Include chars from the second most used scripts in the world\n" - " -3 Include chars from the third most used scripts in the world\n" - " -4 Include chars from the forth most used scripts in the world\n" + " -0,--no-numerals Include at least one numeral in output\n" + " -A,--no-capitalize Include at least one numeral in output\n" + " -c,--capitalize Include at least one capital letter in output\n" + " -n,--numerals Include at least one numeral in output\n" + " -y,--symbols Include at least one symbol in output\n" + " -i,--i18n Include at least one international letter in output\n" + " -1 Include chars from the most used scripts in the world\n" + " -2 Include chars from the second most used scripts in the world\n" + " -3 Include chars from the third most used scripts in the world\n" + " -4 Include chars from the forth most used scripts in the world\n" "\n" " -h,--help Print this help text\n" " -d,--debug Enable debug mode (prints entire character pool)\n" @@ -54,51 +57,71 @@ void usage() { int main(int argc, char* argv[]) { struct timespec ts; // Timespec for seeding rng - unsigned int count; // Number of chars to choose from int debug; // Debug mode switch int len; // Password length int i; // Arg index unsigned long seed; // Seed for the RNG (current seconds * nanoseconds) - unsigned int chars[4096]; // Uint array to hold international chars + + struct i18n_set* set = NULL; // Linked list of i18n_set structs + struct i18n_set* cursor = NULL; // Cursor to track current position with in + // the linked list // Initialize debug = 0; - count = 0; len = 32; i = 1; - chars[0] = '\0'; - setlocale(LC_ALL, "en_US.UTF-8"); + setlocale(LC_ALL, ""); + + // Start with the defaults + set = i18n_set_new(I18N_TYPE_ASCII_UPPER); + i18n_set_add(set, I18N_TYPE_ASCII_LOWER); + i18n_set_add(set, I18N_TYPE_ASCII_NUMERALS); + while(i < argc) { - if(strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--capitals") == 0) { - count += i18n_cat_ascii_upper(chars); + if(strcmp(argv[i], "-0") == 0 || strcmp(argv[i], "--no-numerals") == 0) { + set = i18n_set_rm_type(set, I18N_TYPE_ASCII_NUMERALS); + + } else if(strcmp(argv[i], "-A") == 0 || strcmp(argv[i], "--no-capitalize") == 0) { + set = i18n_set_rm_type(set, I18N_TYPE_ASCII_UPPER); - } else if(strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--lower") == 0) { - count += i18n_cat_ascii_lower(chars); + } else if(strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--capitalize") == 0) { + if(!i18n_set_exists(set, I18N_TYPE_ASCII_UPPER)) + i18n_set_add(set, I18N_TYPE_ASCII_UPPER); } else if(strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--numerals") == 0) { - count += i18n_cat_ascii_numerals(chars); + if(!i18n_set_exists(set, I18N_TYPE_ASCII_NUMERALS)) + i18n_set_add(set, I18N_TYPE_ASCII_NUMERALS); } else if(strcmp(argv[i], "-y") == 0 || strcmp(argv[i], "--symbols") == 0) { - count += i18n_cat_ascii_symbols(chars); + if(!i18n_set_exists(set, I18N_TYPE_ASCII_SYMBOLS)) + i18n_set_add(set, I18N_TYPE_ASCII_SYMBOLS); } else if(strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--i18n") == 0) { - count += i18n_cat_one(chars); - count += i18n_cat_two(chars); - count += i18n_cat_three(chars); - count += i18n_cat_four(chars); + if(!i18n_set_exists(set, I18N_TYPE_ONE)) + i18n_set_add(set, I18N_TYPE_ONE); + if(!i18n_set_exists(set, I18N_TYPE_TWO)) + i18n_set_add(set, I18N_TYPE_TWO); + if(!i18n_set_exists(set, I18N_TYPE_THREE)) + i18n_set_add(set, I18N_TYPE_THREE); + if(!i18n_set_exists(set, I18N_TYPE_FOUR)) + i18n_set_add(set, I18N_TYPE_FOUR); } else if(strcmp(argv[i], "-1") == 0) { - count += i18n_cat_one(chars); + if(!i18n_set_exists(set, I18N_TYPE_ONE)) + i18n_set_add(set, I18N_TYPE_ONE); } else if(strcmp(argv[i], "-2") == 0) { - count += i18n_cat_two(chars); + if(!i18n_set_exists(set, I18N_TYPE_TWO)) + i18n_set_add(set, I18N_TYPE_TWO); } else if(strcmp(argv[i], "-3") == 0) { - count += i18n_cat_three(chars); + if(!i18n_set_exists(set, I18N_TYPE_THREE)) + i18n_set_add(set, I18N_TYPE_THREE); } else if(strcmp(argv[i], "-4") == 0) { - count += i18n_cat_four(chars); + if(!i18n_set_exists(set, I18N_TYPE_FOUR)) + i18n_set_add(set, I18N_TYPE_FOUR); } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { usage(); @@ -125,25 +148,32 @@ int main(int argc, char* argv[]) { i++; } - // If no charset was specified, use standard ascii 33 - 126 chars, which - // includes english lower case, upper case, numbers, and some symbols. - if(chars[0] == '\0') - count += i18n_cat_ascii(chars); - if(debug) - i18n_dump_arr(chars); + i18n_set_dump(set); // Get the random data seed clock_gettime(CLOCK_REALTIME, &ts); seed = ts.tv_sec + ts.tv_nsec; srand((unsigned)seed); - while(len > 0) { - int r = rand() % count; - printf("%lc", chars[r]); - len--; + cursor = set; + while((len--) > 0) { + // Randomly select the number of character sets to advance through + int i = rand() % 10; + while((i--) > 0) { + // Loop + if(!cursor->next) + cursor = set; + else + cursor = cursor->next; + } + + // Randomly select an integer within the set size + int rc = rand() % cursor->count; // Random char within set + printf("%lc", cursor->chars[rc]); } printf("\n"); + i18n_set_free(set); return 0; } |