/* WARNING: This file was generated by dkct. Changes you make here will be lost if dkct is run again! You should modify the original source and run dkct on it. Original source: dk3appr.ctr */ /* Copyright (C) 2011-2017, Dirk Krause Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above opyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @file dk3appr.c The dk3appr module. */ #line 10 "dk3appr.ctr" #include "dk3all.h" #if DK3_HAVE_OPENSSL_RAND_H #include #endif #if DK3_ON_WINDOWS #include #endif #line 22 "dk3appr.ctr" /** Names for the PRNG types. */ static dkChar const * const dk3app_prng_type_names[] = { /* 0 */ dkT("openssl"), /* OpenSSL PRNG. */ /* 1 */ dkT("random"), /* initstate()/setstate()/random() */ /* 2 */ dkT("rand48"), /* lrand48(). */ /* 3 */ dkT("simple"), /* srand()/rand(). */ NULL }; int dk3app_get_allowed_prng_types(dk3_app_t *app, dkChar const *il) { int back = 0; dkChar buffer[256]; dkChar *p1 = NULL; dkChar *p2 = NULL; int i = 0; #line 44 "dk3appr.ctr" if((app) && (il)) { if(dk3str_len(il) < DK3_SIZEOF(buffer,dkChar)) { dk3str_cpy_not_overlapped(buffer, il); p1 = dk3str_start(buffer, NULL); while(p1) { p2 = dk3str_chr(p1, dkT(',')); if(p2) { *(p2++) = dkT('\0'); p2 = dk3str_start(p2, NULL); } i = dk3str_array_index(dk3app_prng_type_names, p1, 0); switch(i) { case 0: { #if DK3_HAVE_OPENSSL_RAND_H back |= DK3_PRNG_OPENSSL; #else /* ERROR: Openssl PRNG not available! */ dk3app_log_i1(app, DK3_LL_ERROR, 192); #endif } break; case 1: { #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM back |= DK3_PRNG_STATE; #else /* ERROR: initstate()/setstate()/random() not available. */ dk3app_log_i1(app, DK3_LL_ERROR, 191); #endif } break; case 2: { #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48 back |= DK3_PRNG_RAND48; #else /* ERROR: lrand48()/lrand48() not available. */ dk3app_log_i1(app, DK3_LL_ERROR, 190); #endif } break; case 3: { #if DK3_HAVE_RAND && DK3_HAVE_SRAND back |= DK3_PRNG_SIMPLE; #else /* ERROR: srand()/rand() not available! */ dk3app_log_i1(app, DK3_LL_ERROR, 189); #endif } break; default: { /* Unknown PRNG type name! */ dk3app_log_i3(app, DK3_LL_ERROR, 187, 188, p1); } break; } p1 = p2; } } else { /* ERROR: Line too long for buffer! */ dk3app_log_i1(app, DK3_LL_ERROR, 38); } } #line 99 "dk3appr.ctr" return back; } /** Find allowed PRNG types using preferences. @param app Application structure. @return Or-combination of DK3_PRNG_xxx. */ static int dk3app_rand_find_allowed_types(dk3_app_t *app) { int back = DK3_PRNG_ALL; dkChar buffer[256]; #line 115 "dk3appr.ctr" if(dk3app_get_pref( app,dk3app_not_localized(37),buffer,DK3_SIZEOF(buffer,dkChar)) ) { #line 119 "dk3appr.ctr" back = dk3app_get_allowed_prng_types(app, buffer); } #line 121 "dk3appr.ctr" return back; } /** Get bytes to seed random number generator. @param app Application structure. @param dp Destination buffer pointer. @param sz Number of bytes required. @param fn File name for seed file. @return Number of bytes found. */ static size_t dk3app_read_bytes_from_file( dk3_app_t *app, void *dp, size_t sz, dkChar const *fn ) { size_t back = 0; FILE *fipo; #line 145 "dk3appr.ctr" fipo = dk3sf_fopen_app(fn, dk3app_not_localized(36), app); if(fipo) { back = dk3sf_fread_app(dp, 1, sz, fipo, app); fclose(fipo); } #line 150 "dk3appr.ctr" return back; } /** Get bytes to seed random number generator. @param app Application structure. @param dp Destination buffer pointer. @param sz Number of bytes required. @param fn File name for seed file. @return Number of bytes found. */ static size_t dk3app_get_seed_from_source(dk3_app_t *app,void *dp,size_t sz,dkChar const *fn) { size_t back = 0; dk3_stat_t stb; int can_use_file = 1; int mode_denied; #line 172 "dk3appr.ctr" /* DEBUG: Attempting to get seed data from ... */ dk3app_log_i3(app, DK3_LL_DEBUG, 196, 197, fn); if(dk3sf_stat_app(&stb, fn, NULL)) { #line 175 "dk3appr.ctr" switch((stb.ft) & (~(DK3_FT_SYMLINK))) { case DK3_FT_DIRECTORY: { /* Ignore it. */ } break; case DK3_FT_REGULAR: { /* Security checks before using the file. */ mode_denied = DK3_FPERM_G_READ | DK3_FPERM_G_WRITE | DK3_FPERM_O_READ | DK3_FPERM_O_WRITE; if((stb.ft) & DK3_FT_SYMLINK) { if((stb.ai) & DK3_STAT_AI_USER_DIFFERS) { can_use_file = 0; /* WARNING: Symlink owner is not file owner. */ dk3app_log_i3(app, DK3_LL_ERROR, 185, 186, fn); } if((stb.perm) & mode_denied) { can_use_file = 0; /* WARNING: File not used (permissions). */ dk3app_log_i3(app, DK3_LL_ERROR, 183, 184, fn); } else { if((stb.lperm) & mode_denied) { can_use_file = 0; /* WARNING: File not used (permissions). */ dk3app_log_i3(app, DK3_LL_ERROR, 183, 184, fn); } } } else { if((stb.perm) & mode_denied) { can_use_file = 0; /* WARNING: File not used (permissions). */ dk3app_log_i3(app, DK3_LL_ERROR, 183, 184, fn); } } if(can_use_file) { back = dk3app_read_bytes_from_file(app, dp, sz, fn); } } break; default: { /* Use file. */ back = dk3app_read_bytes_from_file(app, dp, sz, fn); } break; } } #line 219 "dk3appr.ctr" /* DEBUG: Seed data: ... bytes. */ { char b1[64]; dkChar b2[64]; sprintf(b1, "%lu", (unsigned long)back); if(dk3str_cnv_c8_to_str_app(b2, DK3_SIZEOF(b2,dkChar), b1, app)) { dk3app_log_i3(app, DK3_LL_DEBUG, 198, 199, b2); } } return back; } /** Get bytes to seed random number generator. @param app Application structure. @param dp Destination buffer pointer. @param sz Number of bytes required. @param fn File name for seed file. @param passno Pass number (only 0 uses files). @return Number of bytes found. */ static size_t dk3app_get_seed_bytes( dk3_app_t *app, void *dp, size_t sz, dkChar const *fn, int passno ) { size_t back = 0; dkChar const *p1; dkChar const *p2; dkChar const *p3; dkChar const *p4; dkChar const *p5; dkChar *p6; size_t s; dkChar fnb[DK3_MAX_PATH]; /* File name buffer. */ if((app) && (dp) && (sz)) { /* $HOME/.rnd-xxx-application */ if(passno == 0) { if(dk3app_get_pref_bool(app, dk3app_not_localized(46), 1)) { p1 = dk3app_get_homedir(app); p2 = dk3app_not_localized(20); p3 = fn; p4 = dk3app_not_localized(5); p5 = dk3app_get_appname(app); if((p1) && (p2) && (p3) && (p4) && (p5)) { s = dk3str_len(p1); s += dk3str_len(p2); s += dk3str_len(p3); s += dk3str_len(p4); s += dk3str_len(p5); if(s < DK3_SIZEOF(fnb,dkChar)) { dk3str_cpy_not_overlapped(fnb, p1); dk3str_cat(fnb, p2); dk3str_cat(fnb, p3); dk3str_cat(fnb, p4); dk3str_cat(fnb, p5); back = dk3app_get_seed_from_source(app, dp, sz, fnb); } } } } /* EGD socket from environment. */ if(back == 0) { p1 = dk3sf_getenv(dk3app_not_localized(43)); if(p1) { back = dk3app_get_seed_from_source(app, dp, sz, p1); } } /* EGD socket from preferences. */ if(back == 0) { if(dk3app_get_pref( app, dk3app_not_localized(42), fnb, DK3_SIZEOF(fnb,dkChar)) ) { p6 = dk3str_start(fnb, NULL); if(p6) { dk3str_chomp(p6, NULL); back = dk3app_get_seed_from_source(app, dp, sz, p6); } } } #if !DK3_ON_WINDOWS /* /dev/urandom */ if(back == 0) { back = dk3app_get_seed_from_source(app, dp, sz, dk3app_not_localized(44)); } /* /dev/random */ if(back == 0) { back = dk3app_get_seed_from_source(app, dp, sz, dk3app_not_localized(45)); } #endif } return back; } #if DK3_HAVE_OPENSSL_RAND_H /** Initialize OpenSSL PRNG. @param app Application structure. @return 1 on success, 0 on error. */ static int dk3app_init_prng_openssl(dk3_app_t *app) { int back = 0; int cc = 0; int passno = 0; size_t sz; char seedval[DK3_SEED_OPENSSL_BYTES]; #if DK3_ON_WINDOWS BYTE sv[DK3_SEED_OPENSSL_BYTES]; HCRYPTPROV hcp; BOOL res; DWORD dwLgt; #endif #line 343 "dk3appr.ctr" do { cc = 0; sz = dk3app_get_seed_bytes( app,seedval,sizeof(seedval),dk3app_not_localized(41),passno ); #line 349 "dk3appr.ctr" if(sz > 0) { cc = 1; RAND_seed(seedval, (int)sz); if(RAND_status() == 1) { cc = 0; back = 1; } } #if DK3_ON_WINDOWS if(back == 0) { #line 358 "dk3appr.ctr" dk3app_log_i1(app, DK3_LL_DEBUG, 227); res = CryptAcquireContext( &hcp, /* Pointer to result variable. */ NULL, /* Default container (user name). */ NULL, /* Users default cryptographic provider. */ PROV_RSA_FULL, /* Provider type. */ CRYPT_VERIFYCONTEXT ); if(res) { #line 367 "dk3appr.ctr" dwLgt = sizeof(sv); res = CryptGenRandom(hcp, dwLgt, sv); if(res) { #line 370 "dk3appr.ctr" cc = 1; RAND_seed(sv, sizeof(sv)); if(RAND_status() == 1) { cc = 0; back = 1; #line 374 "dk3appr.ctr" } } else { #line 376 "dk3appr.ctr" } CryptReleaseContext(hcp, (DWORD)0L); } else { #line 379 "dk3appr.ctr" } } if(back == 0) { #line 382 "dk3appr.ctr" dk3app_log_i1(app, DK3_LL_DEBUG, 228); RAND_screen(); if(RAND_status() == 1) { cc = 0; back = 1; #line 386 "dk3appr.ctr" } } #endif passno++; } while(cc); if(back) { dk3app_log_i1(app, DK3_LL_DEBUG, 229); } else { /* Warning: Failed to seed OpenSSL PRNG! */ dk3app_log_i1(app, DK3_LL_ERROR, 182); } #line 397 "dk3appr.ctr" return back; } #endif #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM /** Initialize state PRNG. @param app Application structure. @return 1 on success, 0 on error. */ static int dk3app_init_prng_state(dk3_app_t *app) { int back = 0; unsigned int seedval = 0; if(dk3app_get_seed_bytes( app, (void *)(&seedval), sizeof(unsigned int), dk3app_not_localized(40), 0 ) ) { srandom(seedval); back = 1; } if(!back) { /* Warning: Failed to seed random() PRNG! */ dk3app_log_i1(app, DK3_LL_ERROR, 181); } return back; } #endif #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48 /** Initialize lrand48() PRNG. @param app Application structure. @return 1 on success, 0 on error. */ static int dk3app_init_prng_rand48(dk3_app_t *app) { int back = 0; long int seedval = 0L; if(dk3app_get_seed_bytes( app, (void *)(&seedval), sizeof(long int), dk3app_not_localized(39), 0 ) ) { srand48(seedval); back = 1; } if(!back) { /*Warning: Failed to seed lrand48() PRNG! */ dk3app_log_i1(app, DK3_LL_ERROR, 180); } return back; } #endif #if DK3_HAVE_RAND && DK3_HAVE_SRAND /** Initialize simple rand() PRNG. @param app Application structure. @return 1 on success, 0 on error. */ static int dk3app_init_prng_simple(dk3_app_t *app) { int back = 0; unsigned int ui; if( dk3app_get_seed_bytes( app, (void *)(&ui), sizeof(unsigned int), dk3app_not_localized(38), 0 ) ) { srand(ui); back = 1; } if(!back) { /* Warning: Failed to seed simple PRNG! */ dk3app_log_i1(app, DK3_LL_ERROR, 179); } return back; } #endif /** Attempt to initialize a PRNG. @param app Application structure. @param il Input line listing allowed PRNGs comma-separated. @return 1 on success (at least one PRNG usable), 0 on error. */ int dk3app_rand_init(dk3_app_t *app, dkChar const *il) { int back = 0; int allowed_types; #line 496 "dk3appr.ctr" if(app) { if(app->f_rand_initialized) { back = app->f_rand_success; } else { app->f_rand_initialized = 1; if(il) { allowed_types = dk3app_get_allowed_prng_types(app, il); } else { allowed_types = dk3app_rand_find_allowed_types(app); } if(!back) { if(allowed_types & DK3_PRNG_OPENSSL) { #line 508 "dk3appr.ctr" #if DK3_HAVE_OPENSSL_RAND_H #line 510 "dk3appr.ctr" back = dk3app_init_prng_openssl(app); if(back) { #line 512 "dk3appr.ctr" app->rand_type = DK3_PRNG_OPENSSL; } #else #line 516 "dk3appr.ctr" #endif } } if(!back) { if(allowed_types & DK3_PRNG_STATE) { #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM back = dk3app_init_prng_state(app); if(back) { app->rand_type = DK3_PRNG_STATE; } #endif } } if(!back) { if(allowed_types & DK3_PRNG_RAND48) { #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48 back = dk3app_init_prng_rand48(app); if(back) { app->rand_type = DK3_PRNG_RAND48; } #endif } } if(!back) { if(allowed_types & DK3_PRNG_SIMPLE) { #if DK3_HAVE_RAND && DK3_HAVE_SRAND back = dk3app_init_prng_simple(app); if(back) { app->rand_type = DK3_PRNG_SIMPLE; } #endif } } if(back) { app->f_rand_success = 1; } } } if(!back) { /* ERROR: No PRNG usable! */ dk3app_log_i1(app, DK3_LL_ERROR, 178); } #line 558 "dk3appr.ctr" return back; } /** Get random bytes. @param app Application structure. @param db Destination buffer. @param sz Size of \a db (number of bytes). @param f_crypto Flag: For cryptographic purposes. @return Number of bytes written to \a db. */ static size_t dk3app_rand_bytes_internal(dk3_app_t *app, void *db, size_t sz, int f_crypto) { size_t back = 0; unsigned char *ucptr = NULL; size_t i = 0; unsigned u = 0; if((app) && (db) && (sz)) { ucptr = (unsigned char *)db; if(!(app->f_rand_initialized)) { dk3app_rand_init(app, NULL); } if(app->f_rand_success) { switch(app->rand_type) { case DK3_PRNG_OPENSSL: { #if DK3_HAVE_OPENSSL_RAND_H if(f_crypto) { if(RAND_bytes(ucptr, (int)sz) == 1) { back = sz; } } else { if(RAND_pseudo_bytes(ucptr, (int)sz) > -1) { back = sz; } } #else /* BUG: Not available! */ #endif } break; case DK3_PRNG_STATE: { #if DK3_HAVE_INITSTATE && DK3_HAVE_SETSTATE && DK3_HAVE_RANDOM long lval; size_t position; lval = random() >> 8; position = 0; for(i = 0; i < sz; i++) { *(ucptr++) = (unsigned char)(lval & 0x000000FFL); position++; lval = lval >> 8; if(position >= (sizeof(long) - 1)) { lval = random() >> 8; position = 0; } } back = sz; #else /* BUG: Not available! */ #endif } break; case DK3_PRNG_RAND48: { #if DK3_HAVE_NRAND48 && DK3_HAVE_LRAND48 long lval; size_t position; lval = lrand48() >> 8; position = 0; for(i = 0; i < sz; i++) { *(ucptr++) = (unsigned char)(lval & 0x000000FFL); position++; lval = lval >> 8; if(position >= (sizeof(long) - 1)) { lval = lrand48() >> 8; position = 0; } } back = sz; #else /* BUG: Not available! */ #endif } break; default: { #if DK3_HAVE_RAND && DK3_HAVE_SRAND for(i = 0; i < sz; i++) { u = rand(); #if DK3_SIZEOF_INT > 2 #if DK3_SIZEOF_INT > 4 u = u >> 28; #else u = u >> 12; #endif #else u = u >> 4; #endif u &= 0x00FFU; *(ucptr++) = (unsigned char)u; } back = sz; #else /* BUG: Not available! */ #endif } break; } } } if(back < sz) { /* ERROR: Failed to obtain enough random bytes! */ dk3app_log_i1(app, DK3_LL_ERROR, 177); } return back; } size_t dk3app_rand_bytes(dk3_app_t *app, void *db, size_t sz) { size_t back; back = dk3app_rand_bytes_internal(app, db, sz, 1); return back; } size_t dk3app_rand_bytes_non_crypto(dk3_app_t *app, void *db, size_t sz) { size_t back; back = dk3app_rand_bytes_internal(app, db, sz, 0); return back; } void dk3app_rand_end(dk3_app_t *app) { #if DK3_HAVE_OPENSSL_RAND_H #if DK3_CHAR_SIZE == 1 dkChar const *p1 = NULL; dkChar const *p2 = NULL; dkChar const *p3 = NULL; dkChar const *p4 = NULL; dkChar const *p5 = NULL; size_t sz = 0; FILE *fipo = NULL; dkChar fnb[DK3_MAX_PATH]; #endif #endif #line 709 "dk3appr.ctr" if((app->f_rand_initialized) && (app->f_rand_success)) { #line 710 "dk3appr.ctr" switch(app->rand_type) { case DK3_PRNG_OPENSSL: { #if DK3_HAVE_OPENSSL_RAND_H #if DK3_CHAR_SIZE == 1 p1 = dk3app_get_homedir(app); p2 = dk3app_not_localized(20); p3 = dk3app_not_localized(41); p4 = dk3app_not_localized(5); p5 = dk3app_get_appname(app); if((p1) && (p2) && (p3) && (p4) && (p5)) { sz = dk3str_len(p1); sz += dk3str_len(p2); sz += dk3str_len(p3); sz += dk3str_len(p4); sz += dk3str_len(p5); if(sz < DK3_SIZEOF(fnb,dkChar)) { dk3str_cpy_not_overlapped(fnb, p1); dk3str_cat(fnb, p2); dk3str_cat(fnb, p3); dk3str_cat(fnb, p4); dk3str_cat(fnb, p5); #line 731 "dk3appr.ctr" fipo = dk3sf_fopen_app(fnb, dk3app_not_localized(24), app); if(fipo) { fclose(fipo); fipo = NULL; #if DK3_ON_WINDOWS /* chmod(fnb, 0600); */ #else #if DK3_HAVE_CHMOD chmod(fnb, 0600); #endif #endif if(RAND_write_file(fnb) <= 0) { /* Warning: Failed to save random seed. */ dk3app_log_i1(app, DK3_LL_ERROR, 193); } } } } #endif #endif } break; } } else { #line 753 "dk3appr.ctr" } #line 754 "dk3appr.ctr" } /* vim: set ai sw=2 : */