mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Restructured the RNG source and add support for loadable
random modules.
This commit is contained in:
parent
710d2e351b
commit
2e494682b6
@ -1,6 +1,19 @@
|
||||
Wed Nov 25 12:33:41 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* rand-*.c: Removed.
|
||||
* rndlinux.c : New.
|
||||
* rndunix.c : New.
|
||||
* random.c : Restructured the interface to the gather modules.
|
||||
(intialize): Call constructor functions
|
||||
(read_radnom_source): Moved to here.
|
||||
* dynload.c (dynload_getfnc_gather_random): New.
|
||||
(dynload_getfnc_fast_random_poll): New.
|
||||
(register_internal_cipher_extension): New.
|
||||
(register_cipher_extension): Support of internal modules.
|
||||
|
||||
Sun Nov 8 17:44:36 1998 Werner Koch (wk@isil.d.shuttle.de)
|
||||
|
||||
* radn-unix.c (read_random_source): Removed the assert.
|
||||
* rand-unix.c (read_random_source): Removed the assert.
|
||||
|
||||
Mon Oct 19 18:34:30 1998 me,,, (wk@tobold)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
gnupg_extensions = tiger twofish
|
||||
gnupg_extensions = tiger twofish rndunix
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
|
||||
|
||||
@ -11,7 +11,7 @@ else
|
||||
pkglib_PROGRAMS =
|
||||
endif
|
||||
|
||||
DYNLINK_MOD_CFLAGS = @DYNLINK_MOD_CFLAGS@
|
||||
DYNLINK_MOD_CFLAGS = -DIS_MODULE @DYNLINK_MOD_CFLAGS@
|
||||
|
||||
|
||||
libcipher_a_SOURCES = cipher.c \
|
||||
@ -33,9 +33,7 @@ libcipher_a_SOURCES = cipher.c \
|
||||
random.h \
|
||||
random.c \
|
||||
rand-internal.h \
|
||||
rand-unix.c \
|
||||
rand-w32.c \
|
||||
rand-dummy.c \
|
||||
rndlinux.c \
|
||||
rmd.h \
|
||||
rmd160.c \
|
||||
sha1.h \
|
||||
@ -58,6 +56,11 @@ twofish: $(srcdir)/twofish.c
|
||||
sed -e 's/-O[0-9]*/ /' `
|
||||
|
||||
|
||||
rndunix: $(srcdir)/rndunix.c
|
||||
$(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndunix $(srcdir)/rndunix.c
|
||||
|
||||
|
||||
|
||||
install-exec-hook:
|
||||
@list='$(pkglib_PROGRAMS)'; for p in $$list; do \
|
||||
if test -f $(pkglibdir)/$$p; then \
|
||||
|
@ -39,6 +39,7 @@
|
||||
|
||||
typedef struct ext_list {
|
||||
struct ext_list *next;
|
||||
int internal;
|
||||
#ifdef HAVE_DL_DLOPEN
|
||||
void *handle; /* handle from dlopen() */
|
||||
#else
|
||||
@ -83,7 +84,7 @@ static int dld_available;
|
||||
void
|
||||
register_cipher_extension( const char *mainpgm, const char *fname )
|
||||
{
|
||||
EXTLIST r, el;
|
||||
EXTLIST r, el, intex;
|
||||
char *p, *pe;
|
||||
|
||||
#ifdef HAVE_DLD_DLD_LINK
|
||||
@ -114,13 +115,53 @@ register_cipher_extension( const char *mainpgm, const char *fname )
|
||||
el->hintstr = NULL;
|
||||
|
||||
/* check that it is not already registered */
|
||||
for(r = extensions; r; r = r->next )
|
||||
intex = NULL;
|
||||
for(r = extensions; r; r = r->next ) {
|
||||
if( !compare_filenames(r->name, el->name) ) {
|
||||
log_info("extension '%s' already registered\n", el->name );
|
||||
m_free(el);
|
||||
return;
|
||||
}
|
||||
else if( r->internal )
|
||||
intex = r;
|
||||
}
|
||||
/* and register */
|
||||
/* we put them after the internal extension modules */
|
||||
/* this is so that the external modules do not get loaded */
|
||||
/* as soon as the internal modules are requested */
|
||||
if( intex ) {
|
||||
el->next = intex->next;
|
||||
intex->next = el;
|
||||
}
|
||||
else {
|
||||
el->next = extensions;
|
||||
extensions = el;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
register_internal_cipher_extension(
|
||||
const char *module_id,
|
||||
void * (*enumfunc)(int, int*, int*, int*)
|
||||
)
|
||||
{
|
||||
EXTLIST r, el;
|
||||
|
||||
el = m_alloc_clear( sizeof *el + strlen(module_id) );
|
||||
strcpy(el->name, module_id );
|
||||
el->internal = 1;
|
||||
|
||||
/* check that it is not already registered */
|
||||
for(r = extensions; r; r = r->next ) {
|
||||
if( !compare_filenames(r->name, el->name) ) {
|
||||
log_info("extension '%s' already registered\n", el->name );
|
||||
m_free(el);
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* and register */
|
||||
el->enumfunc = enumfunc;
|
||||
el->handle = (void*)1;
|
||||
el->next = extensions;
|
||||
extensions = el;
|
||||
}
|
||||
@ -455,3 +496,51 @@ enum_gnupgext_pubkeys( void **enum_context, int *algo,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int (*
|
||||
dynload_getfnc_gather_random())(byte*, size_t*, int)
|
||||
{
|
||||
EXTLIST r;
|
||||
void *sym;
|
||||
|
||||
for( r = extensions; r; r = r->next ) {
|
||||
int seq, class, vers;
|
||||
|
||||
if( r->failed )
|
||||
continue;
|
||||
if( !r->handle && load_extension(r) )
|
||||
continue;
|
||||
seq = 0;
|
||||
while( (sym = (*r->enumfunc)(40, &seq, &class, &vers)) ) {
|
||||
if( vers != 1 || class != 40 )
|
||||
continue;
|
||||
return (int (*)(byte*, size_t*, int))sym;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void (*
|
||||
dynload_getfnc_fast_random_poll())( void (*)(const void*, size_t, int))
|
||||
{
|
||||
EXTLIST r;
|
||||
void *sym;
|
||||
|
||||
for( r = extensions; r; r = r->next ) {
|
||||
int seq, class, vers;
|
||||
|
||||
if( r->failed )
|
||||
continue;
|
||||
if( !r->handle && load_extension(r) )
|
||||
continue;
|
||||
seq = 0;
|
||||
while( (sym = (*r->enumfunc)(41, &seq, &class, &vers)) ) {
|
||||
if( vers != 1 || class != 41 )
|
||||
continue;
|
||||
return (void (*)( void (*)(const void*, size_t, int)))sym;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,10 @@
|
||||
#ifndef G10_CIPHER_DYNLOAD_H
|
||||
#define G10_CIPHER_DYNLOAD_H
|
||||
|
||||
|
||||
void register_internal_cipher_extension( const char *module_id,
|
||||
void * (*enumfunc)(int, int*, int*, int*) );
|
||||
|
||||
int
|
||||
enum_gnupgext_digests( void **enum_context,
|
||||
int *algo,
|
||||
@ -49,4 +53,10 @@ enum_gnupgext_pubkeys( void **enum_context, int *algo,
|
||||
int (*cmp)(void *, MPI), void *opaquev ),
|
||||
unsigned (**get_nbits)( int algo, MPI *pkey ) );
|
||||
|
||||
|
||||
int (*dynload_getfnc_gather_random(void))(byte*, size_t*, int);
|
||||
void (*dynload_getfnc_fast_random_poll(void)
|
||||
)( void (*)(const void*, size_t, int));
|
||||
|
||||
|
||||
#endif /*G10_CIPHER_DYNLOAD_H*/
|
||||
|
@ -1,134 +0,0 @@
|
||||
/* rand-dummy.c - INSECURE dummy random device
|
||||
* Copyright (C) 1998 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNUPG.
|
||||
*
|
||||
* GNUPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GNUPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_GETHRTIME
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETRUSAGE
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#ifdef __MINGW32__
|
||||
#include <process.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include "util.h"
|
||||
#include "ttyio.h"
|
||||
#include "i18n.h"
|
||||
#include "rand-internal.h"
|
||||
#ifdef USE_RAND_DUMMY /* a dummy random file so we can do some tests */
|
||||
|
||||
|
||||
#ifndef RAND_MAX /* for SunOS */
|
||||
#define RAND_MAX 32767
|
||||
#endif
|
||||
|
||||
#if __GNUC__
|
||||
#warning Using the insecure dummy random device
|
||||
#endif
|
||||
|
||||
void
|
||||
random_poll()
|
||||
{
|
||||
char buf[POOLSIZE/5];
|
||||
read_random_source( buf, POOLSIZE/5, 1 ); /* read dummy data */
|
||||
add_randomness( buf, POOLSIZE/5, 2);
|
||||
memset( buf, 0, POOLSIZE/5);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fast_random_poll()
|
||||
{
|
||||
#if HAVE_GETHRTIME
|
||||
{ hrtime_t tv;
|
||||
tv = gethrtime();
|
||||
add_randomness( &tv, sizeof(tv), 1 );
|
||||
}
|
||||
#elif HAVE_GETTIMEOFDAY
|
||||
{ struct timeval tv;
|
||||
if( gettimeofday( &tv, NULL ) )
|
||||
BUG();
|
||||
add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
|
||||
add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
|
||||
}
|
||||
#else /* use times */
|
||||
{
|
||||
#ifndef __MINGW32__
|
||||
struct tms buf;
|
||||
times( &buf );
|
||||
add_randomness( &buf, sizeof buf, 1 );
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_GETRUSAGE
|
||||
{ struct rusage buf;
|
||||
if( getrusage( RUSAGE_SELF, &buf ) )
|
||||
BUG();
|
||||
add_randomness( &buf, sizeof buf, 1 );
|
||||
memset( &buf, 0, sizeof buf );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
read_random_source( byte *buffer, size_t length, int level )
|
||||
{
|
||||
static int initialized=0;
|
||||
|
||||
if( !initialized ) {
|
||||
log_info(_("WARNING: using insecure random number generator!!\n"));
|
||||
tty_printf(_("The random number generator is only a kludge to let\n"
|
||||
"it compile - it is in no way a strong RNG!\n\n"
|
||||
"DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
|
||||
initialized=1;
|
||||
#ifdef HAVE_RAND
|
||||
srand(make_timestamp()*getpid());
|
||||
#else
|
||||
srandom(make_timestamp()*getpid());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_RAND
|
||||
while( length-- )
|
||||
*buffer++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
|
||||
#else
|
||||
while( length-- )
|
||||
*buffer++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#endif /* USE_RAND_DUMMY */
|
@ -20,34 +20,11 @@
|
||||
#ifndef G10_RAND_INTERNAL_H
|
||||
#define G10_RAND_INTERNAL_H
|
||||
|
||||
/* For now we use the DUMMY random generator if we do not have
|
||||
* the real random device */
|
||||
#ifndef HAVE_DEV_RANDOM
|
||||
#define USE_RAND_DUMMY 1
|
||||
#undef USE_RAND_UNIX
|
||||
#undef USE_RAND_W32
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#include "random.h"
|
||||
|
||||
#define BLOCKLEN 64 /* hash this amount of bytes */
|
||||
#define DIGESTLEN 20 /* into a digest of this length (rmd160) */
|
||||
/* poolblocks is the number of digests which make up the pool
|
||||
* and poolsize must be a multiple of the digest length
|
||||
* to make the AND operations faster, the size should also be
|
||||
* a multiple of ulong
|
||||
*/
|
||||
#define POOLBLOCKS 30
|
||||
#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
|
||||
#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
|
||||
#error Please make sure that poolsize is a multiple of ulong
|
||||
#endif
|
||||
#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
|
||||
|
||||
|
||||
void read_random_source( byte *buffer, size_t length, int level );
|
||||
|
||||
void rndlinux_constructor(void);
|
||||
void rndunix_constructor(void);
|
||||
void rndw32_constructor(void);
|
||||
void rndos2_constructor(void);
|
||||
void rndatari_constructor(void);
|
||||
void rndmvs_constructor(void);
|
||||
|
||||
#endif /*G10_RAND_INTERNAL_H*/
|
||||
|
@ -1,54 +0,0 @@
|
||||
/* rand-w32.c - Windoze32 and NT random device
|
||||
* Copyright (C) 1998 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNUPG.
|
||||
*
|
||||
* GNUPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GNUPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "util.h"
|
||||
#include "rmd.h"
|
||||
#include "ttyio.h"
|
||||
#include "i18n.h"
|
||||
#include "rand-internal.h"
|
||||
#ifdef USE_RAND_W32 /* this file is only for Mingw32 */
|
||||
|
||||
|
||||
#error To be written
|
||||
|
||||
void
|
||||
random_poll()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fast_random_poll()
|
||||
{
|
||||
}
|
||||
|
||||
#endif /* USE_RAND_W32 */
|
143
cipher/random.c
143
cipher/random.c
@ -36,7 +36,9 @@
|
||||
#include "rmd.h"
|
||||
#include "ttyio.h"
|
||||
#include "i18n.h"
|
||||
#include "random.h"
|
||||
#include "rand-internal.h"
|
||||
#include "dynload.h"
|
||||
|
||||
|
||||
#if SIZEOF_UNSIGNED_LONG == 8
|
||||
@ -47,6 +49,20 @@
|
||||
#error weird size for an unsigned long
|
||||
#endif
|
||||
|
||||
#define BLOCKLEN 64 /* hash this amount of bytes */
|
||||
#define DIGESTLEN 20 /* into a digest of this length (rmd160) */
|
||||
/* poolblocks is the number of digests which make up the pool
|
||||
* and poolsize must be a multiple of the digest length
|
||||
* to make the AND operations faster, the size should also be
|
||||
* a multiple of ulong
|
||||
*/
|
||||
#define POOLBLOCKS 30
|
||||
#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
|
||||
#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
|
||||
#error Please make sure that poolsize is a multiple of ulong
|
||||
#endif
|
||||
#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
|
||||
|
||||
|
||||
static int is_initialized;
|
||||
#define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
|
||||
@ -60,9 +76,16 @@ static int just_mixed;
|
||||
|
||||
static int secure_alloc;
|
||||
static int quick_test;
|
||||
static int faked_rng;
|
||||
|
||||
|
||||
static void read_pool( byte *buffer, size_t length, int level );
|
||||
static void add_randomness( const void *buffer, size_t length, int source );
|
||||
static void random_poll(void);
|
||||
static void read_random_source( byte *buffer, size_t length, int level );
|
||||
#ifndef HAVE_DEV_RANDOM
|
||||
static int gather_faked( byte *buffer, size_t *r_length, int level );
|
||||
#endif
|
||||
|
||||
|
||||
static void
|
||||
@ -76,6 +99,20 @@ initialize()
|
||||
keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
|
||||
: m_alloc_clear(POOLSIZE+BLOCKLEN);
|
||||
is_initialized = 1;
|
||||
|
||||
#if USE_RNDLINUX
|
||||
rndlinux_constructor();
|
||||
#elif USE_RNDUNIX
|
||||
rndunix_constructor();
|
||||
#elif USE_RNDW32
|
||||
rndw32_constructor();
|
||||
#elif USE_RNDOS2
|
||||
rndos2_constructor();
|
||||
#elif USE_RNDATARI
|
||||
rndatari_constructor();
|
||||
#elif USE_RNDMVS
|
||||
rndmvs_constructor();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
@ -88,13 +125,13 @@ secure_random_alloc()
|
||||
int
|
||||
quick_random_gen( int onoff )
|
||||
{
|
||||
int last = quick_test;
|
||||
int last;
|
||||
|
||||
read_random_source( NULL, 0, 0 ); /* load module */
|
||||
last = quick_test;
|
||||
if( onoff != -1 )
|
||||
quick_test = onoff;
|
||||
#ifdef USE_RAND_DUMMY
|
||||
last = 1; /* insecure RNG */
|
||||
#endif
|
||||
return last;
|
||||
return faked_rng? 1 : last;
|
||||
}
|
||||
|
||||
|
||||
@ -250,9 +287,9 @@ read_pool( byte *buffer, size_t length, int level )
|
||||
|
||||
/****************
|
||||
* Add LENGTH bytes of randomness from buffer to the pool.
|
||||
* source may be used to specify the randomeness source.
|
||||
* source may be used to specify the randomness source.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
add_randomness( const void *buffer, size_t length, int source )
|
||||
{
|
||||
if( !is_initialized )
|
||||
@ -271,3 +308,95 @@ add_randomness( const void *buffer, size_t length, int source )
|
||||
|
||||
|
||||
|
||||
static void
|
||||
random_poll()
|
||||
{
|
||||
char buf[POOLSIZE/5];
|
||||
read_random_source( buf, POOLSIZE/5, 1 );
|
||||
add_randomness( buf, POOLSIZE/5, 2);
|
||||
memset( buf, 0, POOLSIZE/5);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fast_random_poll()
|
||||
{
|
||||
static void (*fnc)( void (*)(const void*, size_t, int)) = NULL;
|
||||
static int initialized = 0;
|
||||
|
||||
if( !initialized ) {
|
||||
if( !is_initialized )
|
||||
initialize();
|
||||
initialized = 1;
|
||||
fnc = dynload_getfnc_fast_random_poll();
|
||||
if( !fnc )
|
||||
log_info("Ooops: No fast random poll function\n");
|
||||
}
|
||||
if( fnc )
|
||||
(*fnc)( add_randomness );
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
read_random_source( byte *buffer, size_t length, int level )
|
||||
{
|
||||
static int (*fnc)(byte*, size_t*, int) = NULL;
|
||||
int nbytes;
|
||||
int goodness;
|
||||
|
||||
if( !fnc ) {
|
||||
if( !is_initialized )
|
||||
initialize();
|
||||
fnc = dynload_getfnc_gather_random();
|
||||
if( !fnc ) {
|
||||
faked_rng = 1;
|
||||
#ifndef HAVE_DEV_RANDOM
|
||||
fnc = gather_faked;
|
||||
#else
|
||||
BUG();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
while( length ) {
|
||||
nbytes = length;
|
||||
goodness = (*fnc)( buffer, &nbytes, level );
|
||||
buffer +=nbytes;
|
||||
length -= nbytes;
|
||||
/* FIXME: how can we handle the goodness */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifndef HAVE_DEV_RANDOM
|
||||
static int
|
||||
gather_faked( byte *buffer, size_t *r_length, int level )
|
||||
{
|
||||
static int initialized=0;
|
||||
size_t length = *r_length;
|
||||
|
||||
if( !initialized ) {
|
||||
log_info(_("WARNING: using insecure random number generator!!\n"));
|
||||
tty_printf(_("The random number generator is only a kludge to let\n"
|
||||
"it compile - it is in no way a strong RNG!\n\n"
|
||||
"DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
|
||||
initialized=1;
|
||||
#ifdef HAVE_RAND
|
||||
srand(make_timestamp()*getpid());
|
||||
#else
|
||||
srandom(make_timestamp()*getpid());
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_RAND
|
||||
while( length-- )
|
||||
*buffer++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
|
||||
#else
|
||||
while( length-- )
|
||||
*buffer++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
|
||||
#endif
|
||||
return 100; /* We really fake it ;-) */
|
||||
}
|
||||
|
||||
#endif /* ! HAVE_DEV_RANDOM */
|
||||
|
||||
|
@ -27,13 +27,6 @@ void secure_random_alloc(void);
|
||||
int quick_random_gen( int onoff );
|
||||
void randomize_buffer( byte *buffer, size_t length, int level );
|
||||
byte *get_random_bits( size_t nbits, int level, int secure );
|
||||
void add_randomness( const void *buffer, size_t length, int source );
|
||||
|
||||
|
||||
/*-- the next two functions are implemented by all the system
|
||||
specific source files rand-xxxx.c --*/
|
||||
void random_poll(void);
|
||||
void fast_random_poll( void );
|
||||
|
||||
|
||||
#endif /*G10_RANDOM_H*/
|
||||
|
@ -1,14 +1,14 @@
|
||||
/* rand-unix.c - raw random number generator for unix like OSes
|
||||
/* rndlinux.c - raw random number for OSes with /dev/random
|
||||
* Copyright (C) 1998 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GNUPG.
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GNUPG is free software; you can redistribute it and/or modify
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GNUPG is distributed in the hope that it will be useful,
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
@ -40,56 +40,47 @@
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "util.h"
|
||||
#include "rmd.h"
|
||||
#include "ttyio.h"
|
||||
#include "i18n.h"
|
||||
#include "rand-internal.h"
|
||||
#ifdef USE_RAND_UNIX /* This file is only for real systems */
|
||||
|
||||
/* #define IS_MODULE 1 */
|
||||
|
||||
static int open_device( const char *name, int minor );
|
||||
static int gather_random( byte *buffer, size_t *r_length, int level );
|
||||
|
||||
|
||||
void
|
||||
random_poll()
|
||||
{
|
||||
char buf[POOLSIZE/5];
|
||||
read_random_source( buf, POOLSIZE/5, 1 ); /* read /dev/urandom */
|
||||
add_randomness( buf, POOLSIZE/5, 2);
|
||||
memset( buf, 0, POOLSIZE/5);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fast_random_poll()
|
||||
static void
|
||||
fast_poll( void (*add)(const void*, size_t, int) )
|
||||
{
|
||||
#if HAVE_GETHRTIME
|
||||
{ hrtime_t tv;
|
||||
tv = gethrtime();
|
||||
add_randomness( &tv, sizeof(tv), 1 );
|
||||
(*add)( &tv, sizeof(tv), 1 );
|
||||
}
|
||||
#elif HAVE_GETTIMEOFDAY
|
||||
{ struct timeval tv;
|
||||
if( gettimeofday( &tv, NULL ) )
|
||||
BUG();
|
||||
add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
|
||||
add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
|
||||
(*add)( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
|
||||
(*add)( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
|
||||
}
|
||||
#else /* use times */
|
||||
{ struct tms buf;
|
||||
times( &buf );
|
||||
add_randomness( &buf, sizeof buf, 1 );
|
||||
(*add)( &buf, sizeof buf, 1 );
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_GETRUSAGE
|
||||
{ struct rusage buf;
|
||||
if( getrusage( RUSAGE_SELF, &buf ) )
|
||||
BUG();
|
||||
add_randomness( &buf, sizeof buf, 1 );
|
||||
(*add)( &buf, sizeof buf, 1 );
|
||||
memset( &buf, 0, sizeof buf );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_DEV_RANDOM /* we have the /dev/random devices */
|
||||
|
||||
/****************
|
||||
* Used to open the Linux and xBSD /dev/random devices
|
||||
@ -115,14 +106,16 @@ open_device( const char *name, int minor )
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
read_random_source( byte *buffer, size_t length, int level )
|
||||
static int
|
||||
gather_random( byte *buffer, size_t *r_length, int level )
|
||||
{
|
||||
static int fd_urandom = -1;
|
||||
static int fd_random = -1;
|
||||
int fd;
|
||||
int n;
|
||||
int warn=0;
|
||||
size_t length = *r_length;
|
||||
/* note: we will always return the requested length */
|
||||
|
||||
if( level >= 2 ) {
|
||||
if( fd_random == -1 )
|
||||
@ -170,28 +163,75 @@ read_random_source( byte *buffer, size_t length, int level )
|
||||
buffer += n;
|
||||
length -= n;
|
||||
} while( length );
|
||||
|
||||
return 100; /* 100% useful at the requested level */
|
||||
}
|
||||
|
||||
#else /* not HAVE_DEV_RANDOM */
|
||||
|
||||
|
||||
#ifndef IS_MODULES
|
||||
static
|
||||
#endif
|
||||
const char * const gnupgext_version = "RNDLINUX ($Revision$)";
|
||||
|
||||
static struct {
|
||||
int class;
|
||||
int version;
|
||||
void *func;
|
||||
} func_table[] = {
|
||||
{ 40, 1, gather_random },
|
||||
{ 41, 1, fast_poll },
|
||||
};
|
||||
|
||||
|
||||
|
||||
/****************
|
||||
* The real random data collector for Unix.
|
||||
* this function runs in a loop, waiting for commands from ctrl_fd
|
||||
* and normally starts a collection process, which outputs random
|
||||
* bytes to out_fd.
|
||||
*
|
||||
* Commands understand from ctrl_fd are single character:
|
||||
* 'Q' = Quit the loop
|
||||
* 'S' = Start a new collection process
|
||||
* Enumerate the names of the functions together with informations about
|
||||
* this function. Set sequence to an integer with a initial value of 0 and
|
||||
* do not change it.
|
||||
* If what is 0 all kind of functions are returned.
|
||||
* Return values: class := class of function:
|
||||
* 10 = message digest algorithm info function
|
||||
* 11 = integer with available md algorithms
|
||||
* 20 = cipher algorithm info function
|
||||
* 21 = integer with available cipher algorithms
|
||||
* 30 = public key algorithm info function
|
||||
* 31 = integer with available pubkey algorithms
|
||||
* 40 = get gather_random function
|
||||
* 41 = get fast_random_poll function
|
||||
* version = interface version of the function/pointer
|
||||
* (currently this is 1 for all functions)
|
||||
*/
|
||||
static void
|
||||
collector( FILE *ctrlfp, FILE *outfp )
|
||||
|
||||
#ifndef IS_MODULE
|
||||
static
|
||||
#endif
|
||||
void *
|
||||
gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
|
||||
{
|
||||
void *ret;
|
||||
int i = *sequence;
|
||||
|
||||
do {
|
||||
if ( i >= DIM(func_table) || i < 0 ) {
|
||||
return NULL;
|
||||
}
|
||||
*class = func_table[i].class;
|
||||
*vers = func_table[i].version;
|
||||
ret = func_table[i].func;
|
||||
i++;
|
||||
} while ( what && what != *class );
|
||||
|
||||
|
||||
*sequence = i;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* no HAVE_DEV_RANDOM */
|
||||
#endif /* USE_RAND_UNIX */
|
||||
#ifndef IS_MODULE
|
||||
void
|
||||
rndlinux_constructor(void)
|
||||
{
|
||||
register_internal_cipher_extension( gnupgext_version,
|
||||
gnupgext_enum_func );
|
||||
}
|
||||
#endif
|
||||
|
754
cipher/rndunix.c
Normal file
754
cipher/rndunix.c
Normal file
@ -0,0 +1,754 @@
|
||||
/****************************************************************************
|
||||
* *
|
||||
* BeOS Randomness-Gathering Code *
|
||||
* Copyright Peter Gutmann, Paul Kendall, and Chris Wedgwood 1996-1998 *
|
||||
* *
|
||||
****************************************************************************/
|
||||
|
||||
/* General includes */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#ifdef HAVE_GETHRTIME
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETTIMEOFDAY
|
||||
#include <sys/times.h>
|
||||
#endif
|
||||
#ifdef HAVE_GETRUSAGE
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
|
||||
/* OS-specific includes */
|
||||
|
||||
#ifdef __osf__
|
||||
/* Somewhere in the morass of system-specific cruft which OSF/1 pulls in
|
||||
* via the following includes are various endianness defines, so we
|
||||
* undefine the cryptlib ones, which aren't really needed for this module
|
||||
* anyway */
|
||||
#undef BIG_ENDIAN
|
||||
#undef LITTLE_ENDIAN
|
||||
#endif /* __osf__ */
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <pwd.h>
|
||||
#ifndef __QNX__
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ipc.h>
|
||||
#endif /* __QNX__ */
|
||||
#include <sys/time.h> /* SCO and SunOS need this before resource.h */
|
||||
#ifndef __QNX__
|
||||
#include <sys/resource.h>
|
||||
#endif /* __QNX__ */
|
||||
#ifdef _AIX
|
||||
#include <sys/select.h>
|
||||
#endif /* _AIX */
|
||||
#ifndef __QNX__
|
||||
#include <sys/shm.h>
|
||||
#include <sys/signal.h>
|
||||
#endif /* __QNX__ */
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h> /* Verschiedene komische Typen */
|
||||
#if defined( __hpux ) && ( OS_VERSION == 9 )
|
||||
#include <vfork.h>
|
||||
#endif /* __hpux 9.x, after that it's in unistd.h */
|
||||
#include <sys/wait.h>
|
||||
/* #include <kitchensink.h> */
|
||||
#include <errno.h>
|
||||
|
||||
#include "types.h" /* for byte and u32 typedefs */
|
||||
#include "g10lib.h"
|
||||
#ifndef IS_MODULE
|
||||
#include "dynload.h"
|
||||
#endif
|
||||
|
||||
typedef enum { FALSE=0, TRUE } BOOLEAN;
|
||||
typedef unsigned char BYTE;
|
||||
|
||||
#define DEBUG_RANDOM 1
|
||||
#define DEBUG_RANDOM_VERBOSE 1
|
||||
|
||||
/* The structure containing information on random-data sources. Each
|
||||
* record contains the source and a relative estimate of its usefulness
|
||||
* (weighting) which is used to scale the number of kB of output from the
|
||||
* source (total = data_bytes / usefulness). Usually the weighting is in the
|
||||
* range 1-3 (or 0 for especially useless sources), resulting in a usefulness
|
||||
* rating of 1...3 for each kB of source output (or 0 for the useless
|
||||
* sources).
|
||||
*
|
||||
* If the source is constantly changing (certain types of network statistics
|
||||
* have this characteristic) but the amount of output is small, the weighting
|
||||
* is given as a negative value to indicate that the output should be treated
|
||||
* as if a minimum of 1K of output had been obtained. If the source produces
|
||||
* a lot of output then the scale factor is fractional, resulting in a
|
||||
* usefulness rating of < 1 for each kB of source output.
|
||||
*
|
||||
* In order to provide enough randomness to satisfy the requirements for a
|
||||
* slow poll, we need to accumulate at least 20 points of usefulness (a
|
||||
* typical system should get about 30 points).
|
||||
*
|
||||
* Some potential options are missed out because of special considerations.
|
||||
* pstat -i and pstat -f can produce amazing amounts of output (the record
|
||||
* is 600K on an Oracle server) which floods the buffer and doesn't yield
|
||||
* anything useful (apart from perhaps increasing the entropy of the vmstat
|
||||
* output a bit), so we don't bother with this. pstat in general produces
|
||||
* quite a bit of output, but it doesn't change much over time, so it gets
|
||||
* very low weightings. netstat -s produces constantly-changing output but
|
||||
* also produces quite a bit of it, so it only gets a weighting of 2 rather
|
||||
* than 3. The same holds for netstat -in, which gets 1 rather than 2.
|
||||
*
|
||||
* Some binaries are stored in different locations on different systems so
|
||||
* alternative paths are given for them. The code sorts out which one to
|
||||
* run by itself, once it finds an exectable somewhere it moves on to the
|
||||
* next source. The sources are arranged roughly in their order of
|
||||
* usefulness, occasionally sources which provide a tiny amount of
|
||||
* relatively useless data are placed ahead of ones which provide a large
|
||||
* amount of possibly useful data because another 100 bytes can't hurt, and
|
||||
* it means the buffer won't be swamped by one or two high-output sources.
|
||||
* All the high-output sources are clustered towards the end of the list
|
||||
* for this reason. Some binaries are checked for in a certain order, for
|
||||
* example under Slowaris /usr/ucb/ps understands aux as an arg, but the
|
||||
* others don't. Some systems have conditional defines enabling alternatives
|
||||
* to commands which don't understand the usual options but will provide
|
||||
* enough output (in the form of error messages) to look like they're the
|
||||
* real thing, causing alternative options to be skipped (we can't check the
|
||||
* return either because some commands return peculiar, non-zero status even
|
||||
* when they're working correctly).
|
||||
*
|
||||
* In order to maximise use of the buffer, the code performs a form of run-
|
||||
* length compression on its input where a repeated sequence of bytes is
|
||||
* replaced by the occurrence count mod 256. Some commands output an awful
|
||||
* lot of whitespace, this measure greatly increases the amount of data we
|
||||
* can fit in the buffer.
|
||||
*
|
||||
* When we scale the weighting using the SC() macro, some preprocessors may
|
||||
* give a division by zero warning for the most obvious expression
|
||||
* 'weight ? 1024 / weight : 0' (and gcc 2.7.2.2 dies with a division by zero
|
||||
* trap), so we define a value SC_0 which evaluates to zero when fed to
|
||||
* '1024 / SC_0' */
|
||||
|
||||
#define SC( weight ) ( 1024 / weight ) /* Scale factor */
|
||||
#define SC_0 16384 /* SC( SC_0 ) evalutes to 0 */
|
||||
|
||||
static struct RI {
|
||||
const char *path; /* Path to check for existence of source */
|
||||
const char *arg; /* Args for source */
|
||||
const int usefulness; /* Usefulness of source */
|
||||
FILE *pipe; /* Pipe to source as FILE * */
|
||||
int pipeFD; /* Pipe to source as FD */
|
||||
pid_t pid; /* pid of child for waitpid() */
|
||||
int length; /* Quantity of output produced */
|
||||
const BOOLEAN hasAlternative; /* Whether source has alt.location */
|
||||
} dataSources[] = {
|
||||
|
||||
{ "/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, FALSE},
|
||||
{ "/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, FALSE},
|
||||
{ "/usr/bin/pfstat", NULL, SC(-2), NULL, 0, 0, 0, FALSE},
|
||||
{ "/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, FALSE},
|
||||
{ "/usr/ucb/netstat", "-s", SC(2), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/netstat", "-s", SC(2), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/sbin/netstat", "-s", SC(2), NULL, 0, 0, 0, TRUE},
|
||||
{ "/usr/etc/netstat", "-s", SC(2), NULL, 0, 0, 0, FALSE},
|
||||
{ "/usr/bin/nfsstat", NULL, SC(2), NULL, 0, 0, 0, FALSE},
|
||||
{ "/usr/ucb/netstat", "-m", SC(-1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/netstat", "-m", SC(-1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/sbin/netstat", "-m", SC(-1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/etc/netstat", "-m", SC(-1), NULL, 0, 0, 0, FALSE },
|
||||
{ "/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/ucb/netstat", "-in", SC(-1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/sbin/netstat", "-in", SC(-1), NULL, 0, 0, 0, TRUE},
|
||||
{ "/usr/etc/netstat", "-in", SC(-1), NULL, 0, 0, 0, FALSE},
|
||||
{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.1.0",
|
||||
SC(-1), NULL, 0, 0, 0, FALSE }, /* UDP in */
|
||||
{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.4.0",
|
||||
SC(-1), NULL, 0, 0, 0, FALSE }, /* UDP out */
|
||||
{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.4.3.0",
|
||||
SC(-1), NULL, 0, 0, 0, FALSE }, /* IP ? */
|
||||
{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.10.0",
|
||||
SC(-1), NULL, 0, 0, 0, FALSE }, /* TCP ? */
|
||||
{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.11.0",
|
||||
SC(-1), NULL, 0, 0, 0, FALSE }, /* TCP ? */
|
||||
{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.13.0",
|
||||
SC(-1), NULL, 0, 0, 0, FALSE }, /* TCP ? */
|
||||
{ "/usr/bin/mpstat", NULL, SC(1), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/bin/w", NULL, SC(1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bsd/w", NULL, SC(1), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/bin/df", NULL, SC(1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/bin/df", NULL, SC(1), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/sbin/portstat", NULL, SC(1), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/bin/iostat", NULL, SC(SC_0), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/bin/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bsd/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, FALSE },
|
||||
{ "/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, FALSE },
|
||||
{ "/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/ucb/netstat", "-n", SC(0.5), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/sbin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/etc/netstat", "-n", SC(0.5), NULL, 0, 0, 0, FALSE },
|
||||
#if defined( __sgi ) || defined( __hpux )
|
||||
{ "/bin/ps", "-el", SC(0.3), NULL, 0, 0, 0, TRUE },
|
||||
#endif /* __sgi || __hpux */
|
||||
{ "/usr/ucb/ps", "aux", SC(0.3), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, TRUE },
|
||||
{ "/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, TRUE },
|
||||
{ "/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, FALSE },
|
||||
/* Unreliable source, depends on system usage */
|
||||
{ "/etc/pstat", "-p", SC(0.5), NULL, 0, 0, 0, TRUE },
|
||||
{ "/bin/pstat", "-p", SC(0.5), NULL, 0, 0, 0, FALSE },
|
||||
{ "/etc/pstat", "-S", SC(0.2), NULL, 0, 0, 0, TRUE },
|
||||
{ "/bin/pstat", "-S", SC(0.2), NULL, 0, 0, 0, FALSE },
|
||||
{ "/etc/pstat", "-v", SC(0.2), NULL, 0, 0, 0, TRUE },
|
||||
{ "/bin/pstat", "-v", SC(0.2), NULL, 0, 0, 0, FALSE },
|
||||
{ "/etc/pstat", "-x", SC(0.2), NULL, 0, 0, 0, TRUE },
|
||||
{ "/bin/pstat", "-x", SC(0.2), NULL, 0, 0, 0, FALSE },
|
||||
{ "/etc/pstat", "-t", SC(0.1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/bin/pstat", "-t", SC(0.1), NULL, 0, 0, 0, FALSE },
|
||||
/* pstat is your friend */
|
||||
{ "/usr/bin/last", "-n 50", SC(0.3), NULL, 0, 0, 0, TRUE },
|
||||
#ifdef __sgi
|
||||
{ "/usr/bsd/last", "-50", SC(0.3), NULL, 0, 0, 0, FALSE },
|
||||
#endif /* __sgi */
|
||||
#ifdef __hpux
|
||||
{ "/etc/last", "-50", SC(0.3), NULL, 0, 0, 0, FALSE },
|
||||
#endif /* __hpux */
|
||||
{ "/usr/bsd/last", "-n 50", SC(0.3), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.1.0",
|
||||
SC(0.1), NULL, 0, 0, 0, FALSE }, /* ICMP ? */
|
||||
{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.3.0",
|
||||
SC(0.1), NULL, 0, 0, 0, FALSE }, /* ICMP ? */
|
||||
{ "/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/arp", "-a", SC(0.1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/sbin/arp", "-a", SC(0.1), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/sbin/ripquery", "-nw 1 127.0.0.1",
|
||||
SC(0.1), NULL, 0, 0, 0, FALSE },
|
||||
{ "/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, TRUE },
|
||||
{ "/usr/ucb/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/bin/tcpdump", "-c 5 -efvvx", SC(1), NULL, 0, 0, 0, FALSE },
|
||||
/* This is very environment-dependant. If network traffic is low, it'll
|
||||
* probably time out before delivering 5 packets, which is OK because
|
||||
* it'll probably be fixed stuff like ARP anyway */
|
||||
{ "/usr/sbin/advfsstat", "-b usr_domain",
|
||||
SC(SC_0), NULL, 0, 0, 0, FALSE},
|
||||
{ "/usr/sbin/advfsstat", "-l 2 usr_domain",
|
||||
SC(0.5), NULL, 0, 0, 0, FALSE},
|
||||
{ "/usr/sbin/advfsstat", "-p usr_domain",
|
||||
SC(SC_0), NULL, 0, 0, 0, FALSE},
|
||||
/* This is a complex and screwball program. Some systems have things
|
||||
* like rX_dmn, x = integer, for RAID systems, but the statistics are
|
||||
* pretty dodgy */
|
||||
#if 0
|
||||
/* The following aren't enabled since they're somewhat slow and not very
|
||||
* unpredictable, however they give an indication of the sort of sources
|
||||
* you can use (for example the finger might be more useful on a
|
||||
* firewalled internal network) */
|
||||
{ "/usr/bin/finger", "@ml.media.mit.edu", SC(0.9), NULL, 0, 0, 0, FALSE },
|
||||
{ "/usr/local/bin/wget", "-O - http://lavarand.sgi.com/block.html",
|
||||
SC(0.9), NULL, 0, 0, 0, FALSE },
|
||||
{ "/bin/cat", "/usr/spool/mqueue/syslog", SC(0.9), NULL, 0, 0, 0, FALSE },
|
||||
#endif /* 0 */
|
||||
{ NULL, NULL, 0, NULL, 0, 0, 0, FALSE }
|
||||
};
|
||||
|
||||
/* Variables to manage the child process which fills the buffer */
|
||||
|
||||
static pid_t gathererProcess = 0; /* The child process which fills the
|
||||
* buffer */
|
||||
static BYTE *gathererBuffer; /* Shared buffer for gathering random noise */
|
||||
static int gathererMemID; /* ID for shared memory */
|
||||
static int gathererBufSize; /* Size of the shared memory buffer */
|
||||
static uid_t gathererID = (uid_t) - 1; /* Gatherers user ID */
|
||||
|
||||
/* The struct at the start of the shared memory buffer used to communicate
|
||||
* information from the child to the parent */
|
||||
|
||||
typedef struct {
|
||||
int usefulness; /* Usefulness of data in buffer */
|
||||
int noBytes; /* No.of bytes in buffer */
|
||||
} GATHERER_INFO;
|
||||
|
||||
/* Under SunOS popen() doesn't record the pid of the child process. When
|
||||
* pclose() is called, instead of calling waitpid() for the correct child, it
|
||||
* calls wait() repeatedly until the right child is reaped. The problem is
|
||||
* that this reaps any other children that happen to have died at that
|
||||
* moment, and when their pclose() comes along, the process hangs forever.
|
||||
* The fix is to use a wrapper for popen()/pclose() which saves the pid in
|
||||
* the dataSources structure (code adapted from GNU-libc's popen() call).
|
||||
*
|
||||
* Aut viam inveniam aut faciam */
|
||||
|
||||
static FILE *
|
||||
my_popen(struct RI *entry)
|
||||
{
|
||||
|
||||
int pipedes[2];
|
||||
FILE *stream;
|
||||
|
||||
/* Create the pipe */
|
||||
if (pipe(pipedes) < 0)
|
||||
return (NULL);
|
||||
|
||||
/* Fork off the child ("vfork() is like an OS orgasm. All OS's want to
|
||||
* do it, but most just end up faking it" - Chris Wedgwood). If your OS
|
||||
* supports it, you should try to use vfork() here because it's somewhat
|
||||
* more efficient */
|
||||
#if defined( sun ) || defined( __ultrix__ ) || defined( __osf__ ) || \
|
||||
defined(__hpux)
|
||||
entry->pid = vfork();
|
||||
#else /* */
|
||||
entry->pid = fork();
|
||||
#endif /* Unixen which have vfork() */
|
||||
if (entry->pid == (pid_t) - 1) {
|
||||
/* The fork failed */
|
||||
close(pipedes[0]);
|
||||
close(pipedes[1]);
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (entry->pid == (pid_t) 0) {
|
||||
struct passwd *passwd;
|
||||
|
||||
/* We are the child. Make the read side of the pipe be stdout */
|
||||
if (dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
|
||||
exit(127);
|
||||
|
||||
/* Now that everything is set up, give up our permissions to make
|
||||
* sure we don't read anything sensitive. If the getpwnam() fails,
|
||||
* we default to -1, which is usually nobody */
|
||||
if (gathererID == (uid_t) - 1 && \
|
||||
(passwd = getpwnam("nobody")) != NULL)
|
||||
gathererID = passwd->pw_uid;
|
||||
|
||||
setuid(gathererID);
|
||||
|
||||
/* Close the pipe descriptors */
|
||||
close(pipedes[STDIN_FILENO]);
|
||||
close(pipedes[STDOUT_FILENO]);
|
||||
|
||||
/* Try and exec the program */
|
||||
execl(entry->path, entry->path, entry->arg, NULL);
|
||||
|
||||
/* Die if the exec failed */
|
||||
exit(127);
|
||||
}
|
||||
|
||||
/* We are the parent. Close the irrelevant side of the pipe and open
|
||||
* the relevant side as a new stream. Mark our side of the pipe to
|
||||
* close on exec, so new children won't see it */
|
||||
close(pipedes[STDOUT_FILENO]);
|
||||
|
||||
fcntl(pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
|
||||
|
||||
stream = fdopen(pipedes[STDIN_FILENO], "r");
|
||||
|
||||
if (stream == NULL) {
|
||||
int savedErrno = errno;
|
||||
|
||||
/* The stream couldn't be opened or the child structure couldn't be
|
||||
* allocated. Kill the child and close the other side of the pipe */
|
||||
kill(entry->pid, SIGKILL);
|
||||
if (stream == NULL)
|
||||
close(pipedes[STDOUT_FILENO]);
|
||||
else
|
||||
fclose(stream);
|
||||
|
||||
waitpid(entry->pid, NULL, 0);
|
||||
|
||||
entry->pid = 0;
|
||||
errno = savedErrno;
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
return (stream);
|
||||
}
|
||||
|
||||
static int
|
||||
my_pclose(struct RI *entry)
|
||||
{
|
||||
int status = 0;
|
||||
|
||||
if (fclose(entry->pipe))
|
||||
return (-1);
|
||||
|
||||
/* We ignore the return value from the process because some programs
|
||||
* return funny values which would result in the input being discarded
|
||||
* even if they executed successfully. This isn't a problem because the
|
||||
* result data size threshold will filter out any programs which exit
|
||||
* with a usage message without producing useful output */
|
||||
if (waitpid(entry->pid, NULL, 0) != entry->pid)
|
||||
status = -1;
|
||||
|
||||
entry->pipe = NULL;
|
||||
entry->pid = 0;
|
||||
return (status);
|
||||
}
|
||||
|
||||
|
||||
/* Unix slow poll (without special support for Linux)
|
||||
*
|
||||
* If a few of the randomness sources create a large amount of output then
|
||||
* the slowPoll() stops once the buffer has been filled (but before all the
|
||||
* randomness sources have been sucked dry) so that the 'usefulness' factor
|
||||
* remains below the threshold. For this reason the gatherer buffer has to
|
||||
* be fairly sizeable on moderately loaded systems. This is something of a
|
||||
* bug since the usefulness should be influenced by the amount of output as
|
||||
* well as the source type */
|
||||
|
||||
#define DEVRANDOM_BITS 1024
|
||||
#define SHARED_BUFSIZE 49152 /* Usually about 25K are filled */
|
||||
|
||||
static void
|
||||
slowPoll(void)
|
||||
{
|
||||
GATHERER_INFO *gathererInfo;
|
||||
BOOLEAN moreSources;
|
||||
struct timeval tv;
|
||||
fd_set fds;
|
||||
#if defined( __hpux )
|
||||
size_t maxFD = 0;
|
||||
int pageSize = 4096; /* PHUX doesn't have getpagesize() */
|
||||
#elif defined( _M_XENIX ) || defined( __aux )
|
||||
int maxFD = 0, pageSize = 4096; /* Nor do others, but they
|
||||
* get fd right */
|
||||
#else /* */
|
||||
int maxFD = 0, pageSize = getpagesize();
|
||||
#endif /* OS-specific brokenness */
|
||||
int bufPos, i, usefulness = 0;
|
||||
|
||||
/* Make sure we don't start more than one slow poll at a time */
|
||||
if (gathererProcess) {
|
||||
g10_log_debug( "already in slowPoll\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Set up the shared memory */
|
||||
gathererBufSize = (SHARED_BUFSIZE / pageSize) * (pageSize + 1);
|
||||
|
||||
if ((gathererMemID = shmget(IPC_PRIVATE, gathererBufSize,
|
||||
IPC_CREAT | 0600)) == -1) {
|
||||
g10_log_debug("shmget failed: %s\n", strerror(errno) );
|
||||
return; /* Something broke */
|
||||
}
|
||||
|
||||
if ((gathererBuffer = (BYTE *) shmat(gathererMemID, NULL, 0)) == (BYTE *) - 1) {
|
||||
g10_log_debug("shmat failed: %s\n", strerror(errno) );
|
||||
return; /* Something broke */
|
||||
}
|
||||
|
||||
/* Fork off the gatherer, the parent process returns to the caller */
|
||||
if ((gathererProcess = fork()) || (gathererProcess == -1)) {
|
||||
g10_log_debug("gatherer pid = %d\n", gathererProcess );
|
||||
return; /* Error/parent process returns */
|
||||
}
|
||||
|
||||
|
||||
fclose(stderr); /* Arrghh!! It's Stuart code!! */
|
||||
|
||||
/* Reset the SIGC(H)LD handler to the system default. This is necessary
|
||||
* because if the program which cryptlib is a part of installs its own
|
||||
* SIGC(H)LD handler, it will end up reaping the cryptlib children before
|
||||
* cryptlib can. As a result, my_pclose() will call waitpid() on a
|
||||
* process which has already been reaped by the installed handler and
|
||||
* return an error, so the read data won't be added to the randomness
|
||||
* pool. There are two types of SIGC(H)LD naming, the SysV SIGCLD and
|
||||
* the BSD/Posix SIGCHLD, so we need to handle either possibility */
|
||||
#ifdef SIGCLD
|
||||
signal(SIGCLD, SIG_DFL);
|
||||
#else /* */
|
||||
signal(SIGCHLD, SIG_DFL);
|
||||
|
||||
#endif /* SIGCLD */
|
||||
|
||||
/* Fire up each randomness source */
|
||||
FD_ZERO(&fds);
|
||||
for (i = 0; dataSources[i].path != NULL; i++) {
|
||||
/* Since popen() is a fairly heavy function, we check to see whether
|
||||
* the executable exists before we try to run it */
|
||||
if (access(dataSources[i].path, X_OK)) {
|
||||
#ifdef DEBUG_RANDOM_VERBOSE
|
||||
printf("%s not present%s\n", dataSources[i].path,
|
||||
dataSources[i].hasAlternative ? ", has alternatives" : "");
|
||||
#endif /* DEBUG_RANDOM */
|
||||
dataSources[i].pipe = NULL;
|
||||
}
|
||||
else
|
||||
dataSources[i].pipe = my_popen(&dataSources[i]);
|
||||
|
||||
if (dataSources[i].pipe != NULL) {
|
||||
dataSources[i].pipeFD = fileno(dataSources[i].pipe);
|
||||
if (dataSources[i].pipeFD > maxFD)
|
||||
maxFD = dataSources[i].pipeFD;
|
||||
fcntl(dataSources[i].pipeFD, F_SETFL, O_NONBLOCK);
|
||||
FD_SET(dataSources[i].pipeFD, &fds);
|
||||
dataSources[i].length = 0;
|
||||
|
||||
/* If there are alternatives for this command, don't try and
|
||||
* execute them */
|
||||
while (dataSources[i].hasAlternative) {
|
||||
#ifdef DEBUG_RANDOM_VERBOSE
|
||||
printf("Skipping %s\n", dataSources[i + 1].path);
|
||||
#endif /* DEBUG_RANDOM */
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gathererInfo = (GATHERER_INFO *) gathererBuffer;
|
||||
bufPos = sizeof(GATHERER_INFO); /* Start of buf.has status
|
||||
* info */
|
||||
|
||||
/* Suck all the data we can get from each of the sources */
|
||||
moreSources = TRUE;
|
||||
while (moreSources && bufPos <= gathererBufSize) {
|
||||
/* Wait for data to become available from any of the sources, with a
|
||||
* timeout of 10 seconds. This adds even more randomness since data
|
||||
* becomes available in a nondeterministic fashion. Kudos to HP's QA
|
||||
* department for managing to ship a select() which breaks its own
|
||||
* prototype */
|
||||
tv.tv_sec = 10;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
#if defined( __hpux ) && ( OS_VERSION == 9 )
|
||||
if (select(maxFD + 1, (int *)&fds, NULL, NULL, &tv) == -1)
|
||||
#else /* */
|
||||
if (select(maxFD + 1, &fds, NULL, NULL, &tv) == -1)
|
||||
#endif /* __hpux */
|
||||
break;
|
||||
|
||||
/* One of the sources has data available, read it into the buffer */
|
||||
for (i = 0; dataSources[i].path != NULL; i++) {
|
||||
if( dataSources[i].pipe && FD_ISSET(dataSources[i].pipeFD, &fds)) {
|
||||
size_t noBytes;
|
||||
|
||||
if ((noBytes = fread(gathererBuffer + bufPos, 1,
|
||||
gathererBufSize - bufPos,
|
||||
dataSources[i].pipe)) == 0) {
|
||||
if (my_pclose(&dataSources[i]) == 0) {
|
||||
int total = 0;
|
||||
|
||||
/* Try and estimate how much entropy we're getting
|
||||
* from a data source */
|
||||
if (dataSources[i].usefulness)
|
||||
if (dataSources[i].usefulness < 0)
|
||||
total = (dataSources[i].length + 999)
|
||||
/ -dataSources[i].usefulness;
|
||||
else
|
||||
total = dataSources[i].length
|
||||
/ dataSources[i].usefulness;
|
||||
#ifdef DEBUG_RANDOM
|
||||
printf("%s %s contributed %d bytes (compressed), "
|
||||
"usefulness = %d\n", dataSources[i].path,
|
||||
(dataSources[i].arg != NULL) ?
|
||||
dataSources[i].arg : "",
|
||||
dataSources[i].length, total);
|
||||
#endif /* DEBUG_RANDOM */
|
||||
if( dataSources[i].length )
|
||||
usefulness += total;
|
||||
}
|
||||
dataSources[i].pipe = NULL;
|
||||
}
|
||||
else {
|
||||
int currPos = bufPos;
|
||||
int endPos = bufPos + noBytes;
|
||||
|
||||
/* Run-length compress the input byte sequence */
|
||||
while (currPos < endPos) {
|
||||
int ch = gathererBuffer[currPos];
|
||||
|
||||
/* If it's a single byte, just copy it over */
|
||||
if (ch != gathererBuffer[currPos + 1]) {
|
||||
gathererBuffer[bufPos++] = ch;
|
||||
currPos++;
|
||||
}
|
||||
else {
|
||||
int count = 0;
|
||||
|
||||
/* It's a run of repeated bytes, replace them
|
||||
* with the byte count mod 256 */
|
||||
while ((ch == gathererBuffer[currPos])
|
||||
&& currPos < endPos) {
|
||||
count++;
|
||||
currPos++;
|
||||
}
|
||||
gathererBuffer[bufPos++] = count;
|
||||
noBytes -= count - 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remember the number of (compressed) bytes of input we
|
||||
* obtained */
|
||||
dataSources[i].length += noBytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if there is more input available on any of the sources */
|
||||
moreSources = FALSE;
|
||||
FD_ZERO(&fds);
|
||||
for (i = 0; dataSources[i].path != NULL; i++) {
|
||||
if (dataSources[i].pipe != NULL) {
|
||||
FD_SET(dataSources[i].pipeFD, &fds);
|
||||
moreSources = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
gathererInfo->usefulness = usefulness;
|
||||
gathererInfo->noBytes = bufPos;
|
||||
|
||||
#ifdef DEBUG_RANDOM
|
||||
printf("Got %d bytes, usefulness = %d\n", bufPos, usefulness);
|
||||
#endif /* DEBUG_RANDOM */
|
||||
|
||||
/* Child MUST exit here */
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
fast_poll( void (*add)(const void*, size_t, int) )
|
||||
{
|
||||
#if HAVE_GETHRTIME
|
||||
{ hrtime_t tv;
|
||||
tv = gethrtime();
|
||||
(*add)( &tv, sizeof(tv), 1 );
|
||||
}
|
||||
#elif HAVE_GETTIMEOFDAY
|
||||
{ struct timeval tv;
|
||||
if( gettimeofday( &tv, NULL ) )
|
||||
BUG();
|
||||
(*add)( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
|
||||
(*add)( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
|
||||
}
|
||||
#else /* use times */
|
||||
{ struct tms buf;
|
||||
times( &buf );
|
||||
(*add)( &buf, sizeof buf, 1 );
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_GETRUSAGE
|
||||
{ struct rusage buf;
|
||||
if( getrusage( RUSAGE_SELF, &buf ) )
|
||||
BUG();
|
||||
(*add)( &buf, sizeof buf, 1 );
|
||||
memset( &buf, 0, sizeof buf );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
gather_random( byte *buffer, size_t *r_length, int level )
|
||||
{
|
||||
GATHERER_INFO gathererInfo;
|
||||
int status;
|
||||
size_t n;
|
||||
size_t length = *r_length;
|
||||
|
||||
slowPoll();
|
||||
assert( gathererProcess );
|
||||
/* Wait for the gathering process to finish, add the randomness it's
|
||||
* gathered, and detach the shared memory */
|
||||
waitpid(gathererProcess, &status, 0); /* Should prob.check status */
|
||||
|
||||
gathererInfo = *(GATHERER_INFO *)gathererBuffer;
|
||||
n = gathererInfo.noBytes;
|
||||
if( n > length )
|
||||
n = length;
|
||||
memcpy( buffer, gathererBuffer, n );
|
||||
|
||||
memset(gathererBuffer, 0, gathererBufSize);
|
||||
shmdt(gathererBuffer);
|
||||
shmctl(gathererMemID, IPC_RMID, NULL);
|
||||
gathererProcess = 0;
|
||||
|
||||
*r_length = n;
|
||||
if( gathererInfo.usefulness > 30 )
|
||||
return 100;
|
||||
else if ( gathererInfo.usefulness )
|
||||
return gathererInfo.usefulness * 100 / 30;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef IS_MODULE
|
||||
static
|
||||
#endif
|
||||
const char * const gnupgext_version = "RNDUNIX ($Revision$)";
|
||||
|
||||
|
||||
static struct {
|
||||
int class;
|
||||
int version;
|
||||
void *func;
|
||||
} func_table[] = {
|
||||
{ 40, 1, gather_random },
|
||||
{ 41, 1, fast_poll },
|
||||
};
|
||||
|
||||
/****************
|
||||
* Enumerate the names of the functions together with informations about
|
||||
* this function. Set sequence to an integer with a initial value of 0 and
|
||||
* do not change it.
|
||||
* If what is 0 all kind of functions are returned.
|
||||
* Return values: class := class of function:
|
||||
* 10 = message digest algorithm info function
|
||||
* 11 = integer with available md algorithms
|
||||
* 20 = cipher algorithm info function
|
||||
* 21 = integer with available cipher algorithms
|
||||
* 30 = public key algorithm info function
|
||||
* 31 = integer with available pubkey algorithms
|
||||
* 40 = get read_random_source() function
|
||||
* 41 = get fast_random_poll function
|
||||
* version = interface version of the function/pointer
|
||||
* (currently this is 1 for all functions)
|
||||
*/
|
||||
|
||||
#ifndef IS_MODULE
|
||||
static
|
||||
#endif
|
||||
void *
|
||||
gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
|
||||
{
|
||||
void *ret;
|
||||
int i = *sequence;
|
||||
|
||||
do {
|
||||
if ( i >= DIM(func_table) || i < 0 ) {
|
||||
return NULL;
|
||||
}
|
||||
*class = func_table[i].class;
|
||||
*vers = func_table[i].version;
|
||||
ret = func_table[i].func;
|
||||
i++;
|
||||
} while ( what && what != *class );
|
||||
|
||||
*sequence = i;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifndef IS_MODULE
|
||||
void
|
||||
rndunix_constructor(void)
|
||||
{
|
||||
register_internal_cipher_extension( gnupgext_version,
|
||||
gnupgext_enum_func );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user