summaryrefslogtreecommitdiff
path: root/src/main.c
blob: faa939b08500aabcd61330dcbff26a1856375359 (plain)
    1 // upwgen generates random internationalized passwords
    2 // Copyright (C) 2019  Aaron Ball <nullspoon@oper.io>
    3 // 
    4 // This program is free software: you can redistribute it and/or modify
    5 // it under the terms of the GNU General Public License as published by
    6 // the Free Software Foundation, either version 3 of the License, or
    7 // (at your option) any later version.
    8 // 
    9 // This program is distributed in the hope that it will be useful,
   10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
   11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12 // GNU General Public License for more details.
   13 // 
   14 // You should have received a copy of the GNU General Public License
   15 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
   16 #include <stdlib.h>
   17 #include <stdio.h>
   18 #include <string.h>
   19 #include <time.h>
   20 #include <locale.h>
   21 
   22 #include "i18n_set.h"
   23 
   24 // Shamelessly ripped off from the GCC docs on stringizing
   25 // This (xstr) converts a macro to a string literal
   26 #define xstr(s) str(s)
   27 #define str(s) #s
   28 
   29 
   30 void usage() {
   31   printf(
   32     "Upwgen is a password generator with international support. If no length\n"
   33     "is specified, defaults to 32 characters output length, selecting from\n"
   34     "the standard English character set (lower case, upper case, numerals,\n"
   35     "and symbols).\n\n"
   36     "Usage:\n  upwgen [options] [length]\n\n"
   37     "Options:\n"
   38     "  -0,--no-numerals   Include at least one numeral in output\n"
   39     "  -A,--no-capitalize Include at least one numeral in output\n"
   40     "  -c,--capitalize    Include at least one capital letter in output\n"
   41     "  -n,--numerals      Include at least one numeral in output\n"
   42     "  -y,--symbols       Include at least one symbol in output\n"
   43     "  -i,--i18n          Include at least one international letter in output\n"
   44     "  -1                 Include chars from the most used scripts in the world\n"
   45     "  -2                 Include chars from the second most used scripts in the world\n"
   46     "  -3                 Include chars from the third most used scripts in the world\n"
   47     "  -4                 Include chars from the forth most used scripts in the world\n"
   48     "\n"
   49     "  -h,--help       Print this help text\n"
   50     "  -d,--debug      Enable debug mode (prints entire character pool)\n"
   51     "  -V,--version    Prints the version\n"
   52   );
   53 }
   54 
   55 
   56 int main(int argc, char* argv[]) {
   57   struct timespec ts; // Timespec for seeding rng
   58   int debug;          // Debug mode switch
   59   int len;            // Password length
   60   int i;              // Arg index
   61   unsigned long seed; // Seed for the RNG (current seconds * nanoseconds)
   62 
   63   struct i18n_set* set    = NULL; // Linked list of i18n_set structs
   64   struct i18n_set* cursor = NULL; // Cursor to track current position with in
   65                                   // the linked list
   66 
   67   // Initialize
   68   debug    = 0;
   69   len      = 32;
   70   i        = 1;
   71   setlocale(LC_ALL, "");
   72 
   73   // Start with the defaults
   74   set = i18n_set_new(I18N_TYPE_ASCII_UPPER);
   75   i18n_set_add(set, I18N_TYPE_ASCII_LOWER);
   76   i18n_set_add(set, I18N_TYPE_ASCII_NUMERALS);
   77 
   78 
   79   while(i < argc) {
   80     if(strcmp(argv[i], "-0") == 0 || strcmp(argv[i], "--no-numerals") == 0) {
   81       set = i18n_set_rm_type(set, I18N_TYPE_ASCII_NUMERALS);
   82 
   83     } else if(strcmp(argv[i], "-A") == 0 || strcmp(argv[i], "--no-capitalize") == 0) {
   84       set = i18n_set_rm_type(set, I18N_TYPE_ASCII_UPPER);
   85 
   86     } else if(strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--capitalize") == 0) {
   87       i18n_set_add(set, I18N_TYPE_ASCII_UPPER);
   88 
   89     } else if(strcmp(argv[i], "-n") == 0 || strcmp(argv[i], "--numerals") == 0) {
   90       i18n_set_add(set, I18N_TYPE_ASCII_NUMERALS);
   91 
   92     } else if(strcmp(argv[i], "-y") == 0 || strcmp(argv[i], "--symbols") == 0) {
   93       i18n_set_add(set, I18N_TYPE_ASCII_SYMBOLS);
   94 
   95     } else if(strcmp(argv[i], "-i") == 0 || strcmp(argv[i], "--i18n") == 0) {
   96       i18n_set_add(set, I18N_TYPE_ONE);
   97       i18n_set_add(set, I18N_TYPE_TWO);
   98       i18n_set_add(set, I18N_TYPE_THREE);
   99       i18n_set_add(set, I18N_TYPE_FOUR);
  100 
  101     } else if(strcmp(argv[i], "-1") == 0) {
  102       i18n_set_add(set, I18N_TYPE_ONE);
  103 
  104     } else if(strcmp(argv[i], "-2") == 0) {
  105       i18n_set_add(set, I18N_TYPE_TWO);
  106 
  107     } else if(strcmp(argv[i], "-3") == 0) {
  108       i18n_set_add(set, I18N_TYPE_THREE);
  109 
  110     } else if(strcmp(argv[i], "-4") == 0) {
  111       i18n_set_add(set, I18N_TYPE_FOUR);
  112 
  113     } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
  114       usage();
  115       return 0;
  116 
  117     } else if(strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--debug") == 0) {
  118       debug = 1;
  119 
  120     } else if(strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
  121       printf("upwgen %s\n", xstr(VERSTR));
  122       return 0;
  123 
  124     } else {
  125       // If we reach this block, the user specified a custom length (or
  126       // fatfingered something). Test for ability to convert from str to int
  127       // and set length if possible.
  128       if(atoi(argv[i]) == 0) {
  129         printf("Invalid length \"%s\"\n", argv[i]);
  130         return 1;
  131       } else {
  132         len = atoi(argv[i]);
  133       }
  134     }
  135     i++;
  136   }
  137 
  138 
  139   if(debug)
  140     i18n_set_dump(set);
  141 
  142   // Get the random data seed
  143   clock_gettime(CLOCK_REALTIME, &ts);
  144   seed = ts.tv_sec + ts.tv_nsec;
  145   srand((unsigned)seed);
  146 
  147   cursor = set;
  148   while(len > 0) {
  149     // Randomly select the number of character sets to advance through (max 10)
  150     int i = rand() % 10;
  151     while(i > 0) {
  152       // Loop
  153       if(!cursor->next) {
  154         cursor = set;
  155       } else {
  156         cursor = cursor->next;
  157       }
  158       i--;
  159     }
  160 
  161     // Randomly select an integer within the set size
  162     int rc = rand() % cursor->count; // Random char within set
  163     printf("%lc", cursor->chars[rc]);
  164     len--;
  165   }
  166   printf("\n");
  167 
  168   i18n_set_free(set);
  169   return 0;
  170 }

Generated by cgit