summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Ball <nullspoon@oper.io>2019-08-30 20:52:31 -0600
committerAaron Ball <nullspoon@oper.io>2019-08-30 20:52:31 -0600
commit5bdaa0d83810eeeb26630e188dc8052342256bdb (patch)
tree2c414d50f560c04947e96267eb9511c1d29dbf7d
parent4fc4a8a49eaecd5ac5d527a08438106c060dbfdd (diff)
parent4c68efc4ed4f4811f6b93e410e11378b2a9ae0a7 (diff)
downloadupwgen-5bdaa0d83810eeeb26630e188dc8052342256bdb.tar.gz
upwgen-5bdaa0d83810eeeb26630e188dc8052342256bdb.tar.xz
Merge branch 'refactor-random-selection'
-rw-r--r--Makefile6
-rw-r--r--doc/upwgen.19
-rw-r--r--src/i18n_cat.c2
-rw-r--r--src/i18n_set.c185
-rw-r--r--src/i18n_set.h43
-rw-r--r--src/main.c138
6 files changed, 324 insertions, 59 deletions
diff --git a/Makefile b/Makefile
index d6edc2e..e17dda5 100644
--- a/Makefile
+++ b/Makefile
@@ -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*);
diff --git a/src/main.c b/src/main.c
index 226b8d0..9ad82ab 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;
}

Generated by cgit