mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02: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)
|
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)
|
Mon Oct 19 18:34:30 1998 me,,, (wk@tobold)
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
## Process this file with automake to produce Makefile.in
|
## 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
|
INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/intl
|
||||||
|
|
||||||
@ -11,7 +11,7 @@ else
|
|||||||
pkglib_PROGRAMS =
|
pkglib_PROGRAMS =
|
||||||
endif
|
endif
|
||||||
|
|
||||||
DYNLINK_MOD_CFLAGS = @DYNLINK_MOD_CFLAGS@
|
DYNLINK_MOD_CFLAGS = -DIS_MODULE @DYNLINK_MOD_CFLAGS@
|
||||||
|
|
||||||
|
|
||||||
libcipher_a_SOURCES = cipher.c \
|
libcipher_a_SOURCES = cipher.c \
|
||||||
@ -33,9 +33,7 @@ libcipher_a_SOURCES = cipher.c \
|
|||||||
random.h \
|
random.h \
|
||||||
random.c \
|
random.c \
|
||||||
rand-internal.h \
|
rand-internal.h \
|
||||||
rand-unix.c \
|
rndlinux.c \
|
||||||
rand-w32.c \
|
|
||||||
rand-dummy.c \
|
|
||||||
rmd.h \
|
rmd.h \
|
||||||
rmd160.c \
|
rmd160.c \
|
||||||
sha1.h \
|
sha1.h \
|
||||||
@ -58,6 +56,11 @@ twofish: $(srcdir)/twofish.c
|
|||||||
sed -e 's/-O[0-9]*/ /' `
|
sed -e 's/-O[0-9]*/ /' `
|
||||||
|
|
||||||
|
|
||||||
|
rndunix: $(srcdir)/rndunix.c
|
||||||
|
$(COMPILE) $(DYNLINK_MOD_CFLAGS) -o rndunix $(srcdir)/rndunix.c
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
install-exec-hook:
|
install-exec-hook:
|
||||||
@list='$(pkglib_PROGRAMS)'; for p in $$list; do \
|
@list='$(pkglib_PROGRAMS)'; for p in $$list; do \
|
||||||
if test -f $(pkglibdir)/$$p; then \
|
if test -f $(pkglibdir)/$$p; then \
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
typedef struct ext_list {
|
typedef struct ext_list {
|
||||||
struct ext_list *next;
|
struct ext_list *next;
|
||||||
|
int internal;
|
||||||
#ifdef HAVE_DL_DLOPEN
|
#ifdef HAVE_DL_DLOPEN
|
||||||
void *handle; /* handle from dlopen() */
|
void *handle; /* handle from dlopen() */
|
||||||
#else
|
#else
|
||||||
@ -83,7 +84,7 @@ static int dld_available;
|
|||||||
void
|
void
|
||||||
register_cipher_extension( const char *mainpgm, const char *fname )
|
register_cipher_extension( const char *mainpgm, const char *fname )
|
||||||
{
|
{
|
||||||
EXTLIST r, el;
|
EXTLIST r, el, intex;
|
||||||
char *p, *pe;
|
char *p, *pe;
|
||||||
|
|
||||||
#ifdef HAVE_DLD_DLD_LINK
|
#ifdef HAVE_DLD_DLD_LINK
|
||||||
@ -114,13 +115,53 @@ register_cipher_extension( const char *mainpgm, const char *fname )
|
|||||||
el->hintstr = NULL;
|
el->hintstr = NULL;
|
||||||
|
|
||||||
/* check that it is not already registered */
|
/* 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) ) {
|
if( !compare_filenames(r->name, el->name) ) {
|
||||||
log_info("extension '%s' already registered\n", el->name );
|
log_info("extension '%s' already registered\n", el->name );
|
||||||
m_free(el);
|
m_free(el);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
else if( r->internal )
|
||||||
|
intex = r;
|
||||||
|
}
|
||||||
/* and register */
|
/* 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;
|
el->next = extensions;
|
||||||
extensions = el;
|
extensions = el;
|
||||||
}
|
}
|
||||||
@ -455,3 +496,51 @@ enum_gnupgext_pubkeys( void **enum_context, int *algo,
|
|||||||
return NULL;
|
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
|
#ifndef G10_CIPHER_DYNLOAD_H
|
||||||
#define 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
|
int
|
||||||
enum_gnupgext_digests( void **enum_context,
|
enum_gnupgext_digests( void **enum_context,
|
||||||
int *algo,
|
int *algo,
|
||||||
@ -49,4 +53,10 @@ enum_gnupgext_pubkeys( void **enum_context, int *algo,
|
|||||||
int (*cmp)(void *, MPI), void *opaquev ),
|
int (*cmp)(void *, MPI), void *opaquev ),
|
||||||
unsigned (**get_nbits)( int algo, MPI *pkey ) );
|
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*/
|
#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
|
#ifndef G10_RAND_INTERNAL_H
|
||||||
#define G10_RAND_INTERNAL_H
|
#define G10_RAND_INTERNAL_H
|
||||||
|
|
||||||
/* For now we use the DUMMY random generator if we do not have
|
void rndlinux_constructor(void);
|
||||||
* the real random device */
|
void rndunix_constructor(void);
|
||||||
#ifndef HAVE_DEV_RANDOM
|
void rndw32_constructor(void);
|
||||||
#define USE_RAND_DUMMY 1
|
void rndos2_constructor(void);
|
||||||
#undef USE_RAND_UNIX
|
void rndatari_constructor(void);
|
||||||
#undef USE_RAND_W32
|
void rndmvs_constructor(void);
|
||||||
#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 );
|
|
||||||
|
|
||||||
|
|
||||||
#endif /*G10_RAND_INTERNAL_H*/
|
#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 "rmd.h"
|
||||||
#include "ttyio.h"
|
#include "ttyio.h"
|
||||||
#include "i18n.h"
|
#include "i18n.h"
|
||||||
|
#include "random.h"
|
||||||
#include "rand-internal.h"
|
#include "rand-internal.h"
|
||||||
|
#include "dynload.h"
|
||||||
|
|
||||||
|
|
||||||
#if SIZEOF_UNSIGNED_LONG == 8
|
#if SIZEOF_UNSIGNED_LONG == 8
|
||||||
@ -47,6 +49,20 @@
|
|||||||
#error weird size for an unsigned long
|
#error weird size for an unsigned long
|
||||||
#endif
|
#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;
|
static int is_initialized;
|
||||||
#define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
|
#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 secure_alloc;
|
||||||
static int quick_test;
|
static int quick_test;
|
||||||
|
static int faked_rng;
|
||||||
|
|
||||||
|
|
||||||
static void read_pool( byte *buffer, size_t length, int level );
|
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
|
static void
|
||||||
@ -76,6 +99,20 @@ initialize()
|
|||||||
keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
|
keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
|
||||||
: m_alloc_clear(POOLSIZE+BLOCKLEN);
|
: m_alloc_clear(POOLSIZE+BLOCKLEN);
|
||||||
is_initialized = 1;
|
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
|
void
|
||||||
@ -88,13 +125,13 @@ secure_random_alloc()
|
|||||||
int
|
int
|
||||||
quick_random_gen( int onoff )
|
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 )
|
if( onoff != -1 )
|
||||||
quick_test = onoff;
|
quick_test = onoff;
|
||||||
#ifdef USE_RAND_DUMMY
|
return faked_rng? 1 : last;
|
||||||
last = 1; /* insecure RNG */
|
|
||||||
#endif
|
|
||||||
return last;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -250,9 +287,9 @@ read_pool( byte *buffer, size_t length, int level )
|
|||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Add LENGTH bytes of randomness from buffer to the pool.
|
* 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 )
|
add_randomness( const void *buffer, size_t length, int source )
|
||||||
{
|
{
|
||||||
if( !is_initialized )
|
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 );
|
int quick_random_gen( int onoff );
|
||||||
void randomize_buffer( byte *buffer, size_t length, int level );
|
void randomize_buffer( byte *buffer, size_t length, int level );
|
||||||
byte *get_random_bits( size_t nbits, int level, int secure );
|
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 );
|
void fast_random_poll( void );
|
||||||
|
|
||||||
|
|
||||||
#endif /*G10_RANDOM_H*/
|
#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.
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
* (at your option) any later version.
|
* (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
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
@ -40,56 +40,47 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "rmd.h"
|
|
||||||
#include "ttyio.h"
|
#include "ttyio.h"
|
||||||
#include "i18n.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
|
static void
|
||||||
random_poll()
|
fast_poll( void (*add)(const void*, size_t, int) )
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
#if HAVE_GETHRTIME
|
#if HAVE_GETHRTIME
|
||||||
{ hrtime_t tv;
|
{ hrtime_t tv;
|
||||||
tv = gethrtime();
|
tv = gethrtime();
|
||||||
add_randomness( &tv, sizeof(tv), 1 );
|
(*add)( &tv, sizeof(tv), 1 );
|
||||||
}
|
}
|
||||||
#elif HAVE_GETTIMEOFDAY
|
#elif HAVE_GETTIMEOFDAY
|
||||||
{ struct timeval tv;
|
{ struct timeval tv;
|
||||||
if( gettimeofday( &tv, NULL ) )
|
if( gettimeofday( &tv, NULL ) )
|
||||||
BUG();
|
BUG();
|
||||||
add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
|
(*add)( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
|
||||||
add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
|
(*add)( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
|
||||||
}
|
}
|
||||||
#else /* use times */
|
#else /* use times */
|
||||||
{ struct tms buf;
|
{ struct tms buf;
|
||||||
times( &buf );
|
times( &buf );
|
||||||
add_randomness( &buf, sizeof buf, 1 );
|
(*add)( &buf, sizeof buf, 1 );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_GETRUSAGE
|
#ifdef HAVE_GETRUSAGE
|
||||||
{ struct rusage buf;
|
{ struct rusage buf;
|
||||||
if( getrusage( RUSAGE_SELF, &buf ) )
|
if( getrusage( RUSAGE_SELF, &buf ) )
|
||||||
BUG();
|
BUG();
|
||||||
add_randomness( &buf, sizeof buf, 1 );
|
(*add)( &buf, sizeof buf, 1 );
|
||||||
memset( &buf, 0, sizeof buf );
|
memset( &buf, 0, sizeof buf );
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef HAVE_DEV_RANDOM /* we have the /dev/random devices */
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Used to open the Linux and xBSD /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
|
static int
|
||||||
read_random_source( byte *buffer, size_t length, int level )
|
gather_random( byte *buffer, size_t *r_length, int level )
|
||||||
{
|
{
|
||||||
static int fd_urandom = -1;
|
static int fd_urandom = -1;
|
||||||
static int fd_random = -1;
|
static int fd_random = -1;
|
||||||
int fd;
|
int fd;
|
||||||
int n;
|
int n;
|
||||||
int warn=0;
|
int warn=0;
|
||||||
|
size_t length = *r_length;
|
||||||
|
/* note: we will always return the requested length */
|
||||||
|
|
||||||
if( level >= 2 ) {
|
if( level >= 2 ) {
|
||||||
if( fd_random == -1 )
|
if( fd_random == -1 )
|
||||||
@ -170,28 +163,75 @@ read_random_source( byte *buffer, size_t length, int level )
|
|||||||
buffer += n;
|
buffer += n;
|
||||||
length -= n;
|
length -= n;
|
||||||
} while( length );
|
} 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.
|
* Enumerate the names of the functions together with informations about
|
||||||
* this function runs in a loop, waiting for commands from ctrl_fd
|
* this function. Set sequence to an integer with a initial value of 0 and
|
||||||
* and normally starts a collection process, which outputs random
|
* do not change it.
|
||||||
* bytes to out_fd.
|
* If what is 0 all kind of functions are returned.
|
||||||
*
|
* Return values: class := class of function:
|
||||||
* Commands understand from ctrl_fd are single character:
|
* 10 = message digest algorithm info function
|
||||||
* 'Q' = Quit the loop
|
* 11 = integer with available md algorithms
|
||||||
* 'S' = Start a new collection process
|
* 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 */
|
#ifndef IS_MODULE
|
||||||
#endif /* USE_RAND_UNIX */
|
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