diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/dktools/dk-pwgen.ctr |
Initial commit
Diffstat (limited to 'support/dktools/dk-pwgen.ctr')
-rw-r--r-- | support/dktools/dk-pwgen.ctr | 2056 |
1 files changed, 2056 insertions, 0 deletions
diff --git a/support/dktools/dk-pwgen.ctr b/support/dktools/dk-pwgen.ctr new file mode 100644 index 0000000000..c9e1e0dc7a --- /dev/null +++ b/support/dktools/dk-pwgen.ctr @@ -0,0 +1,2056 @@ +%% options + +copyright owner = Dirk Krause +copyright year = 2015-xxxx +license = bsd + + + +%% module + + +#include "dk4conf.h" + +#if DK4_ON_WINDOWS +/** Allow use of the getenv() function. */ +#define _CRT_SECURE_NO_WARNINGS 1 +#endif + +#if DK4_ON_WINDOWS +#ifndef WINDOWS_H_INCLUDED +#include <windows.h> +#define WINDOWS_H_INCLUDED 1 +#endif +#ifndef WINCRYPT_H_INCLUDED +#include <wincrypt.h> +#define WINCRYPT_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_UNISTD_H +#ifndef UNISTD_H_INCLUDED +#include <unistd.h> +#define UNISTD_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_SYS_TYPES_H +#ifndef SYS_TYPES_H_INCLUDED +#include <sys/types.h> +#define SYS_TYPES_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_SIGNAL_H +#ifndef SIGNAL_H_INCLUDED +#include <signal.h> +#define SIGNAL_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_PROCESS_H +#ifndef PROCESS_H_INCLUDED +#include <process.h> +#define PROCESS_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_IO_H +#ifndef IO_H_INCLUDED +#include <io.h> +#define IO_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_FCNTL_H +#ifndef FCNTL_H_INCLUDED +#include <fcntl.h> +#define FCNTL_H_INCLUDED 1 +#endif +#endif + +#if DK4_HAVE_OPENSSL_RAND_H +#ifndef OPENSSL_RAND_H_INCLUDED +#include <openssl/rand.h> +#define OPENSSL_RAND_H_INCLUDED 1 +#endif +#endif + +#include "dk4types.h" +#include "dk4const.h" +#include "dk4mem.h" +#include "dk4mema.h" +#include "dk4memrs.h" +#include "dk4strd.h" +#include "dk4app.h" +#include "dk4aopt.h" +#include "dk4fput.h" +#include "dk4vers.h" +#include "dk4maiddsz.h" +#include "dk4maasz.h" +#include "dk4mpl.h" +#include "dk4svbufa.h" + + + +$!trace-include + + + +/** Output mode. +*/ +enum { + /** Create normal user password. + */ + DK_PWGEN_MODE_NORMAL = 0 , + + /** Create hard password. + */ + DK_PWGEN_MODE_HARD , + + /** Create binary data. + */ + DK_PWGEN_MODE_BINARY , + + /** Create hexadecimal key, use + lower case a to f. + */ + DK_PWGEN_MODE_HEX_LOWER , + + /** Create hexadecimal key, use + upper case A to F. + */ + DK_PWGEN_MODE_HEX_UPPER , + + /** Create numeric PIN. + */ + DK_PWGEN_MODE_PIN +}; + + +/** Constant texts used by program, not localized. +*/ +static const dkChar * const dk_pwgen_kwnl[] = { +$!string-table macro=dkT +# +# 0 Program group name +# +dktools +# +# 1 Help text name +# +dk-pwgen.txt +# +# 2 String table name +# +dk-pwgen.str +# +# 3 4 5 Characters for hexadecimal output and PIN output +# +0123456789abcdef +0123456789ABCDEF +0123456789 +# +# 6 Special characters +# +# -_.:,;<>|#'+*~@^°!"§$%&/()=?`{[]} +-_.:,;<>|#'+*~@^!"$%&/()=?`{[]} +# +# 7 EGD socket preference name +# +rand.egd.name +# +# 8 Long option name for verbose mode. +# +verbose +$!end +}; + + + +static const dkChar * const dk_pwgen_help_text[] = { +$!text macro=dkT,preprocessor + +Generate passwords, PINs and hexadecimal keys + +dk-pwgen [<options>] + +Options: +-h --hard Create hard password instead of normal. +-b --binary Create binary random data + (not on Windows). +-p --pin Create PIN number. +-x --hex Create hexadecimal key, use `a'...`f'. +-X --Hex Create hexadecimal key, use `A'...`F'. +-l <range> --length=<range> Length, i.e. ``8-10''. +-u <range> --upper-case=<range> Number of uppercase chars in passwords. +-d <range> --digits=<range> Number of digits in passwords. +-s <range> --special=<range> Number of special chars in passwords. +-n --no-newline Suppress newline after output. + --verbose Show error message on SIGPIPE. + + --help Show this short help text. + --manual *** SHOW FULL MANUAL. *** + --version Show version information. + --license Show license information. + +http://dktools.sourceforge.net + +$!end +}; + + + +static const dkChar * const dk_pwgen_license_text[] = { +$!text macro=dkT,preprocessor +This software uses code from the following projects, either directly or as +a library: + +dktools Dirk Krause's tools and libraries. + See http://dktools.sourceforge.net/ for more information. +#if DK4_HAVE_ZLIB_H + +zlib Data compression library. + See http://www.zlib.net/ for more information. +#endif +#if DK4_HAVE_BZLIB_H + +bzip2 Data compression program and library. + See http://www.bzip.org/ for more information. +#endif +#if DK4_HAVE_OPENSSL_RAND_H + +OpenSSL Cryptographic toolkit, used to build file checksums here. + See http://www.openssl.org/ for more information. + +This product includes software developed by the OpenSSL Project for use in +the OpenSSL Toolkit (http://www.openssl.org/). +This product includes cryptographic software written by +Eric Young (eay@cryptsoft.com). +This product includes software written by Tim Hudson (tjh@cryptsoft.com). +#endif + +All the licenses below apply to the program. +Licenses for used libraries are shown as found on my Scientific Linux 6.x +computer in the /usr/share/doc directory on 2015-04-01. Check the project +homepages of the used libraries for additional information and/or updated +license terms. + + +DK tools and libraries license +============================== +Copyright (c) 2015-2016, 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 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 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. +#if DK4_HAVE_ZLIB_H + + +Zlib license +============ +(C) 1995-2004 Jean-loup Gailly and Mark Adler + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +Jean-loup Gailly Mark Adler +jloup@gzip.org madler@alumni.caltech.edu +#endif +#if DK4_HAVE_BZLIB_H + + +Bzip2 and libbzip2 library license +================================== +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2007 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + +Julian Seward, jseward@bzip.org +bzip2/libbzip2 version 1.0.5 of 10 December 2007 +#endif +#if DK4_HAVE_OPENSSL_RAND_H + + +OpenSSL license +=============== + +LICENSE ISSUES +-------------- + +The OpenSSL toolkit stays under a dual license, i.e. both the conditions of +the OpenSSL License and the original SSLeay license apply to the toolkit. +See below for the actual license texts. Actually both licenses are BSD-style +Open Source licenses. In case of any license issues related to OpenSSL +please contact openssl-core@openssl.org. + +OpenSSL License +--------------- + +Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. 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. + +3. All advertising materials mentioning features or use of this + software must display the following acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + +4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + endorse or promote products derived from this software without + prior written permission. For written permission, please contact + openssl-core@openssl.org. + +5. Products derived from this software may not be called "OpenSSL" + nor may "OpenSSL" appear in their names without prior written + permission of the OpenSSL Project. + +6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes software developed by the OpenSSL Project + for use in the OpenSSL Toolkit (http://www.openssl.org/)" + +THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY +EXPRESSED 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 OpenSSL PROJECT OR +ITS 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. + +This product includes cryptographic software written by Eric Young +(eay@cryptsoft.com). This product includes software written by Tim +Hudson (tjh@cryptsoft.com). + + +Original SSLeay License +----------------------- + +Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) +All rights reserved. + +This package is an SSL implementation written +by Eric Young (eay@cryptsoft.com). +The implementation was written so as to conform with Netscapes SSL. + +This library is free for commercial and non-commercial use as long as +the following conditions are aheared to. The following conditions +apply to all code found in this distribution, be it the RC4, RSA, +lhash, DES, etc., code; not just the SSL code. The SSL documentation +included with this distribution is covered by the same copyright terms +except that the holder is Tim Hudson (tjh@cryptsoft.com). + +Copyright remains Eric Young's, and as such any Copyright notices in +the code are not to be removed. +If this package is used in a product, Eric Young should be given attribution +as the author of the parts of the library used. +This can be in the form of a textual message at program startup or +in documentation (online or textual) provided with the package. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the copyright + notice, this list of conditions and the following disclaimer. +2. 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. +3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + "This product includes cryptographic software written by + Eric Young (eay@cryptsoft.com)" + The word 'cryptographic' can be left out if the rouines from the library + being used are not cryptographic related :-). +4. If you include any Windows specific code (or a derivative thereof) from + the apps directory (application code) you must include an acknowledgement: + "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + +THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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. + +The licence and distribution terms for any publically available version or +derivative of this code cannot be changed. i.e. this code cannot simply be +copied and put under another distribution licence +[including the GNU Public Licence.] + +#endif + +$!end +}; + + + +static const dkChar * const dk_pwgen_kw_def[] = { +$!string-table macro=dkT +# +# 0 Error: OpenSSL PRNG not available! +# +OpenSSL PRNG not available! +# +# 1 Error: Failed to set up signal handlers! +# +Failed to set up signal handlers! +# +# 2 Error: Failed to restore signal handlers! +# +Failed to restore signal handlers! +# +# 3 Error: Numeric overflow while reading a size number! +# +Numeric overflow while reading a size number! +# +# 4 5 Error: Not a size specification: "..."! +# +Not a size specification: " +"! +# +# 6 7 Error: Failed to retrieve size from text: "..."! +# +Failed to retrieve size from text: " +"! +# +# 8 Error: Options -h, -x, -X, and -p are mutually exclusive! +# +Options -h, -x, -X, and -p are mutually exclusive! +# +# 9 10 11 Error: Option -u ignored for this output type! +# +Option -u ignored for this output type! +Option -d ignored for this output type! +Option -s ignored for this output type! +# +# 12 Error: Illegal range combination for -l, -u, -d, -s! +# +Conflicting ranges for -l and -u/-d/-s! +# +# 13 Error: Numeric overflow in password length calculation! +# +Numeric overflow in password length calculation! +# +# 14 Error: Failed to obtain random data from cryptographic context! +# +Failed to obtain random data from cryptographic context! +# +# 15 Error: Failed to acquire cryptographic context! +# +Failed to acquire cryptographic context! +# +# 16 Error: Failed to open /dev/random and /dev/urandom devices! +# +Failed to open /dev/random and /dev/urandom devices! +# +# 17 Error: Failed to obtain random data! +# +Failed to obtain random data! +# +# 18 Error: Failed to seed OpenSSL PRNG! +# +Failed to seed OpenSSL PRNG! +# +# 19 20 21 Error: Aborted by SIGTERM signal! +# +Aborted by SIGTERM signal! +Aborted by SIGINT signal! +Aborted by SIGPIPE signal! +# +# 22 Error: Write attempt to standard output failed! +# +Write attempt to standard output failed! +# +# 23 Debug: Seeding PRNG using OpenSSL builtin functions. +# +Seeding PRNG using OpenSSL builtin functions. +# +# 24 Debug: Seeding PRNG from EGD socket. +# +Seeding PRNG from EGD socket. +# +# 25 Debug: Seeding PRNG from Windows cryptographic context. +# +Seeding PRNG from Windows cryptographic context. +# +# 26 Debug: Seeding PRNG from screen contents. +# +Seeding PRNG from screen contents. +# +# 27 Debug: Seeding PRNG from /dev/random or /dev/urandom device. +# +Seeding PRNG from /dev/random or /dev/urandom device. +# +# 28 Debug: Seeding PRNG from EGD socket specified by preference. +# +Seeding PRNG from EGD socket specified by preference. +# +# 29 ERROR: Options -b, -h, -x, -X, and -p are mutually exclusive! +# +Options -b, -h, -x, -X, and -p are mutually exclusive! +# +# 30 ERROR: Failed to reset used memory! +# +Failed to reset used memory! +# +# 31 ERROR: The -b option is not supported on Windows! +# +The -b option is not supported on Windows! +$!end +}; + + + +/** Options understood by program. +*/ +static const dk4_option_specification_t dk_pwgen_options[] = { + { dkT('h'), dkT("hard"), DK4_OPT_ARG_NONE }, + { dkT('b'), dkT("binary"), DK4_OPT_ARG_NONE }, + { dkT('x'), dkT("hex"), DK4_OPT_ARG_NONE }, + { dkT('X'), dkT("Hex"), DK4_OPT_ARG_NONE }, + { dkT('p'), dkT("pin"), DK4_OPT_ARG_NONE }, + { dkT('l'), dkT("length"), DK4_OPT_ARG_STRING }, + { dkT('u'), dkT("upper-case"), DK4_OPT_ARG_STRING }, + { dkT('d'), dkT("digits"), DK4_OPT_ARG_STRING }, + { dkT('s'), dkT("special"), DK4_OPT_ARG_STRING }, + { dkT('n'), dkT("no-newline"), DK4_OPT_ARG_NONE }, + { dkT('\0'), dkT("verbose"), DK4_OPT_ARG_NONE } +}; + + + +#ifndef BUFSIZ +#define BUFSIZ 8192 +#endif + + +/** Use an explicitly specified buffer for stdout operations + so we can securely reset the memory before exiting. +*/ +static char stdout_buffer[BUFSIZ]; + + + +/** Use an explicitly specified buffer when reading seed file + so we can securely reset the memory before exiting. +*/ +static char seed_file_buf[BUFSIZ]; + + + +/** Localized version if available, otherwise default texts. +*/ +static const dkChar * const *dk_pwgen_msg = dk_pwgen_kw_def; + + + +/** Application structure. +*/ +static dk4_app_t *app = NULL; + + + +/** Number of elements in dk_pwgen_msg array. +*/ +static size_t dk_pwgen_sz_msg = +sizeof(dk_pwgen_kw_def)/sizeof(DK4_PCDKCHAR) - 1; + + +/** Number of elements in dk_pwgen_options array. +*/ +static const size_t dk_pwgen_sz_options = +sizeof(dk_pwgen_options)/sizeof(dk4_option_specification_t); + + + +/** Minimum output length. +*/ +static size_t length_min = 8; + + + +/** Maximum output length. +*/ +static size_t length_max = 10; + + + +/** Output length to produce. +*/ +static size_t length = 8; + + + +/** Minimum number of upper case characters. +*/ +static size_t upper_min = 1; + + + +/** Maximum number of upper case characters. +*/ +static size_t upper_max = 2; + + + +/** Number of upper case characters to produce. +*/ +static size_t upper = 1; + + + +/** Minimum number of digits. +*/ +static size_t digit_min = 1; + + + +/** Maximum number of digits. +*/ +static size_t digit_max = 2; + + + +/** Number of digits to produce. +*/ +static size_t digits = 1; + + + +/** Minimum number of special characters. +*/ +static size_t special_min = 1; + + + +/** Maximum number of special characters. +*/ +static size_t special_max = 2; + + + +/** Number of special characters to produce. +*/ +static size_t specials = 1; + + + +/** Flag: Errors occured while writing to stdout. +*/ +static int output_error = 0; + + + +/** Flag: Verbose output (report SIGPIPE). +*/ +static int verbose = 1; + + + +/** Exit status code. +*/ +static int exval = EXIT_FAILURE; + + + +/** Output type to produce. +*/ +static int output_type = DK_PWGEN_MODE_NORMAL; + + + +#if DK4_HAVE_OPENSSL_RAND_H + + + +#ifdef SIGPIPE +/** Indicator: SIGPIPE signal received. +*/ +static +DK4_VOLATILE +dk4_sig_atomic_t sig_had_pipe = 0; +#endif + +/** Indicator: SIGINT signal received. +*/ +static +DK4_VOLATILE +dk4_sig_atomic_t sig_had_int = 0; + +/** Indicator: SIGTERM signal received. +*/ +static +DK4_VOLATILE +dk4_sig_atomic_t sig_had_term = 0; + + + +/** Pass a volatile pointer to an atomic integer. + This function is necessary as some compilers mis-optimize + direct access to volatile variables (at least if you believe + one of the coding standards). + @param ptr Address of atomic integer variable. + @return The unmodified pointer. +*/ +static +DK4_VOLATILE +dk4_sig_atomic_t * +sig_pass_pointer(DK4_VOLATILE dk4_sig_atomic_t *ptr) +{ + return ptr; +} + + + +#ifdef SIGPIPE +/** Handler for SIGPIPE signal. + @param signo Signal number (always SIGPIPE, ignored). +*/ +static +void +sig_handler_pipe(int signo) +{ + *sig_pass_pointer(&sig_had_pipe) = 1; +} +#endif + +/** Handler for SIGINT signal. + @param signo Signal number (always SIGINT, ignored). +*/ +static +void +sig_handler_int(int signo) +{ + *sig_pass_pointer(&sig_had_int) = 1; +} + +/** Handler for SIGTERM signal. + @param signo Signal number (always SIGTERM, ignored). +*/ +static +void +sig_handler_term(int signo) +{ + *sig_pass_pointer(&sig_had_term) = 1; +} + +/** Read value from volatile atomic type. + This function is necessary as some compilers mis-optimize + direct access to volatile variables (at least if you believe + one of the coding standards). + @param ap Pointer to volatile atomic variable. + @return Contents of the variable. +*/ +static +dk4_sig_atomic_t +sig_read_atomic(DK4_VOLATILE dk4_sig_atomic_t *ap) +{ + return (*ap); +} + +/** Check whether we can continue or if a signal was received. + @param check_pipe Flag: Check for occured SIGPIPE signal too. + @return 1 if the program can continue, 0 if a signal was received. +*/ +static +int +sig_can_continue(int check_pipe) +{ + int back = 1; +#ifdef SIGPIPE + if (0 != check_pipe) { + if (0 != sig_read_atomic(&sig_had_pipe)) { back = 0; } + } +#endif + if (0 != sig_read_atomic(&sig_had_int )) { back = 0; } + if (0 != sig_read_atomic(&sig_had_term)) { back = 0; } + return back; +} + + + +/** Check whether we can continue. + @return 1 for yes, 0 for no. +*/ +static +int +dk_pwgen_can_continue(void) +{ + int back = 1; + if (0 == sig_can_continue(1)) { + back = 0; + } + return back; +} + + + +/** Read range from text to size_t variables. + @param minptr Address of minimum variable. + @param maxptr Address of maximum variable. + @param buf Buffer containing the text. + @return 1 on success, 0 on error. +*/ +static +int +dk_pwgen_opt_range(size_t *minptr, size_t *maxptr, dkChar option) +{ + dkChar buf[32*sizeof(dk4_um_t)]; + dk4_er_t er; + const dkChar *endptr; + dkChar *p1; + size_t val; + int res; + int rdf = 0; + int back = 0; + int passno = 0; + $? "+ dk_pwgen_opt_range" + if (0 != dk4app_opt_is_set_long(app, dk_pwgen_kwnl[8], NULL)) { + verbose = 1; + } + if (0 != dk4app_opt_is_set_short(app, option, NULL)) { + res = dk4app_opt_get_string_short( + buf, DK4_SIZEOF(buf,dkChar), app, option, NULL + ); + if (0 != res) { $? ". opt args ok" + p1 = dk4str_chr(buf, dkT('-')); + if (NULL != p1) { $? ". minimum and maximum" + *(p1++) = dkT('\0'); + p1 = dk4str_start(p1, NULL); + } else { $? ". just value" + } + val = 0; + endptr = NULL; + dk4error_init(&er); + if (0 != dk4ma_input_dk_dec_size_t(&val, buf, &endptr, 1, &er)) { + *minptr = val; + *maxptr = val; + back = 1; + if (NULL != p1) { $? ". retrieve maximum" + passno = 1; + back = 0; + val = 0; + endptr = NULL; + if (0 != dk4ma_input_dk_dec_size_t(&val, p1, &endptr, 1, &er)) { + *maxptr = val; + back = 1; + if (*maxptr < *minptr) { + val = *maxptr; + *maxptr = *minptr; + *minptr = val; + } + } else { $? "! failed to retrieve value" + /* ERROR: Failed to read size */ + rdf = 1; + } + } + } else { $? "! failed to read value" + /* ERROR: Failed to read size */ + rdf = 1; + } + } else { $? "! bug, failed to retrieve opt args" + /* ERROR: Failed to obtain option argument, probably bug */ + } + } else { $? ". option not set" + back = 1; + } + if ((0 == back) && (0 != rdf)) { + switch (er.ec) { + case DK4_E_MATH_OVERFLOW : { $? "! overflow" + /* ERROR: Numeric overflow while reading number */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 3); + } break; + case DK4_E_SYNTAX : { $? "! syntax" + /* ERROR: Not a size specification */ + dk4app_log_3( + app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 4, 5, + ((0 == passno) ? buf : p1) + ); + } break; + default: { $? "! other problem" + /* ERROR: Failed to read size */ + dk4app_log_3( + app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 6, 7, + ((0 == passno) ? buf : p1) + ); + } break; + } + } $? "- dk_pwgen_opt_range %u %u %d", (unsigned)(*minptr), (unsigned)(*maxptr), back + return back; +} + + + +/** Process command line options. + @return 1 on success, 0 on error (invalid option combination). +*/ +static +int +dk_pwgen_check_options(void) +{ + dk4_er_t er; + size_t val; + int back = 0; + $? "+ dk_pwgen_check_options" + + if (0 != dk4app_opt_is_set_short(app, dkT('b'), NULL)) { + output_type = DK_PWGEN_MODE_BINARY; + if ( + (0 != dk4app_opt_is_set_short(app, dkT('h'), NULL)) + || (0 != dk4app_opt_is_set_short(app, dkT('x'), NULL)) + || (0 != dk4app_opt_is_set_short(app, dkT('X'), NULL)) + || (0 != dk4app_opt_is_set_short(app, dkT('p'), NULL)) + ) + { + /* ERROR: Options -b, -h, -x, -X and -p are mutually exclusive! */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 29); + goto finished; + } + else + { + back = 1; + } + } else { + if (0 != dk4app_opt_is_set_short(app, dkT('h'), NULL)) { + output_type = DK_PWGEN_MODE_HARD; + if ( + (0 != dk4app_opt_is_set_short(app, dkT('x'), NULL)) + || (0 != dk4app_opt_is_set_short(app, dkT('X'), NULL)) + || (0 != dk4app_opt_is_set_short(app, dkT('p'), NULL)) + ) + { + /* ERROR: Options -h, -x, -X and -p are mutually exclusive! */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 8); + goto finished; + } + else + { + back = 1; + } + } else { + if (0 != dk4app_opt_is_set_short(app, dkT('x'), NULL)) { + output_type = DK_PWGEN_MODE_HEX_LOWER; + if ( + (0 != dk4app_opt_is_set_short(app, dkT('X'), NULL)) + || (0 != dk4app_opt_is_set_short(app, dkT('p'), NULL)) + ) + { + /* ERROR: Options -h, -x, -X and -p are mutually exclusive! */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 8); + goto finished; + } + else + { + back = 1; + } + } else { + if (0 != dk4app_opt_is_set_short(app, dkT('X'), NULL)) { + output_type = DK_PWGEN_MODE_HEX_UPPER; + if (0 != dk4app_opt_is_set_short(app, dkT('p'), NULL)) { + /* ERROR: Options -h, -x, -X and -p are mutually exclusive! */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 8); + goto finished; + } else { + back = 1; + } + } else { + if (0 != dk4app_opt_is_set_short(app, dkT('p'), NULL)) { + output_type = DK_PWGEN_MODE_PIN; + } + back = 1; + } + } + } + } + if (1 == back) { + if (0 == dk_pwgen_opt_range(&length_min, &length_max, dkT('l'))) { + back = 0; + } + if (1 == back) { + switch (output_type) { + case DK_PWGEN_MODE_HARD : + case DK_PWGEN_MODE_HEX_LOWER : + case DK_PWGEN_MODE_HEX_UPPER : + case DK_PWGEN_MODE_PIN : + { + if (0 != dk4app_opt_is_set_short(app, dkT('u'), NULL)) { + /* WARNING: Option ignored */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 9); + } + if (0 != dk4app_opt_is_set_short(app, dkT('d'), NULL)) { + /* WARNING: Option ignored */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 10); + } + if (0 != dk4app_opt_is_set_short(app, dkT('s'), NULL)) { + /* WARNING: Option ignored */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 11); + } + } break; + default : { + if (0 != dk_pwgen_opt_range(&upper_min, &upper_max, dkT('u'))) { + if (0 != dk_pwgen_opt_range(&digit_min, &digit_max, dkT('d'))) { + if (0 != dk_pwgen_opt_range(&special_min, &special_max, dkT('s'))) + { + dk4error_init(&er); + val = dk4ma_size_t_add(upper_max, digit_max, &er); + val = dk4ma_size_t_add(val, special_max, &er); + if (DK4_E_NONE == er.ec) { + if (val > length_min) { + back = 0; + /* ERROR: Illegal range combination */ + dk4app_log_1( + app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 12 + ); + } + } else { + /* ERROR: Numeric overflow in size calculation */ + dk4app_log_1( + app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 13 + ); + } + } else { + back = 0; + } + } else { + back = 0; + } + } else { + back = 0; + } + } break; + } + } + } + finished: + $? "- dk_pwgen_check_options %d", back + return back; +} + + + +/** Seed PRNG. + @return 1 on success, 0 on error (not enough seed data). +*/ +static +int +dk_pwgen_seed_prng(void) +{ +#if DK4_CHAR_SIZE == 1 + dkChar snb[DK4_MAX_PATH]; +#endif + char buffer[64]; + char *envptr; +#if DK4_ON_WINDOWS + HCRYPTPROV hcp; + BOOL res; +#else + FILE *fipo; + size_t rdb; +#endif + int cc; + int rounds = 0; + int back = 0; + int svbres = 0; + $? "+ dk_pwgen_seed_prng" + + /* Let OpenSSL library functions try to initialize. + */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_DEBUG, 23); + if (1 == RAND_status()) { + back = 1; + goto finished; + } + +#if DK4_HAVE_RAND_EGD && DK4_HAVE_STRUCT_SOCKADDR_UN + /* Attempt EGD socket if specified in environment. + */ + envptr = getenv("EGDSOCKET"); + if (NULL != envptr) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_DEBUG, 24); + if (0 < RAND_egd(envptr)) { + if (1 == RAND_status()) { + back = 1; + goto finished; + } + } + } + + /* Attempt EGD socket defined by preference. + The RAND_egd() function accepts char, not dkChar. + */ +#if DK4_CHAR_SIZE == 1 + if (0 != dk4app_pref_get(snb,DK4_SIZEOF(snb,dkChar),app,dk_pwgen_kwnl[7],0)) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_DEBUG, 28); + if (0 < RAND_egd(snb)) { + if (1 == RAND_status()) { + back = 1; + goto finished; + } + } + } +#endif +#endif + + /* Use platform specific mechanisms if available. + */ +#if DK4_ON_WINDOWS + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_DEBUG, 25); + res = CryptAcquireContext( + &hcp, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT + ); + if (res) { + cc = 1; + do { + if (0 != dk_pwgen_can_continue()) { + res = CryptGenRandom(hcp, (DWORD)sizeof(buffer), buffer); + if (res) { + RAND_seed(buffer, sizeof(buffer)); + if (1 == RAND_status()) { + cc = 0; + back = 1; + } else { + rounds++; + } + } else { + cc = -1; + /* ERROR: Failed to obtain random bytes from crypto context */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 14); + } + } else { + cc = -1; + } + } while ((1 == cc) && (128 > rounds)); + CryptReleaseContext(hcp, (DWORD)0UL); + dk4mem_reset_secure(buffer, sizeof(buffer), NULL); + if (0 == back) { + if (0 != dk_pwgen_can_continue()) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_DEBUG, 25); + RAND_screen(); + if (1 == RAND_status()) { + back = 1; + } + } + } + } else { + /* ERROR: Failed to acquire crypto context */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 15); + } +#else + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_DEBUG, 27); + fipo = fopen("/dev/random", "rb"); + if (NULL == fipo) { + fipo = fopen("/dev/urandom", "rb"); + } + if (NULL != fipo) { + dk4mem_reset(seed_file_buf, sizeof(seed_file_buf), NULL); + svbres = dk4setvbuf( + fipo, DK4_FILE_FULL_BUFFERING, seed_file_buf, sizeof(seed_file_buf), NULL + ); + if (0 != svbres) { + cc = 1; + do { + if (0 != dk_pwgen_can_continue()) { + rdb = fread(buffer, 1, sizeof(buffer), fipo); + if (0 < rdb) { + RAND_seed(buffer, rdb); + if (1 == RAND_status()) { + cc = 0; + back = 1; + } else { + rounds++; + } + } else { + cc = -1; + } + } else { + cc = -1; + } + } while ((1 == cc) && (128 > rounds)); + } else { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 16); + } + fclose(fipo); + dk4mem_reset_secure(seed_file_buf, sizeof(seed_file_buf), NULL); + dk4mem_reset_secure(buffer, sizeof(buffer), NULL); + } else { + /* ERROR: Failed to open both /dev/random and /dev/urandom */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 16); + } +#endif + + finished: + $? "- dk_pwgen_seed_prng %d", back + return back; +} + + + +/** Find a random number in a given range. + @param dptr Address of destination variable. + @param min Minimum value. + @param max Maximum value. + @return 1 on success, 0 on error. +*/ +static +int +dk_pwgen_value_in_range(size_t *dptr, size_t min, size_t max) +{ + size_t width; + size_t rval; + int back = 0; + $? "+ dk_pwgen_value_in_range %u %u", (unsigned)min, (unsigned)max + if (max > min) { + width = max - min; + if (0 != (width + 1)) { width++ ; } + if (0 < RAND_bytes((unsigned char *)(&rval), (int)sizeof(rval))) { + $? ". rval = %u width = %u", (unsigned)rval, (unsigned)width + *dptr = min + (rval % width); + back = 1; + } else { + /* ERROR: Failed to obtain random bytes */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 17); + } + } else { + *dptr = min; + back = 1; + } + $? "- dk_pwgen_value_in_range %d %u", back, (unsigned)(*dptr) + return back; +} + + + +/** Create hexadecimal key and write to standard output. + @param upper Flag: Use upper case `a' to `f'. +*/ +static +void +dk_pwgen_output_hex(int upper) +{ + unsigned char buf[8]; /* Buffer for 8 random bytes */ + size_t i; /* Index of current output character */ + size_t bi; /* Index in buffer 0 to 7 */ + size_t j; /* Index in hexademical digits string */ + int cc; /* Flag: Can continue 1=yes,0=no,-1=abort */ + dkChar dc; /* Current character to write */ + $? "+ dk_pwgen_output_hex upper=%d", upper + cc = 1; + i = 0; + bi = 0; + do { + if (0 != dk_pwgen_can_continue()) { + if (i < length) { + + + + if (0 == (i % 16)) { + bi = 0; + if (0 < RAND_bytes(buf, (int)sizeof(buf))) { + cc = 1; + } else { + cc = -1; + exval = EXIT_FAILURE; + /* ERROR: Random */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 17); + } + } + if (1 == cc) { + j = (size_t)(buf[bi / 2]); + j = 0x00FFU & j; + if (0 == (i % 2)) { + j = j >> 4; + } + j &= 0x000FU; + dc = (dk_pwgen_kwnl[(0 != upper) ? 4 : 3])[j]; + if (0 == dk4fputc(dc, stdout, NULL)) { output_error = 1; cc = -1; } + } + i++; bi++; + } else { + cc = 0; + } + } else { + cc = -1; + } + } while (1 == cc); + if (0 == dk4mem_reset_secure(buf, sizeof(buf), NULL)) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 30); + exval = EXIT_FAILURE; + } + dc = dkT('\0'); j = 0; + if ((0 != j) || (dkT('\0') != dc)) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 30); + exval = EXIT_FAILURE; + } + $? "- dk_pwgen_output_hex" +} + + + +/** Create hard password and write to standard output. +*/ +static +void +dk_pwgen_output_hard(void) +{ + dk4_um_t val; + size_t i; + int cc; + dkChar dc; + + i = 0; cc = 1; + do { + if (0 != dk_pwgen_can_continue()) { + if (i < length) { + if (0 < RAND_bytes((unsigned char *)(&val), (int)sizeof(dk4_um_t))) { + dc = (dkChar)33 + (dkChar)(val % (dk4_um_t)90U); + if (0 == dk4fputc(dc, stdout, NULL)) { + output_error = 1; + cc = -1; + } + } else { + cc = -1; + exval = EXIT_FAILURE; + /* ERROR: Random */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 17); + } + i++; + } else { + cc = 0; + } + } else { + cc = -1; + } + } while (1 == cc); + val = (dk4_um_t)0UL; dc = dkT('\0'); + if ((val != (dk4_um_t)0UL) || (dc != dkT('\0'))) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 30); + exval = EXIT_FAILURE; + } +} + + + +/** Create binary password and write to standard output. +*/ +static +void +dk_pwgen_output_binary(void) +{ +#if !DK4_ON_WINDOWS + char buf[256]; + size_t i; + size_t remaining; + size_t wrb; + int cc; +#endif + +#if DK4_ON_WINDOWS + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 31); + exval = EXIT_FAILURE; +#else + remaining = length; + cc = 1; + do { + if (0 != dk_pwgen_can_continue()) { + i = sizeof(buf); + if (remaining < i) { i = remaining; } + if (0 == i) { + cc = 0; + } else { + if (0 < RAND_bytes((unsigned char *)buf, (int)i)) { + wrb = fwrite(buf, 1, i, stdout); + if (i == wrb) { + if (i >= remaining) { + cc = 0; + } else { + remaining = remaining - i; + } + } else { + cc = -1; + exval = EXIT_FAILURE; + output_error = 1; + } + } else { + cc = -1; + exval = EXIT_FAILURE; + /* ERROR: Random */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 17); + } + } + } else { + cc = -1; + } + } while ((1 == cc) && (0 < remaining)); + if (0 != fflush(stdout)) { + exval = EXIT_FAILURE; + output_error = 1; + } + if (0 == dk4mem_reset_secure(buf, sizeof(buf), NULL)) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 30); + exval = EXIT_FAILURE; + } +#endif +} + + +/** Create numeric PIN and write to standard output. +*/ +static +void +dk_pwgen_output_pin(void) +{ + dk4_um_t val; + size_t i; + int cc; + dkChar dc; + + i = 0; cc = 1; + do { + if (0 != dk_pwgen_can_continue()) { + if (i < length) { + if (0 < RAND_bytes((unsigned char *)(&val), (int)sizeof(dk4_um_t))) { + dc = dkT('0') + (dkChar)(val % (dk4_um_t)10U); + if (0 == dk4fputc(dc, stdout, NULL)) { + output_error = 1; + cc = -1; + } + } else { + cc = -1; + exval = EXIT_FAILURE; + /* ERROR: Random */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 17); + } + i++; + } else { + cc = 0; + } + } else { + cc = -1; + } + } while (1 == cc); + dc = dkT('\0'); + if (dc != dkT('\0')) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 30); + exval = EXIT_FAILURE; + } +} + + + +/** Create normal password and write to standard output. +*/ +static +void +dk_pwgen_output_normal(void) +{ + char *ti = NULL; /* Cells */ + dk4_um_t val; /* Value */ + size_t avail; /* Number of unused cells */ + size_t curel; /* Current element within group */ + size_t ind_to_set; /* Index of unused cell to set */ + size_t i; /* Traverse all cells */ + size_t max; /* Number of elements within pass */ + size_t speclen; /* Length of string containing special */ + int passno; /* Current pass */ + int cc; /* Flag: No error yet, can continue */ + int res; /* Operation result */ + dkChar dc; /* Character to write */ + char ic; /* Indicator character */ + + ti = dk4mem_new_app(char,length,app); + if (NULL != ti) { $? ". ti" + DK4_MEMRES(ti, length); + cc = 1; + if (0 == dk_pwgen_value_in_range(&upper, upper_min, upper_max)) { + cc = 0; + } + if (0 == dk_pwgen_value_in_range(&digits, digit_min, digit_max)) { + cc = 0; + } + if (0 == dk_pwgen_value_in_range(&specials, special_min, special_max)) { + cc = 0; + } + if (1 == cc) { + passno = 0; + avail = length; + while (3 > passno) { $? ". pass %d", passno + switch (passno) { + case 2 : { + max = specials; + ic = 's'; + } break; + case 1 : { + max = digits; + ic = 'd'; + } break; + default : { + max = upper; + ic = 'u'; + } break; + } + curel = 0; + while (curel < max) { + $? ". element %u / %u", (unsigned)curel, (unsigned)max + if (0 != dk_pwgen_can_continue()) { + res = RAND_bytes( + (unsigned char *)(&ind_to_set), (int)sizeof(size_t) + ); + if (0 < res) { + if (0 < avail) { + ind_to_set = ind_to_set % avail; + $? ". use free cell %u", (unsigned)ind_to_set + res = 0; + i = 0; + while (i < length) { + $? ". check cell %u", (unsigned)i + if ('\0' == ti[i]) { + if (0 == ind_to_set) { + $? ". use cell %u", (unsigned)i + res = 1; + ti[i] = ic; + i = length - 1; + avail--; + } else { + ind_to_set--; + } + } else { $? ". cell %u = %!8c", (unsigned)i, ti[i] + } + i++; + } + curel++; + if (0 == res) { $? "! no free cell found" + /* No free cell found */ + curel = max; passno = 3; cc = 0; + dk4app_log_1( + app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 12 + ); + } + } else { + /* No more cells available */ + curel = max; passno = 3; cc = 0; + dk4app_log_1( + app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 12 + ); + } + } else { + /* ERROR: Random data */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 17); + curel = max; passno = 3; cc = 0; + } + } else { + curel = max; passno = 3; cc = 0; + } + } + passno++; + if (0 == dk_pwgen_can_continue()) { passno = 3; } + } + if ((1 == cc) && (0 != dk_pwgen_can_continue())) { $? ". create output" + i = 0; + speclen = dk4str_len(dk_pwgen_kwnl[6]); + $? ". kw = \"%!ds\" speclen = %u", dk_pwgen_kwnl[6], (unsigned)speclen + while (i < length) { + $? ". i = %u", (unsigned)i + if (0 != dk_pwgen_can_continue()) { + res = RAND_bytes( + (unsigned char *)(&val), (int)sizeof(dk4_um_t) + ); + if (0 < res) { + $? ". val = %ju", val + switch (ti[i]) { + case 's': { + val = val % (dk4_um_t)speclen; + $? ". val = %ju", val + dc = (dk_pwgen_kwnl[6])[(size_t)val]; + } break; + case 'd': { + val = val % (dk4_um_t)10UL; + dc = dkT('0') + (dkChar)val; + } break; + case 'u': { + val = val % (dk4_um_t)26UL; + dc = dkT('A') + (dkChar)val; + } break; + default: { + val = val % (dk4_um_t)26UL; + dc = dkT('a') + (dkChar)val; + } break; + } + if (0 == dk4fputc(dc, stdout, NULL)) { + output_error = 1; + } + i++; + } else { + i = length; + exval = EXIT_FAILURE; + /* ERROR: Random */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 17); + } + } else { + i = length; + } + } + } else { + exval = EXIT_FAILURE; + } + } else { + exval = EXIT_FAILURE; + /* Failed to obtain random */ + } + if (0 == dk4mem_reset_secure(ti, length, NULL)) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 30); + exval = EXIT_FAILURE; + } + dk4mem_free(ti); + dc = dkT('\0'); + if (dc != dkT('\0')) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 30); + exval = EXIT_FAILURE; + } + } else { $? "! ti" + exval = EXIT_FAILURE; + /* ERROR: Memory, already reported */ + } +} + + + +/** Create password, PIN or key and write to output. +*/ +static +void +dk_pwgen_produce_output(void) +{ + $? "+ dk_pwgen_produce_output" + if (0 != dk_pwgen_value_in_range(&length, length_min, length_max)) { + exval = EXIT_SUCCESS; + switch (output_type) { + case DK_PWGEN_MODE_BINARY : { $? ". binary" + dk_pwgen_output_binary(); + } break; + case DK_PWGEN_MODE_HARD : { $? ". hard" + dk_pwgen_output_hard(); + } break; + case DK_PWGEN_MODE_HEX_LOWER : { $? ". hex lower" + dk_pwgen_output_hex(0); + } break; + case DK_PWGEN_MODE_HEX_UPPER : { $? ". hex upper" + dk_pwgen_output_hex(1); + } break; + case DK_PWGEN_MODE_PIN : { $? ". pin" + dk_pwgen_output_pin(); + } break; + default : { $? ". normal" + dk_pwgen_output_normal(); + } break; + } + if (0 == dk4app_opt_is_set_short(app, dkT('n'), NULL)) { + if (DK_PWGEN_MODE_BINARY != output_type) { + if (0 == dk4fputc(dkT('\n'), stdout, NULL)) { + output_error = 1; + } + } + } + } + $? "- dk_pwgen_produce_output" +} + + + +/** Run normally with signal handlers installed. +*/ +static +void +dk_pwgen_normal_run(void) +{ + $? "+ dk_pwgen_normal_run" + if (0 < dk_pwgen_check_options()) { + if (0 < dk_pwgen_seed_prng()) { + dk_pwgen_produce_output(); + } else { + /* ERROR: Failed to seed PRNG */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 18); + } + RAND_cleanup(); + } + $? "- dk_pwgen_normal_run" +} + + + + +#if DK4_HAVE_SIGACTION +/** Set signal handlers and run. +*/ +static +void +dk_pwgen_run_with_signal_handlers(void) +{ +#ifdef SIGPIPE + struct sigaction opipe; +#endif + struct sigaction oint; +#ifdef SIGPIPE + struct sigaction npipe; +#endif + struct sigaction nint; + struct sigaction oterm; + struct sigaction nterm; + int success = 0; + +#ifdef SIGPIPE + /* Set up signal handling for SIGPIPE. + */ + DK4_MEMRES(&npipe, sizeof(npipe)); + npipe.sa_handler = sig_handler_pipe; + npipe.sa_flags = 0; + if (0 != sigemptyset(&npipe.sa_mask)) { + /* ERROR: Failed to set up masked signal set for SIGPIPE */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 1); + goto finished; + } + if (0 != sigaddset(&npipe.sa_mask, SIGPIPE)) { + /* ERROR: Failed to set up masked signal set for SIGPIPE */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 1); + goto finished; + } + if (0 != sigaction(SIGPIPE, &npipe, &opipe)) { + /* ERROR: Failed to set up signal handler for SIGPIPE */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 1); + goto finished; + } +#endif + + /* Set up signal handling for SIGINT. + */ + DK4_MEMRES(&nint, sizeof(nint)); + nint.sa_handler = sig_handler_int; + nint.sa_flags = 0; + if (0 != sigemptyset(&nint.sa_mask)) { + /* ERROR: Failed to set up masked signal set for SIGINT */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 1); + goto restore_old_pipe; + } + if (0 != sigaddset(&nint.sa_mask, SIGINT)) { + /* ERROR: Failed to set up masked signal set for SIGINT */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 1); + goto restore_old_pipe; + } + if (0 != sigaction(SIGINT, &nint, &oint)) { + /* ERROR: Failed to set up signal handler for SIGINT */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 1); + goto restore_old_pipe; + } + + /* Set up signal handling for SIGTERM + */ + DK4_MEMRES(&nterm, sizeof(nterm)); + nterm.sa_handler = sig_handler_term; + nterm.sa_flags = 0; + if (0 != sigemptyset(&nterm.sa_mask)) { + /* ERROR: Failed to set up masked signal set for SIGTERM */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 1); + goto restore_old_int; + } + if (0 != sigaddset(&nterm.sa_mask, SIGTERM)) { + /* ERROR: Failed to set up masked signal set for SIGTERM */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 1); + goto restore_old_int; + } + if (0 != sigaction(SIGTERM, &nterm, &oterm)) { + /* ERROR: Failed to set up signal handler for SIGTERM */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 1); + goto restore_old_int; + } + + success = 1; + dk_pwgen_normal_run(); + + /* Restore signal handling for SIGTERM. + */ + if (0 != sigaction(SIGTERM, &oterm, NULL)) { + /* ERROR: Failed to restore old SIGTERM settings */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 2); + success = 0; + } + + /* Restore signal handling for SIGINT. + */ + restore_old_int: + if (0 != sigaction(SIGINT, &oint, NULL)) { + /* ERROR: Failed to restore old SIGPIPE settings */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 2); + success = 0; + } + +#ifdef SIGPIPE + /* Restore signal handling for SIGPIPE. + */ + restore_old_pipe: + if (0 != sigaction(SIGPIPE, &opipe, NULL)) { + /* ERROR: Failed to restore old SIGPIPE settings */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 2); + success = 0; + } +#endif + + /* Set exit status code if error occured. + */ + finished: + if (0 == success) { exval = EXIT_FAILURE; } +} +#else +#if DK4_HAVE_SIGSET +/** Set signal handlers and run. +*/ +static +void +dk_pwgen_run_with_signal_handlers(void) +{ +#ifdef SIGPIPE + dk4_sig_handler_t *oldpipe = NULL; +#endif + dk4_sig_handler_t *oldint = NULL; + dk4_sig_handler_t *oldterm = NULL; + +#ifdef SIGPIPE + oldpipe = sigset(SIGPIPE, sig_handler_pipe); +#endif + oldint = sigset(SIGINT, sig_handler_int); + oldterm = sigset(SIGTERM, sig_handler_term); + dk_pwgen_normal_run(); + sigset(SIGTERM, oldterm); + sigset(SIGINT, oldint); +#ifdef SIGPIPE + sigset(SIGPIPE, oldpipe); +#endif +} +#else +#if DK4_HAVE_SIGNAL +/** Set signal handlers and run. +*/ +static +void +dk_pwgen_run_with_signal_handlers(void) +{ +#ifdef SIGPIPE + dk4_sig_handler_t *oldpipe = NULL; +#endif + dk4_sig_handler_t *oldint = NULL; + dk4_sig_handler_t *oldterm = NULL; + +#ifdef SIGPIPE + oldpipe = signal(SIGPIPE, sig_handler_pipe); +#endif + oldint = signal(SIGINT, sig_handler_int); + oldterm = signal(SIGTERM, sig_handler_term); + dk_pwgen_normal_run(); + signal(SIGTERM, oldterm); + signal(SIGINT, oldint); +#ifdef SIGPIPE + signal(SIGPIPE, oldpipe); +#endif +} +#else +/** Set signal handlers and run. +*/ +static +void +dk_pwgen_run_with_signal_handlers(void) +{ + dk_pwgen_normal_run(); +} +#endif +#endif +#endif + +#endif +/* if DK4_HAVE_OPENSSL_RAND_H */ + + + +/** Main function. + @param argc Number of command line arguments. + @param argv Command line arguments array. + @return 0 on success, all other values indicate errors. +*/ +#if DK4_CHAR_SIZE > 1 +int wmain(int argc, wchar_t *argv[]) +#else +int main(int argc, char *argv[]) +#endif +{ + int shp; + int pbso; /* Flag: Private buffer used for stdout */ + + pbso = dk4setvbuf( + stdout, DK4_FILE_LINE_BUFFERING, stdout_buffer, sizeof(stdout_buffer), NULL + ); + $!trace-init dk-pwgen.deb + $? "+ main" + dk4fput_initialize_stdout(); + dk4fput_initialize_stderr(); + app = dk4app_open_cmd( + argc, argv, dk_pwgen_options, dk_pwgen_sz_options, + dk_pwgen_kwnl[0], DKT_VERSION_DK, + dk_pwgen_kwnl[1], dk_pwgen_help_text, dk_pwgen_license_text + ); + if (NULL != app) { + dk_pwgen_sz_msg = dk4app_string_table_size(dk_pwgen_kw_def); + dk_pwgen_msg = dk4app_string_table(app,dk_pwgen_kwnl[2],dk_pwgen_kw_def); + if (0 != dk4app_can_run_normally(app)) { +#if DK4_HAVE_OPENSSL_RAND_H + /* + Run. + */ + dk_pwgen_run_with_signal_handlers(); + /* + Report signals and output errors, if any. + */ + if (0 != sig_read_atomic(&sig_had_term)) { + /* ERROR: SIGTERM signal received */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 19); + exval = EXIT_FAILURE; + } + if (0 != sig_read_atomic(&sig_had_int )) { + /* ERROR: SIGINT signal received */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 20); + exval = EXIT_FAILURE; + } +#ifdef SIGPIPE + if (0 != sig_read_atomic(&sig_had_pipe)) { + /* ERROR: SIGPIPE signal received */ + if (0 != verbose) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 21); + } + exval = EXIT_FAILURE; + shp = 1; + } else { + shp = 0; + } +#else + shp = 0; +#endif + if ((0 == shp) && (0 != output_error)) { + /* ERROR: Failed to write to stdout */ + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 22); + exval = EXIT_FAILURE; + } +#else + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 0); +#endif + if (0 == pbso) { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 30); + exval = EXIT_FAILURE; + } else { +#ifdef BUFSIZ + fflush(stdout); + if (0 == dk4mem_reset_secure(stdout_buffer,sizeof(stdout_buffer),NULL)) + { + dk4app_log_1(app, dk_pwgen_msg, dk_pwgen_sz_msg, DK4_LL_ERROR, 30); + exval = EXIT_FAILURE; + } +#endif + } + } else { + if (0 != dk4app_help_version_license(app)) { + exval = EXIT_SUCCESS; + } + } + dk4app_close(app); + } else { + } + fflush(stdout); + fflush(stderr); + dk4fput_cleanup_stderr(); + dk4fput_cleanup_stdout(); + $? "- main %d", exval + $!trace-end + exit(exval); return exval; +} + |