/* Copyright (c) 2000-2010, Dirk Krause All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Dirk Krause nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file createp.c Create passwords. */ /* createp -c -tdefault -l6-8 -d1-2 -s1-2 -k1-2 -o default configure type (length, digits, specials, upper-case) createp -c -ttest -l6-8 -o hex -a openssl,random,rand48,rand configure type (length, ASCII-Hex encoded random data) createp -c -ttest -l6-8 -o ascii85 configure type (length, ASCII85-endcoded random data) createp -c -t wpa-key -l32 -o charset aA0 configure type (length, character classes) createp -u unconfigure createp -C show current configuration createp -h show help text createp -v show version createp -tdefault erwin create password of type default for user erwin */ #include #include #if DK_HAVE_STDLIB_H #include #endif #if DK_HAVE_UNISTD_H #include #endif #if DK_HAVE_PROCESS_H #include #endif #include #include #include #include #include #include #include #include #include "dktools-version.h" #line 100 "createp.ctr" /** Output mode: Default output mode. */ #define PROGRAM_MODE_DEFAULT 0 /** Output mode: Random data, ASCII-Hex encoded. */ #define PROGRAM_MODE_HEX 1 /** Output mode: Random data, ASCII-85 encoded. */ #define PROGRAM_MODE_ASCII85 2 /** Output mode: Use specified character set. */ #define PROGRAM_MODE_SET 3 /** Action: Run normally (create passwords/WPA keys). */ #define ACTION_RUN 0 /** Action: Print help text, */ #define ACTION_HELP 1 /** Action: Show version. */ #define ACTION_VERSION 2 /** Action: Save preferences. */ #define ACTION_CONFIGURE 4 /** Action: Unconfigure. */ #define ACTION_UNCONFIGURE 8 /** Action: Show configuration. */ #define ACTION_SHOWCONF 16 /** Buffer length for preferences keys and values. */ #define DEFAULT_BUFFER_LENGTH 256 /** Createp job. */ typedef struct { int rand_types_allowed; /**< Allowed PRNG types (or-comb). */ int program_mode; /**< Output mode. */ int program_action; /**< Action to take. */ int exval; /**< Exit status. */ unsigned l_min; /**< Minimum password length. */ unsigned l_max; /**< Maximum password length. */ unsigned l; /**< Password length. */ unsigned d_min; /**< Minimum number of digits. */ unsigned d_max; /**< Maximum number of digits. */ unsigned d; /**< Number of digits. */ unsigned s_min; /**< Minimum number of specials. */ unsigned s_max; /**< Maximum number of specials. */ unsigned s; /**< Number of specials. */ unsigned u_min; /**< Minimum number of upper-case. */ unsigned u_max; /**< Maximum number of upper-case. */ unsigned u; /**< Number of upper-case. */ size_t u_cs_buffer; /**< Used bytes in \a cs_buffer. */ size_t s_b_type; /**< Size of type buffer. */ unsigned char pw_only; /**< Flag: Print password only. */ unsigned char f_pw_only; /**< Flag: Found setting pw only. */ unsigned char f_cmd_rand_types_allowed; /**< Flag: Found allowed. */ unsigned char f_cmd_mode; /**< Flag: Found output mode. */ unsigned char f_cmd_l; /**< Flag: Length specified in command line. */ unsigned char f_cmd_d; /**< Flag: Digits specified in command line. */ unsigned char f_cmd_s; /**< Flag: Specials specified in command line. */ unsigned char f_cmd_u; /**< Flag: uppercase specified in command line. */ unsigned char f_cmd_charset; /**< Flag: Charset specified in command line. */ char **msg; /**< Message text array. */ dk_app_t *a; /**< Application. */ unsigned char *cs_buffer; /**< Buffer, length 256. */ char *b_type; /**< Type. */ dk_storage_t *s_names; /**< user names container. */ dk_storage_iterator_t *i_names; /**< User names iterator. */ dk_bitfield_t *b_cs_buffer; /**< Bitfield, type set for position. */ } CMD; /** Struct to store user names in order of appearance on the command line. */ typedef struct { unsigned long number; /**< Line number. */ char *name; /**< Name. */ } NAME; /* Name of the program group */ #ifndef GROUPNAME #define GROUPNAME "dktools" #endif /** Application group name. */ static char grname[] = { GROUPNAME }; /** System configuration directory. */ static char etcdir[] = { DK_SYSCONFDIR }; /** Entry names and default values for the strings used by the program. */ static dk_key_value_t kv[] = { { "0", "Not enough memory (RAM/swap space)!" }, { "1", "String \"" }, { "2", "\" is to long!" }, { "3", "\"" }, { "4", "\" is not a number or range!" }, { "5", "Unknown output mode \"" }, { "6", "\"!" }, { "7", "Invalid output character set \"" }, { "8", "\"!" }, { "9", "Not a boolean value: \"" }, { "10", "\"!" }, { "11", "on" }, { "12", "off" }, { "13", "Password type" }, { "14", "PRNG types, either \"all\" or a combination of:" }, { "15", "openssl the OpenSSL PRNG" }, { "16", "random the PRNG using initstate()/setstate()/random()" }, { "17", "rand48 the PRNG using nrand48()" }, { "18", "rand the PRNG using rand()" }, { "19", "Output mode, one of:" }, { "20", "default specify number of digits, special" }, { "21", " and upper-case characters as options" }, { "22", "hex '0'...'9','a'...'f'" }, { "23", "ascii85 characters 33...127" }, { "24", "charset specify all characters manually" }, { "25", " any lower-case character represents all" }, { "26", " lower-case characters" }, { "27", " any upper-case character represents all" }, { "28", " upper-case characters" }, { "29", " any digit represents all digits" }, { "30", "Password length" }, { "31", "Number of digits" }, { "32", "Number of special characters" }, { "33", "Number of upper-case characters" }, { "34", "Length undefined for \"" }, { "35", "\"!" }, { "36", "Number of digits undefined for \"" }, { "37", "\"!" }, { "38", "Number of special characters undefined for \"" }, { "39", "\"!" }, { "40", "Number of upper-case characters undefined for \"" }, { "41", "\"!" }, { "42", "PRNGs undefined for \"" }, { "43", "\"!" }, { "44", "Output mode undefined for \"" }, { "45", "\"!" }, { "46", "Password-only setting undefined for \"" }, { "47", "\"!" }, { "48", "Character set undefined for \"" }, { "49", "\"!" }, { "50", "Preference \"" }, { "51", "\" contains an empty string." }, { "52", "No value found for \"" }, { "53", "\"." }, { "54", "The type name \"" }, { "55", "\" is too long!" }, { "56", "The default type name \"" }, { "57", "\" is too long!" }, { "58", "No default password type set!" }, { "59", "A password type is needed!" }, { "60", "No output character set defined!" }, { "61", "Illegal password length 0!" }, { "62", "Argument missing for long option \"" }, { "63", "\"!" }, { "64", "Output character set missing for long option \"--mode=charset\"" }, }; /** Size of \a kv (number of entries). */ static size_t szkv = sizeof(kv)/sizeof(dk_key_value_t); /** Preferences keys. */ static char *pk[] = { /* 0 */ "/password/", /* 1 */ "/mode", /* 2 */ "/charset", /* 3 */ "/password/type", /* 4 */ "default", /* 5 */ "/suppress-name", /* 6 */ "/prngs", NULL }; /** Preferences keys for numeric values. */ static char *pk_numerics[] = { /* 0 */ "/length", /* 1 */ "/digits", /* 2 */ "/specials", /* 3 */ "/capitals", NULL }; /** Patterns to compare output mode. */ static char *pk_modes[] = { "d$efault", "h$ex", "a$scii85", "c$harset", NULL }; /** Output modes. */ static char *pk_modes_to_write[] = { "default", "hex", "ascii85", "charset", NULL }; /** Long options. */ static char *long_options[] = { /* 0 */ "h$elp", /* 1 */ "v$ersion", /* 2 */ "c$onfigure", /* 3 */ "sh$ow-configuration", /* 4 */ "un$configure", /* 5 */ "r$eset", /* 6 */ "l$ength", /* 7 */ "d$igits", /* 8 */ "sp$ecials", /* 9 */ "up$per-case", /* 10 */ "ou$tput", /* 11 */ "pr$ng", /* 12 */ "pa$ssword-only", /* 13 */ "sil$ently", NULL }; /** Names of PRNGs. */ static char *prngs_to_write[] = { "all", "openssl", "random", "rand48", "rand", NULL }; /** Boolean values to write. */ static char *booleans_to_write[] = { "off", "on", NULL }; /** Comma */ static char comma[] = { "," }; /** Name of string table to search. */ static char string_table_name[] = { "createp" }; /** String containing three spaces. */ static char three_spaces[] = { " " }; /** Hex numbers. */ static char hex_values[] = { "0123456789ABCDEF" }; /** Set of special characters. */ static char special_characters[] = { "^°!\"§$%&/()=?{[]}\\#'+*~-_.:,;<>|" }; /** Version text. */ static char *version_text[] = { "", "createp, version 3 (part of the dktools collection, version " VERSNUMB ")", "Copyright (C) 2002-2010 Dipl.-Ing. D. Krause", "http://dktools.sourceforge.net", "", NULL }; /** License terms. */ static char *license_terms[] = { "Redistribution and use in source and binary forms, with or without", "modification, are permitted provided that the following conditions are met:", "* Redistributions of source code must retain the above copyright notice, this", " list of conditions and the following disclaimer.", "* Redistributions in binary form must reproduce the above copyright notice,", " this list of conditions and the following disclaimer in the documentation", " and/or other materials provided with the distribution.", "* Neither the name of the Dirk Krause nor the names of other contributors may", " be used to endorse or promote products derived from this software without", " specific prior written permission.", "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"", "AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE", "IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE", "ARE DISCLAIMED.", "IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY", "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES", "(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;", "LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND", "ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT", "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS", "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.", NULL }; /** Section head ``Libraries used'' used to show license. */ static char *libraries_used[]= { "", "Libraries used:", "", NULL }; #if DK_HAVE_OPENSSL_RAND_H /** Text referring to OpenSSL shown in license. */ static char *ossl_txt[] = { "OpenSSL The OpenSSL cryptographic library", "\t http://www.openssl.org", NULL }; #endif /** Default help text if help text file is not found. */ static char *help_txt[] = { "", "createp - Password suggestor", "============================", "", "Usage", "-----", "" "createp -c -t ", " configures a password type.", "", "createp -C", " shows the current configuration.", "", "createp -u", " removes the permanent options.", "", "createp -h", " shows this help text.", "" "createp -v", " shows the version information.", "", "createp -t [] ", " suggests passwords.", "", "", "Options", "-------", "", "-l ", "-l -", " chooses the password length.", "", "-o ", " chooses the output mode, one of:", " default specify number of digits, special and uppercase chars", " hex output hex digits (0-9a-f)", " ascii85 use all characters from 33 ... 127", " charset specify a set of possible output characters manually", "", "-d ", "-d -", " chooses the number of digits in the password.", " (for default output mode only)", "", "-k ", "-k -", " chooses the number of upper-case characters in the password.", " (for default output mode only)", "", "-s ", "-s -", " chooses the number of special characters in the password.", " (for default output mode only)", "", "-a ", " chooses a set of possible PRNGs, either \"all\" (attempt all supported", " PRNGs) or a combination of:", " openssl the OpenSSL PRNG (the one you should prefer)", " random the PRNG using initstate()/setstate()/random()", " rand48 the PRNG using nrand48()", " rand the PRNG using rand()", "", "-p", " suppresses user name output, prints password suggestions only.", "", NULL }; /** Debug message. @param c Createp job. @param n Index of message text in message text array. */ static void debug_1 DK_P2(CMD *,c, size_t,n) { char *logmsgs[2]; logmsgs[0] = (c->msg)[n]; logmsgs[1] = NULL; dkapp_log_msg(c->a, DK_LOG_LEVEL_DEBUG, logmsgs, 1); } /** Debug message consisting of three parts. @param c Createp job. @param n1 Index of first part in message text array. @param n2 Index of third part in message text array. @param s Second part (i.e. file name, user name). */ static void debug_3 DK_P4(CMD *,c, size_t,n1, size_t,n2, char*,s) { char *logmsgs[4]; logmsgs[0] = (c->msg)[n1]; logmsgs[1] = s; logmsgs[2] = (c->msg)[n2]; logmsgs[3] = NULL; dkapp_log_msg(c->a, DK_LOG_LEVEL_DEBUG, logmsgs, 3); } /** Warning message consisting of three parts. @param c Createp job. @param n1 Index of first part in message text array. @param n2 Index of third part in message text array. @param s Second part (i.e. file name, user name). */ static void warn_3 DK_P4(CMD *,c, size_t,n1, size_t,n2, char*,s) { char *logmsgs[4]; logmsgs[0] = (c->msg)[n1]; logmsgs[1] = s; logmsgs[2] = (c->msg)[n2]; logmsgs[3] = NULL; dkapp_log_msg(c->a, DK_LOG_LEVEL_WARNING, logmsgs, 3); } /** Error message. @param c Createp job. @param n Index of message text in message text array. */ static void err_1 DK_P2(CMD *,c, size_t,n) { char *logmsgs[2]; logmsgs[0] = (c->msg)[n]; logmsgs[1] = NULL; dkapp_log_msg(c->a, DK_LOG_LEVEL_ERROR, logmsgs, 1); } /** Error message consisting of three parts. @param c Createp job. @param n1 Index of first part in message text array. @param n2 Index of third part in message text array. @param s Second part (i.e. file name, user name). */ static void err_3 DK_P4(CMD *,c, size_t,n1, size_t,n2, char*,s) { char *logmsgs[4]; logmsgs[0] = (c->msg)[n1]; logmsgs[1] = s; logmsgs[2] = (c->msg)[n2]; logmsgs[3] = NULL; dkapp_log_msg(c->a, DK_LOG_LEVEL_ERROR, logmsgs, 3); } /** Compare two name entries by order of appearance in the command line. This function is used to build the sorted storage. @param l Left entry. @param r Right entry. @param cr Comparison criteria (ignored). @return -1, 0 or 1 (comparison result). */ static int compare_names DK_P3(void *,l, void *,r, int,cr) { int back = 0; NAME *lname, *rname; lname = (NAME *)l; rname = (NAME *)r; if(lname) { if(rname) { if(lname->number > rname->number) { back = 1; } else { if(lname->number < rname->number) { back = -1; } } } else { back = 1; } } else { if(rname) { back = -1; } } return back; } /** Check whether to run absolutely silently. @param argc Number of command line arguments. @param argv Command line arguments array. @param rs Pointer to result variable (silent). @param rf Pointer to result variable (filter). */ static void silence_check DK_P4(int,argc, char **,argv, int *,rs, int *,rf) { int i; char *ptr, **lfdptr; int myrs = 0; lfdptr = argv; lfdptr++; i = 1; while(i < argc) { ptr = *lfdptr; if(*ptr == '-') { ptr++; if(*ptr == '-') { ptr++; switch(dkstr_array_abbr(long_options, ptr, '$', 0)) { case 13: myrs = 1; break; } } else { switch(*ptr) { case 't': case 'l': case 'd': case 's': case 'k': case 'o': { ptr++; if(!(*ptr)) { lfdptr++; i++; } } break; case 'S': { myrs = 1; } break; } } } lfdptr++; i++; } if(rs) { *rs = myrs; } } /** Set default values in CMD. @param c Createp job. */ static void cmd_reset DK_P1(CMD *,c) { c->rand_types_allowed = DK_RAND_TYPE_ALL; c->program_mode = PROGRAM_MODE_DEFAULT; c->l_min = 6; c->l_max = 6; c->d_min = 2; c->d_max = 2; c->s_min = 0; c->s_max = 0; c->u_min = 0; c->u_max = 0; c->exval = 1; c->f_cmd_rand_types_allowed = 0x00; c->f_cmd_mode = 0x00; c->f_cmd_l = 0x00; c->f_cmd_d = 0x00; c->f_cmd_s = 0x00; c->f_cmd_u = 0x00; c->f_cmd_charset = 0x00; c->pw_only = 0x00; c->f_pw_only = 0x00; } /** Reset the CMD to default values if -r occurs on the command line. @param c Createp job. */ static void option_reset DK_P1(CMD *,c) { cmd_reset(c); (c->b_type)[0] = '\0'; } /** Initialize a CMD struct. @param c Createp job. */ static void cmd_init DK_P1(CMD *,c) { c->program_action = ACTION_RUN; c->cs_buffer = NULL; c->u_cs_buffer = 0; c->b_cs_buffer = NULL; c->s_names = NULL; c->i_names = NULL; c->b_type = NULL; c->s_b_type = 0; cmd_reset(c); } /** Prepare a CMD struct for usage, set up data structures. @param c Createp job. @return 1 on success, 0 on error. */ static int prepare_cmd DK_P1(CMD *,c) { int back = 0; c->s_names = dksto_open(0); if(c->s_names) { dksto_set_comp(c->s_names, compare_names, 0); c->i_names = dksto_it_open(c->s_names); if(c->i_names) { c->b_cs_buffer = dkbf_open(256); if(c->b_cs_buffer) { dkbf_reset(c->b_cs_buffer); back = 1; } else { err_1(c, 0); } } else { err_1(c, 0); } } else { err_1(c, 0); } return back; } /** Clean up the CMD structure, release dynamic memory. @param c Createp job. */ static void cleanup_cmd DK_P1(CMD *,c) { NAME *nptr; if(c->s_names) { if(c->i_names) { dksto_it_reset(c->i_names); while((nptr = (NAME *)dksto_it_next(c->i_names)) != NULL) { if(nptr->name) { dk_delete(nptr->name); } nptr->name = NULL; nptr->number = 0UL; dk_delete(nptr); } dksto_it_close(c->i_names); } dksto_close(c->s_names); } if(c->b_cs_buffer) { dkbf_close(c->b_cs_buffer); } } /** Retrieve one password-type-specific preference. @param c Createp job. @param k Preference sub name (/type/xxx/kkk). @param b Result buffer. @param sz Size of \a b. @return Pointer (b) on success, NULL on error. */ static char * get_pw_type_pref DK_P4(CMD *,c, char *,k, char *,b, size_t,sz) { char *back = NULL; char kb[DEFAULT_BUFFER_LENGTH]; if(strlen(c->b_type) > 0) { if((strlen(pk[0]) + strlen(c->b_type) + strlen(k)) < sizeof(kb)) { strcpy(kb, pk[0]); strcat(kb, c->b_type); strcat(kb, k); if(dkapp_get_pref(c->a, kb, b, sz, 0)) { back = dkstr_start(b, NULL); if(back) { dkstr_chomp(back, NULL); } else { debug_3(c, 50, 51, kb); } } else { debug_3(c, 52, 53, kb); } } else { err_3(c, 54, 55, c->b_type); } } else { /* INTERNAL ERROR: No type defined, should not happen */ } return back; } /** Convert text to a number or to a range of numbers. @param min Pointer to result minimum. @param max pointer to result maximum. @param s String to convert. @return 1 on success, 0 on error. */ static int convert_text_to_numbers DK_P3(unsigned *,min, unsigned *,max, char *,s) { int back = 0; unsigned u1, u2; char *ptr; ptr = dkstr_chr(s, '-'); if(ptr) { *(ptr++) = '\0'; if(sscanf(s, "%u", &u1) == 1) { back = 1; *min = u1; *max = u1; if(sscanf(ptr, "%u", &u2) == 1) { if(u1 < u2) { *max = u2; } else { *min = u2; *max = u1; } } } } else { if(sscanf(s, "%u", &u1) == 1) { back = 1; *min = u1; *max = u1; } } return back; } /** Retrieve numeric value or range from preferences. @param c Createp job. @param f Flag: already found on command line. @param min Pointer to minimum result buffer. @param max Pointer to maximum result buffer. @param ind Type: 0=length, 1=digits, 2=specials, 3=uppercase. */ static void get_numerics DK_P5(CMD *,c,unsigned char,f,unsigned *,min,unsigned *,max, unsigned,ind) { char valbuffer[DEFAULT_BUFFER_LENGTH], x[sizeof(valbuffer)], *ptr; if(!f) { ptr = get_pw_type_pref(c, pk_numerics[ind], valbuffer, sizeof(valbuffer)); if(ptr) { strcpy(x, ptr); if(!convert_text_to_numbers(min, max, ptr)) { warn_3(c, 3, 4, x); } } else { if(!((c->program_action) & ACTION_CONFIGURE)) { switch(ind) { case 0: { warn_3(c, 34, 35, c->b_type); } break; case 1: { warn_3(c, 36, 37, c->b_type); } break; case 2: { warn_3(c, 38, 39, c->b_type); } break; case 3: { warn_3(c, 40, 41, c->b_type); } break; } } } } } /** Retrieve output mode from string. @param c Createp job. @param s String containing output mode. @return 1 on success, 0 on error. */ static int get_mode_from_string DK_P2(CMD *,c, char *,s) { int back = 0; int i; i = dkstr_array_abbr(pk_modes, s, '$', 0); if(i > -1) { c->program_mode = i; back = 1; } return back; } /** Retrieve output mode from preferences. @param c Createp job. @return 1 on success, 0 on error. */ static int get_mode DK_P1(CMD *,c) { int back = 1; char valbuffer[DEFAULT_BUFFER_LENGTH], *ptr1; if(!(c->f_cmd_mode)) { ptr1 = get_pw_type_pref(c, pk[1], valbuffer, sizeof(valbuffer)); if(ptr1) { back = get_mode_from_string(c, ptr1); if(!back) { warn_3(c, 5, 6, ptr1); } } else { if(!((c->program_action) & ACTION_CONFIGURE)) { warn_3(c, 44, 45, c->b_type); } } } return back; } /** Retrieve allowed output character set from a string. @param c Createp job. @param s String containing allowed output characters. */ static void get_charset_from_string DK_P2(CMD *,c, char *,s) { char cc, *ptr1; unsigned char uc, *uptr; unsigned u; ptr1 = s; uptr = c->cs_buffer; c->u_cs_buffer = 0; dkbf_reset(c->b_cs_buffer); while(*ptr1) { cc = *(ptr1++); uc = (unsigned char)cc; u = (unsigned)uc; u = (u & 255); switch(cc) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { for(cc = '0'; cc <= '9'; cc++) { uc = (unsigned char)cc; u = (unsigned)uc; u &= 255; if(!dkbf_get(c->b_cs_buffer, u)) { c->u_cs_buffer += 1; *(uptr++) = uc; dkbf_set(c->b_cs_buffer, u, 1); } } } break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g': case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n': case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': { for(cc = 'a'; cc <= 'z'; cc++) { uc = (unsigned char)cc; u = (unsigned)uc; u &= 255; if(!dkbf_get(c->b_cs_buffer, u)) { c->u_cs_buffer += 1; *(uptr++) = uc; dkbf_set(c->b_cs_buffer, u, 1); } } } break; case 'A': case 'F': case 'K': case 'P': case 'U': case 'B': case 'G': case 'L': case 'Q': case 'V': case 'C': case 'H': case 'M': case 'R': case 'W': case 'D': case 'I': case 'N': case 'S': case 'X': case 'E': case 'J': case 'O': case 'T': case 'Y': case 'Z': { for(cc = 'A'; cc <= 'Z'; cc++) { uc = (unsigned char)cc; u = (unsigned)uc; u &= 255; if(!dkbf_get(c->b_cs_buffer, u)) { c->u_cs_buffer += 1; *(uptr++) = uc; dkbf_set(c->b_cs_buffer, u, 1); } } } break; default: { if(!dkbf_get(c->b_cs_buffer, u)) { if((c->u_cs_buffer) < 256) { c->u_cs_buffer += 1; *uptr++ = uc; dkbf_set(c->b_cs_buffer, u, 1); } } } break; } } } /** Retrieve allowed output character set from preferences. @param c Createp job. @return 1 on success, 0 on error. */ static int get_charset DK_P1(CMD *,c) { int back = 0; char valbuffer[DEFAULT_BUFFER_LENGTH], *ptr1; if(!(c->f_cmd_charset)) { ptr1 = get_pw_type_pref(c, pk[2], valbuffer, sizeof(valbuffer)); if(ptr1) { get_charset_from_string(c, ptr1); if(c->u_cs_buffer) { back = 1; } else { warn_3(c, 7, 8, ptr1); } } else { if(!((c->program_action) & ACTION_CONFIGURE)) { warn_3(c, 48, 48, c->b_type); } } } return back; } /** Check whether to print user name / passord pair to output or just the password. @param c Createp job. */ static void get_pw_only DK_P1(CMD *,c) { char valbuffer[DEFAULT_BUFFER_LENGTH], *ptr1; if(!(c->f_pw_only)) { ptr1 = get_pw_type_pref(c, pk[5], valbuffer, sizeof(valbuffer)); if(ptr1) { if(dkstr_is_bool(ptr1)) { if(dkstr_is_on(ptr1)) { c->pw_only = 0x01; } else { c->pw_only = 0x00; } } else { warn_3(c, 9, 10, ptr1); } } else { if(!((c->program_action) & ACTION_CONFIGURE)) { warn_3(c, 46,47, c->b_type); } } } } /** Retrieve allowed PRNG types from preferences. @param c Createp job. */ static void get_rand_types_allowed_for_type DK_P1(CMD *,c) { char valbuffer[DEFAULT_BUFFER_LENGTH], *ptr1; if(!(c->f_cmd_rand_types_allowed)) { ptr1 = get_pw_type_pref(c, pk[6], valbuffer, sizeof(valbuffer)); if(ptr1) { c->rand_types_allowed = dkapp_rand_types_from_string(c->a, ptr1); } else { if(!((c->program_action) & ACTION_CONFIGURE)) { warn_3(c, 42, 43, c->b_type); } } } } /** Get missing attributes for required password type from preferences. @param c Createp job. @return 1 on success, 0 on error. */ static int configure_for_type DK_P1(CMD *,c) { int back = 1; get_rand_types_allowed_for_type(c); get_numerics(c, c->f_cmd_l, &(c->l_min), &(c->l_max), 0); get_mode(c); get_pw_only(c); switch(c->program_mode) { case PROGRAM_MODE_DEFAULT: { get_numerics(c, c->f_cmd_d, &(c->d_min), &(c->d_max), 1); get_numerics(c, c->f_cmd_s, &(c->s_min), &(c->s_max), 2); get_numerics(c, c->f_cmd_u, &(c->u_min), &(c->u_max), 3); } break; case PROGRAM_MODE_SET: { get_charset(c); } break; } return back; } /** Load defaults from the preferences system. Use built-in defaults if preferences are not yet set. @param c Createp job. */ static void load_defaults_from_preferences DK_P1(CMD *,c) { int found = 0; char valbuffer[DEFAULT_BUFFER_LENGTH], *ptr1; if(dkapp_get_pref(c->a, pk[3], valbuffer, sizeof(valbuffer), 0)) { ptr1 = dkstr_start(valbuffer, NULL); if(ptr1) { dkstr_chomp(ptr1, NULL); if(strlen(ptr1) < c->s_b_type) { strcpy(c->b_type, ptr1); found = 1; } else { warn_3(c, 56, 57, ptr1); } } else { debug_1(c, 58); } } else { debug_1(c, 58); } if(!found) { if(strlen(pk[4]) < c->s_b_type) { strcpy(c->b_type, pk[4]); found = 1; } } if(found) { configure_for_type(c); } } /** Process the command line arguments. @param c Createp job. @return 1 on success, 0 on error. */ static int process_arguments DK_P1(CMD *,c) { int back = 1; unsigned long namenumber = 0UL; int xargc, i; char argbuffer[256], *ptr, **xargv, **lfdptr, *optptr, *vptr; NAME *nptr; load_defaults_from_preferences(c); xargc = dkapp_get_argc(c->a); xargv = dkapp_get_argv(c->a); lfdptr = xargv; lfdptr++; i = 1; while(i < xargc) { ptr = *lfdptr; switch(*ptr) { case '-': { optptr = ptr; ptr++; switch(*ptr) { case '-': { ptr++; if(strlen(ptr) < sizeof(argbuffer)) { strcpy(argbuffer, ptr); vptr = dkstr_chr(argbuffer, '='); if(vptr) { *(vptr++) = '\0'; vptr = dkstr_start(vptr, NULL); if(vptr) { dkstr_chomp(vptr, NULL); } } switch(dkstr_array_abbr(long_options, argbuffer, '$', 0)) { case 0: { c->program_action |= ACTION_HELP; } break; case 1: { c->program_action |= ACTION_VERSION; } break; case 2: { c->program_action |= ACTION_CONFIGURE; } break; case 3: { c->program_action |= ACTION_SHOWCONF; } break; case 4: { c->program_action |= ACTION_UNCONFIGURE; } break; case 5: { option_reset(c); } break; case 6: { if(vptr) { if(convert_text_to_numbers(&(c->l_min), &(c->l_max), vptr)) { c->f_cmd_l = 0x01; } else { warn_3(c, 3, 4, vptr); } } else { err_3(c, 62, 63, ptr); } } break; case 7: { if(vptr) { if(convert_text_to_numbers(&(c->d_min), &(c->d_max), vptr)) { c->f_cmd_d = 0x01; } else { warn_3(c, 3, 4, vptr); } } else { err_3(c, 62, 63, optptr); } } break; case 8: { if(vptr) { if(convert_text_to_numbers(&(c->s_min), &(c->s_max), vptr)) { c->f_cmd_s = 0x01; } else { warn_3(c, 3, 4, vptr); } } else { err_3(c, 62, 63, optptr); } } break; case 9: { if(vptr) { if(convert_text_to_numbers(&(c->u_min), &(c->u_max), vptr)) { c->f_cmd_u = 0x01; } else { warn_3(c, 3, 4, vptr); } } else { err_3(c, 62, 63, optptr); } } break; case 10: { if(vptr) { char *xptr; xptr = dkstr_chr(vptr, ':'); if(xptr) { *(xptr++) = '\0'; } if(get_mode_from_string(c, vptr)) { c->f_cmd_mode = 0x01; switch(c->program_mode) { case PROGRAM_MODE_SET: { if(xptr) { get_charset_from_string(c, xptr); c->f_cmd_charset = 0x01; if(!(c->u_cs_buffer)) { warn_3(c, 7, 8, xptr); } } else { err_1(c, 64); } } break; } } else { err_3(c, 5, 6, vptr); } } else { err_3(c, 62, 63, optptr); } } break; case 11: { if(vptr) { c->rand_types_allowed = dkapp_rand_types_from_string(c->a, vptr); c->f_cmd_rand_types_allowed = 0x01; } else { err_3(c, 62, 63, optptr); } } break; case 12: { if(vptr) { if(dkstr_is_bool(vptr)) { if(dkstr_is_on(vptr)) { c->pw_only = 0x01; } else { c->pw_only = 0x00; } c->f_pw_only = 0x01; } else { err_3(c, 9, 10, vptr); } } else { c->pw_only = 0x01; c->f_pw_only = 0x01; } } break; } } else { err_3(c, 1, 2, optptr); back = 0; } } break; case 'a': { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < xargc) { ptr = *lfdptr; } } if(ptr) { if(strlen(ptr) < sizeof(argbuffer)) { strcpy(argbuffer, ptr); c->rand_types_allowed = dkapp_rand_types_from_string(c->a, argbuffer); c->f_cmd_rand_types_allowed = 0x01; } else { err_3(c, 1, 2, ptr); back = 0; } } } break; case 't': { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < xargc) { ptr = *lfdptr; } } if(ptr) { if(strlen(ptr) < c->s_b_type) { strcpy(c->b_type, ptr); if(!configure_for_type(c)) { back = 0; } } } } break; case 'p': { ptr++; if(*ptr == '-') { c->pw_only = 0x00; } else { c->pw_only = 0x01; } c->f_pw_only = 0x01; } break; case 'o': { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < xargc) { ptr = *lfdptr; } } if(ptr) { if(strlen(ptr) < sizeof(argbuffer)) { strcpy(argbuffer, ptr); if(get_mode_from_string(c, argbuffer)) { c->f_cmd_mode = 0x01; switch(c->program_mode) { case PROGRAM_MODE_SET: { lfdptr++; i++; if(i < xargc) { ptr = *lfdptr; if(strlen(ptr) < sizeof(argbuffer)) { strcpy(argbuffer, ptr); get_charset_from_string(c, argbuffer); c->f_cmd_charset = 0x01; if(!(c->u_cs_buffer)) { warn_3(c, 7, 8, argbuffer); } } else { err_3(c, 1, 2, ptr); back = 0; } } } break; } } else { err_3(c, 5, 6, argbuffer); } } } } break; case 'l': { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < xargc) { ptr = *lfdptr; } } if(ptr) { if(strlen(ptr) < sizeof(argbuffer)) { strcpy(argbuffer, ptr); if(convert_text_to_numbers(&(c->l_min), &(c->l_max), argbuffer)) { c->f_cmd_l = 0x01; } else { warn_3(c, 3, 4, ptr); } } else { /* ERROR: String too long */ err_3(c, 1, 2, ptr); back = 0; } } } break; case 'd': { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < xargc) { ptr = *lfdptr; } } if(ptr) { if(strlen(ptr) < sizeof(argbuffer)) { strcpy(argbuffer, ptr); if(convert_text_to_numbers(&(c->d_min), &(c->d_max), argbuffer)) { c->f_cmd_d = 0x01; } else { warn_3(c, 3, 4, ptr); } } else { /* ERROR STRING too long */ err_3(c, 1, 2, ptr); back = 0; } } } break; case 's': { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < xargc) { ptr = *lfdptr; } } if(ptr) { if(strlen(ptr) < sizeof(argbuffer)) { strcpy(argbuffer, ptr); if(convert_text_to_numbers(&(c->s_min), &(c->s_max), argbuffer)) { c->f_cmd_s = 0x01; } else { warn_3(c, 3, 4, ptr); } } else { /* ERROR: String too long */ err_3(c, 1, 2, ptr); back = 0; } } } break; case 'k': { ptr++; if(!(*ptr)) { ptr = NULL; lfdptr++; i++; if(i < xargc) { ptr = *lfdptr; } } if(ptr) { if(strlen(ptr) < sizeof(argbuffer)) { strcpy(argbuffer, ptr); if(convert_text_to_numbers(&(c->u_min), &(c->u_max), argbuffer)) { c->f_cmd_u = 0x01; } else { warn_3(c, 3, 4, ptr); } } else { /* ERROR: String too long */ err_3(c, 1, 2, ptr); back = 0; } } } break; case 'r': { option_reset(c); } break; case 'S': { } break; case 'h': { c->program_action |= ACTION_HELP; } break; case 'v': { c->program_action |= ACTION_VERSION; } break; case 'c': { c->program_action |= ACTION_CONFIGURE; } break; case 'C': { c->program_action |= ACTION_SHOWCONF; } break; case 'u': { c->program_action |= ACTION_UNCONFIGURE; } break; } } break; default: { nptr = dk_new(NAME,1); if(nptr) { nptr->name = NULL; nptr->number = namenumber++; nptr->name = dkstr_dup(ptr); if(nptr->name) { if(!dksto_add(c->s_names, nptr)) { /* ERROR: Memory */ err_1(c, 0); back = 0; dk_delete(nptr->name); nptr->name = NULL; nptr->number = 0UL; dk_delete(nptr); nptr = NULL; } } else { /* ERROR: Memory */ err_1(c, 0); back = 0; dk_delete(nptr); nptr = NULL; } } else { /* ERROR: Memory */ err_1(c, 0); back = 0; } } break; } lfdptr++; i++; } return back; } /** Print version number. @param c Createp job. */ static void print_version DK_P1(CMD *,c) { char **ptr; ptr = version_text; while(*ptr) { fputs(*(ptr++), stdout); fputc('\n', stdout); } ptr = license_terms; while(*ptr) { fputs(*(ptr++), stdout); fputc('\n', stdout); } ptr = libraries_used; while(*ptr) { fputs(*(ptr++), stdout); fputc('\n', stdout); } ptr = dklic_get(); while(*ptr) { fputs(*(ptr++), stdout); fputc('\n', stdout); } #if DK_HAVE_OPENSSL_RAND_H ptr = ossl_txt; while(*ptr) { fputs(*(ptr++), stdout); fputc('\n', stdout); } #endif } /** Print help text. @param c Createp job. */ static void print_help DK_P1(CMD *,c) { dkapp_help(c->a, "createp.txt", help_txt); } /** Convert allowed character set to short description. @param c Createp job. @param vb Result buffer. @param szvb Size of \a vb. */ static void charset_to_short DK_P3(CMD *,c, char *,vb, size_t,szvb) { char *vptr; size_t used, i; unsigned char have_small, have_large, have_digits; DK_MEMRES(vb,szvb) ; vptr = vb; used = 0; have_small = have_large = have_digits = 0x00; for(i = 0; ((i < c->u_cs_buffer) && (used < szvb)); i++) { if(((c->cs_buffer)[i] >= 'a') && ((c->cs_buffer)[i] <= 'z')) { if(!have_small) { have_small = 0x01; *(vptr++) = 'a'; used++; } } else { if(((c->cs_buffer)[i] >= 'A') && ((c->cs_buffer)[i] <= 'Z')) { if(!have_large) { have_large = 0x01; *(vptr++) = 'A'; used++; } } else { if(((c->cs_buffer)[i] >= '0') && ((c->cs_buffer)[i] <= '9')) { if(!have_digits) { have_digits = 0x01; *(vptr++) = '0'; used++; } } else { *(vptr++) = (c->cs_buffer)[i]; used++; } } } } if(used < szvb) { *vptr = '\0'; } else { vb[szvb-1] = '\0'; } } /** Save password type attribute to preferences. @param c Createp job. @param k Key. @param v Value. */ static void save_pw_type_pref DK_P3(CMD *,c, char *,k, char *,v) { char kb[DEFAULT_BUFFER_LENGTH]; if(strlen(c->b_type) > 0) { if((strlen(pk[0]) + strlen(c->b_type) + strlen(k)) < sizeof(kb)) { strcpy(kb, pk[0]); strcat(kb, c->b_type); strcat(kb, k); dkapp_set_pref(c->a, kb, v); } else { err_3(c, 54, 55, c->b_type); } } else { err_1(c, 59); } } /** Write number of range to buffer. @param b Result buffer. @param min Minimum value. @param max Maximum value. */ static void num_or_range_to_buffer DK_P3(char *,b, unsigned,min, unsigned,max) { if(min < max) { sprintf(b, "%u-%u", min, max); } else { sprintf(b, "%u", min); } } /** Add one allowed PRNG name to buffer. @param c Createp job. @param b Result buffer. @param szb Size of \a b. @param r PRNG ID. @param i Index of PRNG name in messages. */ static void add_one_prng DK_P5(CMD *,c, char *,b, size_t,szb, int,r, int,i) { if((c->rand_types_allowed) & r) { if(strlen(b) > 0) { if((strlen(b) + strlen(comma) + strlen(prngs_to_write[i])) < szb) { strcat(b, comma); strcat(b, prngs_to_write[i]); } } else { if(strlen(prngs_to_write[i]) < szb) { strcpy(b, prngs_to_write[i]); } } } } /** Write list of allowed PRNGs to buffer. @param c Createp job. @param b Buffer. @param szb Size of \a b. */ static void prngs_to_buffer DK_P3(CMD *,c, char *,b, size_t,szb) { DK_MEMRES(b,szb) ; if((c->rand_types_allowed) == DK_RAND_TYPE_ALL) { if(strlen(prngs_to_write[0]) < szb) { strcpy(b, prngs_to_write[0]); } } else { add_one_prng(c, b, szb, DK_RAND_TYPE_OPENSSL, 1); add_one_prng(c, b, szb, DK_RAND_TYPE_STATE, 2); add_one_prng(c, b, szb, DK_RAND_TYPE_RAND48, 3); add_one_prng(c, b, szb, DK_RAND_TYPE_SIMPLE, 4); } } /** Save configuration to preferences. @param c Createp job. */ static void save_configuration DK_P1(CMD *,c) { char valbuffer[DEFAULT_BUFFER_LENGTH]; if(!strlen(c->b_type)) { if(strlen(pk[4]) < c->s_b_type) { strcpy(c->b_type, pk[4]); } } if(strlen(c->b_type)) { dkapp_set_pref(c->a, pk[3], c->b_type); /* PRNGs */ prngs_to_buffer(c, valbuffer, sizeof(valbuffer)); save_pw_type_pref(c, pk[6], valbuffer); /* length */ num_or_range_to_buffer(valbuffer, c->l_min, c->l_max); save_pw_type_pref(c, pk_numerics[0], valbuffer); /* mode */ save_pw_type_pref(c, pk[5], booleans_to_write[(c->pw_only) ? 1 : 0]); save_pw_type_pref(c, pk[1], pk_modes_to_write[c->program_mode]); /* password only */ switch(c->program_mode) { case PROGRAM_MODE_DEFAULT: { /* digits */ num_or_range_to_buffer(valbuffer, c->d_min, c->d_max); save_pw_type_pref(c, pk_numerics[1], valbuffer); /* specials */ num_or_range_to_buffer(valbuffer, c->s_min, c->s_max); save_pw_type_pref(c, pk_numerics[2], valbuffer); /* upper-case */ num_or_range_to_buffer(valbuffer, c->u_min, c->u_max); save_pw_type_pref(c, pk_numerics[3], valbuffer); } break; case PROGRAM_MODE_SET: { /* charset */ charset_to_short(c, valbuffer, sizeof(valbuffer)); save_pw_type_pref(c, pk[2], valbuffer); } break; } } } /** Get maximum value of two sizes. @param s1 One size. @param s2 Another size. @return Maximum of \a s1 and \a s2. */ static size_t max_size DK_P2(size_t,s1,size_t,s2) { size_t back; back = ((s1 > s2) ? s1 : s2); return back; } /** Put text centered. @param a Application. @param s String to print. @param lgts Length of string printed on screen. @param range Available length to print string. */ static void put_centered DK_P4(dk_app_t *,a, char *,s, size_t,lgts, size_t,range) { size_t i, j, k; if(lgts < range) { i = (range - lgts) / 2; j = range - lgts - i; for(k = 0; k < i; k++) fputc(' ', stdout); dkapp_stdout(a, s); for(k = 0; k < j; k++) fputc(' ', stdout); } else { dkapp_stdout(a, s); } } /** Convert a line number to text describing the used PRNG. @param i Index of PRNG. @return Index in message array containing PRNG name. */ static size_t line_number_to_prng_description DK_P1(size_t,i) { size_t back = 15; switch(i) { case 1: back = 16; break; case 2: back = 17; break; case 3: back = 18; break; } return back; } /** Show configuration. @param c Createp job. */ static void show_configuration DK_P1(CMD *,c) { char bl[64], bd[64], bs[64], bu[64]; char br[DEFAULT_BUFFER_LENGTH], bc[DEFAULT_BUFFER_LENGTH], *bm; char *suppress_name; size_t sz, i, j, k; num_or_range_to_buffer(bl, c->l_min, c->l_max); num_or_range_to_buffer(bd, c->d_min, c->d_max); num_or_range_to_buffer(bs, c->s_min, c->s_max); num_or_range_to_buffer(bu, c->u_min, c->u_max); prngs_to_buffer(c, br, sizeof(br)); if(c->program_mode == PROGRAM_MODE_SET) { charset_to_short(c, bc, sizeof(bc)); } else { bc[0] = '\0'; } bm = pk_modes_to_write[c->program_mode]; suppress_name = (c->msg)[(c->pw_only) ? 11 : 12]; sz = strlen(bm); if(c->rand_types_allowed == DK_RAND_TYPE_ALL) { sz = max_size(sz, strlen(br)); } sz = max_size(sz, dkapp_prlen(c->a, c->b_type)); sz = max_size(sz, strlen(bl)); sz = max_size(sz, dkapp_prlen(c->a, suppress_name)); sz = max_size(sz, strlen(bm)); switch(c->program_mode) { case PROGRAM_MODE_DEFAULT: { sz = max_size(sz, strlen(bd)); sz = max_size(sz, strlen(bs)); sz = max_size(sz, strlen(bu)); } break; case PROGRAM_MODE_SET: { sz = max_size(sz, strlen(bc)); } break; } /* type */ fputs("-t", stdout); fputs(three_spaces, stdout); put_centered(c->a, c->b_type, dkapp_prlen(c->a, c->b_type), sz); fputs(three_spaces, stdout); dkapp_stdout(c->a, (c->msg)[13]); fputc('\n', stdout); /* PRNGS */ fputs("-a", stdout); fputs(three_spaces, stdout); if(c->rand_types_allowed == DK_RAND_TYPE_ALL) { put_centered(c->a, br, strlen(br), sz); fputs(three_spaces, stdout); dkapp_stdout(c->a, (c->msg)[14]); } else { fputs(br, stdout); fputc('\n', stdout); for(i = 0; i < sz + 8; i++) fputc(' ', stdout); dkapp_stdout(c->a, (c->msg)[14]); } fputc('\n', stdout); for(j = 0; j < 4; j++) { k = line_number_to_prng_description(j); for(i = 0; i < sz + 8; i++) fputc(' ', stdout); dkapp_stdout(c->a, (c->msg)[k]); fputc('\n', stdout); } /* output mode */ fputs("-o", stdout); fputs(three_spaces, stdout); put_centered(c->a, bm, strlen(bm), sz); fputs(three_spaces, stdout); if(c->program_mode == PROGRAM_MODE_SET) { fputs(bc, stdout); fputc('\n', stdout); for(i = 0; i < sz + 8; i++) fputc(' ', stdout); } dkapp_stdout(c->a, (c->msg)[19]); fputc('\n', stdout); for(j = 0; j < 10; j++) { for(i = 0; i < sz + 8; i++) fputc(' ', stdout); dkapp_stdout(c->a, (c->msg)[20+j]); fputc('\n', stdout); } /* length */ fputs("-l", stdout); fputs(three_spaces, stdout); put_centered(c->a, bl, strlen(bl), sz); fputs(three_spaces, stdout); dkapp_stdout(c->a, (c->msg)[30]); fputc('\n', stdout); switch(c->program_mode) { case PROGRAM_MODE_DEFAULT: { /* digits */ fputs("-d", stdout); fputs(three_spaces, stdout); put_centered(c->a, bd, strlen(bd), sz); fputs(three_spaces, stdout); dkapp_stdout(c->a, (c->msg)[31]); fputc('\n', stdout); /* specials */ fputs("-s", stdout); fputs(three_spaces, stdout); put_centered(c->a, bs, strlen(bs), sz); fputs(three_spaces, stdout); dkapp_stdout(c->a, (c->msg)[32]); fputc('\n', stdout); /* uppercase */ fputs("-k", stdout); fputs(three_spaces, stdout); put_centered(c->a, bu, strlen(bu), sz); fputs(three_spaces, stdout); dkapp_stdout(c->a, (c->msg)[33]); fputc('\n', stdout); } break; } } /** Create a random unsigned in a specified range. @param c Createp job @param v Pointer to result buffer. @param min Minimum value. @param max maximum value. */ static void create_unsigned DK_P4(CMD *,c, unsigned *,v, unsigned,min, unsigned,max) { unsigned l; if(min == max) { *v = min; } else { dkapp_rand_bytes(c->a, (void *)(&l), sizeof(unsigned)); l = min + (l % (1U + max - min)); if(l < min) l = min; if(l > max) l = max; *v = l; } } /** Create one password or WPA key using a specified output character set. @param c Createp job @param n User or host name. */ static void one_set DK_P2(CMD *,c, char *,n) { unsigned long ul; unsigned i; size_t sz; create_unsigned(c, &(c->l), c->l_min, c->l_max); if((!(c->pw_only)) && (n)) { fputs(n, stdout); fputc(' ', stdout); } for(i = 0; i < c->l; i++) { dkapp_rand_bytes(c->a, (void *)(&ul), sizeof(unsigned long)); ul = ul % (unsigned long)(c->u_cs_buffer); sz = (size_t)ul; if(sz >= c->u_cs_buffer) sz = c->u_cs_buffer - 1; fputc((c->cs_buffer)[sz], stdout); } fputc('\n', stdout); } /** Create passwords or WPA keys using a specified output character set. @param c Createp job. */ static void do_set DK_P1(CMD *,c) { unsigned char found; NAME *nptr; if(c->u_cs_buffer > 0) { found = 0x00; dksto_it_reset(c->i_names); while((nptr = (NAME *)dksto_it_next(c->i_names)) != NULL) { found = 0x01; one_set(c, nptr->name); } if(!found) { one_set(c, NULL); } } else { err_1(c, 60); c->exval = 1; } } /** Create one password or WPA key using random data and ASCII-Hex encoding. @param c Createp job. @param n User or host name. */ static void one_hex DK_P2(CMD *,c, char *,n) { unsigned long rval; unsigned i; size_t ind; size_t pos; size_t max; create_unsigned(c, &(c->l), c->l_min, c->l_max); if((!(c->pw_only)) && (n)) { fputs(n, stdout); fputc(' ', stdout); } dkapp_rand_bytes(c->a, (void *)(&rval), sizeof(unsigned long)); pos = 0; max = 2 * sizeof(unsigned long); for(i = 0; i < c->l; i++) { ind = (size_t)(rval & 0x0FUL); fputc(hex_values[ind], stdout); rval = rval >> 4; pos++; if((pos >= max) && (i < (c->l - 1))) { dkapp_rand_bytes(c->a, (void *)(&rval), sizeof(unsigned long)); pos = 0; } } fputc('\n', stdout); } /** Create passwords or WPA keys using random data and ASCII-Hex encoding. @param c Createp job. */ static void do_hex DK_P1(CMD *,c) { unsigned char found; NAME *nptr; found = 0x00; dksto_it_reset(c->i_names); while((nptr = (NAME *)dksto_it_next(c->i_names)) != NULL) { found = 0x01; one_hex(c, nptr->name); } if(!found) { one_hex(c, NULL); } } /** Create one password or WPA key using random data and ASCII-85 encoding. @param c Createp job. @param n User or host name. */ static void one_ascii85 DK_P2(CMD *,c, char *,n) { unsigned i; size_t pos, sz; unsigned long rval; char uc; create_unsigned(c, &(c->l), c->l_min, c->l_max); if((!(c->pw_only)) && (n)) { fputs(n, stdout); fputc(' ', stdout); } dkapp_rand_bytes(c->a, (void *)(&rval), sizeof(unsigned long)); pos = 0; for(i = 0; i < c->l; i++) { sz = (size_t)(rval % 85); uc = (char)(33 + sz); fputc(uc, stdout); rval = rval / 85UL; pos++; if((pos >= 5) && (i < (c->l - 1))) { dkapp_rand_bytes(c->a, (void *)(&rval), sizeof(unsigned long)); pos = 0; } } fputc('\n', stdout); } /** Create passwords or WPA keys by getting random data and applying ASCII-85 encoding. @param c Create job. */ static void do_ascii85 DK_P1(CMD *,c) { unsigned char found; NAME *nptr; found = 0x00; dksto_it_reset(c->i_names); while((nptr = (NAME *)dksto_it_next(c->i_names)) != NULL) { found = 0x01; one_ascii85(c, nptr->name); } if(!found) { one_ascii85(c, NULL); } } #line 2229 "createp.ctr" #line 2230 "createp.ctr" #line 2231 "createp.ctr" #line 2232 "createp.ctr" #line 2233 "createp.ctr" #line 2234 "createp.ctr" #line 2235 "createp.ctr" #line 2236 "createp.ctr" #line 2237 "createp.ctr" #line 2238 "createp.ctr" #line 2239 "createp.ctr" #line 2240 "createp.ctr" #line 2241 "createp.ctr" #line 2242 "createp.ctr" #line 2243 "createp.ctr" /** Create one password using the default algorithm. @param c Createp job. @param n User name. @param p1 Pointer to result buffer. @param p2 In: result buffer length, out: result buffer used. */ static void one_default DK_P4(CMD *,c, char *,n, unsigned char *,p1, size_t *,p2) { unsigned i; size_t j, k, l, avail, sz; for(i = 0; i < c->l_max; i++) { p1[i] = 0x00; p2[i] = (size_t)i; } #line 2263 "createp.ctr" create_unsigned(c, &(c->l), c->l_min, c->l_max); create_unsigned(c, &(c->d), c->d_min, c->d_max); create_unsigned(c, &(c->s), c->s_min, c->s_max); create_unsigned(c, &(c->u), c->u_min, c->u_max); if((!(c->pw_only)) && (n)) { fputs(n, stdout); fputc(' ', stdout); } avail = c->l; #line 2272 "createp.ctr" if(c->d > 0) { for(j = 0; ((j < c->d) && (avail > 0)); j++) { dkapp_rand_bytes(c->a, (void *)(&k), sizeof(size_t)); k = k % avail; l = p2[k]; p1[l] = 0x01; while(k < (avail - 1)) { p2[k] = p2[k+1]; k++; } avail--; #line 2281 "createp.ctr" } } if(c->s > 0) { for(j = 0; ((j < c->s) && (avail > 0)); j++) { dkapp_rand_bytes(c->a, (void *)(&k), sizeof(size_t)); k = k % avail; l = p2[k]; p1[l] = 0x02; while(k < (avail - 1)) { p2[k] = p2[k+1]; k++; } avail--; #line 2292 "createp.ctr" } } if(c->u > 0) { for(j = 0; ((j < c->u) && (avail > 0)); j++) { dkapp_rand_bytes(c->a, (void *)(&k), sizeof(size_t)); k = k % avail; l = p2[k]; p1[l] = 0x03; while(k < (avail - 1)) { p2[k] = p2[k+1]; k++; } avail--; #line 2303 "createp.ctr" } } for(i = 0; i < c->l; i++) { dkapp_rand_bytes(c->a, (void *)(&sz), sizeof(size_t)); if(p1[i] == 0x03) { sz = sz % 26; fputc(((char)('A' + sz)), stdout); } else { if(p1[i] == 0x02) { sz = sz % (sizeof(special_characters) - 1); fputc(special_characters[sz], stdout); } else { if(p1[i] == 0x01) { sz = sz % 10; fputc(((char)('0' + sz)), stdout); } else { sz = sz % 26; fputc(((char)('a' + sz)), stdout); } } } } fputc('\n', stdout); } /** Create and print passwords using the default algorithm. @param c Createp job. */ static void do_default DK_P1(CMD *,c) { unsigned char *p1; size_t *p2; unsigned char found; NAME *nptr; if(c->l_max > 0) { p1 = dk_new(unsigned char,(c->l_max)); if(p1) { p2 = dk_new(size_t,(c->l_max)); if(p2) { found = 0x00; dksto_it_reset(c->i_names); while((nptr = (NAME *)dksto_it_next(c->i_names)) != NULL) { found = 0x01; one_default(c, nptr->name, p1, p2); } if(!found) { one_default(c, NULL, p1, p2); } dk_delete(p2); } else { err_1(c, 0); c->exval = 1; } dk_delete(p1); } else { err_1(c, 0); c->exval = 1; } } else { err_1(c, 61); c->exval = 1; } } /** Create the passwords. @param c Createp job. */ static void create_the_passwords DK_P1(CMD *,c) { if(dkapp_rand_begin(c->a, c->rand_types_allowed)) { switch(c->program_mode) { case PROGRAM_MODE_SET: { do_set(c); } break; case PROGRAM_MODE_HEX: { do_hex(c); } break; case PROGRAM_MODE_ASCII85: { do_ascii85(c); } break; default: { do_default(c); } break; } if(!dkapp_rand_end(c->a)) { c->exval = 1; /* Failed to save seed file ..., reported by dkappr */ } } else { c->exval = 1; } } /** Apply corrections if length, number of digits, special and upper-case characters is inconsistent. @param c Createp job. */ static void correct_the_numbers DK_P1(CMD *,c) { size_t minval; switch(c->program_mode) { case PROGRAM_MODE_DEFAULT: { minval = c->d_max + c->s_max + c->u_max; if(c->l_min < minval) { c->l_min = minval; } if(c->l_max < c->l_min) { c->l_max = c->l_min; } } break; } } /** Run. Main has done the setup. @param c Createp job. */ static void run DK_P1(CMD *,c) { if(prepare_cmd(c)) { if(process_arguments(c)) { correct_the_numbers(c); c->exval = 0; /* no error yet */ if(c->program_action == ACTION_RUN) { create_the_passwords(c); } else { if((c->program_action) & (ACTION_HELP | ACTION_VERSION)) { print_version(c); if((c->program_action) & ACTION_HELP) { print_help(c); } } else { if((c->program_action) & (ACTION_CONFIGURE | ACTION_SHOWCONF)) { if((c->program_action) & ACTION_CONFIGURE) { save_configuration(c); } show_configuration(c); } else { if((c->program_action) & ACTION_UNCONFIGURE) { dkapp_unconfigure(c->a); } } } } } } cleanup_cmd(c); } /** Buffer to hold the output character set. */ static unsigned char char_set[256]; /** Buffer to store the password type name. */ static char b_type[256]; /** The createp programs main() function. @param argc Number of command line arguments. @param argv Command line arguments array. @return 0 on success, any other value indicates an error. */ #if DK_HAVE_PROTOTYPES int main(int argc, char *argv[]) #else int main(argc, argv) int argc; char *argv[]; #endif { int exval = 1; int rs = 0; int rf = 1; CMD cmd; char **xptr; #line 2513 "createp.ctr" silence_check(argc, argv, &rs, &rf); cmd_init(&cmd); cmd.cs_buffer = char_set; cmd.b_type = b_type; cmd.s_b_type = sizeof(b_type); b_type[0] = '\0'; cmd.a = dkapp_open_ext1(argc, argv, grname, etcdir, rs, rf); if(cmd.a) { cmd.msg = dkapp_find_key_value(cmd.a, kv, szkv, string_table_name); if(cmd.msg) { run(&cmd); xptr = cmd.msg; dk_delete(xptr); cmd.msg = NULL; exval = cmd.exval; } dkapp_close(cmd.a); cmd.a = NULL; } else { if(!rs) { fprintf( stderr, "createp: ERROR: Not enough memory!\n" ); fflush(stderr); } } #line 2538 "createp.ctr" exit(exval); return exval; } /* vim: set ai sw=2 foldopen=all : */