%% 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 #define WINDOWS_H_INCLUDED 1 #endif #ifndef WINCRYPT_H_INCLUDED #include #define WINCRYPT_H_INCLUDED 1 #endif #endif #if DK4_HAVE_UNISTD_H #ifndef UNISTD_H_INCLUDED #include #define UNISTD_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SYS_TYPES_H #ifndef SYS_TYPES_H_INCLUDED #include #define SYS_TYPES_H_INCLUDED 1 #endif #endif #if DK4_HAVE_SIGNAL_H #ifndef SIGNAL_H_INCLUDED #include #define SIGNAL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_PROCESS_H #ifndef PROCESS_H_INCLUDED #include #define PROCESS_H_INCLUDED 1 #endif #endif #if DK4_HAVE_IO_H #ifndef IO_H_INCLUDED #include #define IO_H_INCLUDED 1 #endif #endif #if DK4_HAVE_FCNTL_H #ifndef FCNTL_H_INCLUDED #include #define FCNTL_H_INCLUDED 1 #endif #endif #if DK4_HAVE_OPENSSL_RAND_H #ifndef OPENSSL_RAND_H_INCLUDED #include #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: -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 --length= Length, i.e. ``8-10''. -u --upper-case= Number of uppercase chars in passwords. -d --digits= Number of digits in passwords. -s --special= 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; }