/* This file was not originally part of the SSLeay distribution; added for Yenta. */

/* Portions of the following code are
   Copyright (C) 1995-1997 Pretty Good Privacy, Inc. All rights reserved,
   and portions are
   Copyright Peter Gutmann, Paul Kendall, and Chris Wedgwood 1996-1997.
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

/*
* Include <time.h> and <sys/time.h>
*/
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#if TIME_WITH_SYS_TIME
#include <time.h>
#endif
#else
#include <time.h>
#endif

#if HAVE_SYS_TIMES_H
#include <sys/times.h>
#endif
/* General includes */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_PWD_H
#include <pwd.h>
#endif
#ifdef HAVE_VFORK_H
#include <vfork.h>
#endif

#ifdef HAVE_SYS_TERMIOS_H

#include <sys/termios.h>
#define TERM_GET(fd,ptr) tcgetattr(fd,ptr)
#define TERM_SET(fd,ptr) tcsetattr(fd,TCSANOW,ptr)
#define CBREAK_ON(ptr) ((ptr)->c_cc[VMIN]=1, (ptr)->c_cc[VTIME]=0,\
						(ptr)->c_lflag &= ~(ECHO|ICANON))
#define TERM_STATE struct termios

#elif defined(HAVE_SYS_TERMIO_H)

#include <sys/termio.h>
#define TERM_GET(fd,ptr) ioctl(fd,TCGETA,ptr)
#define TERM_SET(fd,ptr) ioctl(fd,TCSETA,ptr)
#define CBREAK_ON(ptr) ((ptr)->c_cc[VMIN]=1, (ptr)->c_cc[VTIME]=0,\
						(ptr)->c_lflag &= ~(ECHO|ICANON))
#define TERM_STATE struct termio 

#elif defined(HAVE_SGTTY_H)
#ifndef CBREAK
#define CBREAK RAW
#endif
#define TERM_GET(fd,ptr) ioctl(fd,TIOCGETP,ptr)
#define TERM_SET(fd,ptr) ioctl(fd,TIOCSETN,ptr)
#define CBREAK_ON(ptr) ((ptr)->sg_flags |= CBREAK, (ptr)->sg_flags &= ~ECHO)
#define TERM_STATE struct sgttyb 

#else
#error Neither termios, termio, nor sgtty is available.
#endif

#include <signal.h>

#include "cryptlib.h"

/*
* This code uses five different timers, if available. Each possibility
* can be specifically enabled or disabled by predefining USE_XX to 1
* or 0. For some, the code attempts to detect availability automatically.
* If the symbols HAVE_XX are defined, they are used. If not, they are set
* to reasonable defaults while other clues are checked. The choices,
* and the auto-detection methods used, are:
* - gethrtime(), if HAVE_GETHRTIME is set to 1.
* - clock_gettime(CLOCK_REALTIME,...), if CLOCK_REALTIME is in <time.h>
* - gettimeofday(), assumed available unless HAVE_GETTIMEOFDAY=0
* - getitimer(ITIMER_REAL,...), if ITIMER_REAL is defined in <sys/time.h>
* - ftime(), assumed available unless HAVE_FTIME=0
*
* These are all accessed through the gettime(), timetype, and tickdiff()
* macros. The MINTICK constant is something to avoid the gettimeofday()
* glitch wherein it increments the return value even if no tick has occurred.
* When measuring the tick interval, if the difference between two successive
* times is not at least MINTICK ticks, it is ignored.
*/

#ifndef USE_GETHRTIME
#define USE_GETHRTIME HAVE_GETHRTIME
#endif

#if USE_GETHRTIME
typedef hrtime_t timetype;
#define gettime(s) (*(s) = gethrtime())
#define tickdiff(s,t) ((s)-(t))
#define MINTICK 0

#else
#ifndef USE_CLOCK_GETTIME
#if 0
#ifndef HAVE_CLOCK_GETTIME
#define HAVE_CLOCK_GETTIME 1
#endif
#endif
#if HAVE_CLOCK_GETTIME
#ifdef CLOCK_REALTIME
#define USE_CLOCK_GETTIME 1
#endif
#endif
#endif

#if USE_CLOCK_GETTIME

#define CHOICE_CLOCK_GETTIME 1
typedef struct timespec timetype;
#define gettime(s) (void)clock_gettime(CLOCK_REALTIME, s)
#define tickdiff(s,t) (((s).tv_sec-(t).tv_sec)*1000000000 + \
	(s).tv_nsec - (t).tv_nsec)
#define MINTICK 0
#if 0
#ifndef HAVE_CLOCK_GETRES
#define HAVE_CLOCK_GETRES 1
#endif
#endif

#else

#ifndef USE_GETTIMEOFDAY
#if 0
#ifndef HAVE_GETTIMEOFDAY
#define HAVE_GETTIMEOFDAY 1	 /* Assume we have it... */
#endif
#endif
#define USE_GETTIMEOFDAY HAVE_GETTIMEOFDAY
#endif

#if USE_GETTIMEOFDAY
typedef struct timeval timetype;
#define gettime(s) (void)gettimeofday(s, (struct timezone *)0)
#define tickdiff(s,t) (((s).tv_sec-(t).tv_sec)*1000000+(s).tv_usec-(t).tv_usec)
#define MINTICK 1

#else

#ifndef USE_GETITIMER
#if 0
#ifndef HAVE_GETITIMER
#define HAVE_GETITIMER 1
#endif
#ifndef HAVE_SETITIMER
#define HAVE_SETITIMER 1
#endif
#endif
#if HAVE_GETITIMER && HAVE_SETITIMER
#ifdef ITIMER_REAL
#define USE_GETITIMER 1
#endif
#endif
#endif

#if USE_GETITIMER
#define CHOICE_GETITIMER 1
#include <signal.h>	 /* For signal(), SIGALRM, SIG_IGN */
typedef struct itimerval timetype;
#define gettime(s) (void)getitimer(ITIMER_REAL, s)
/* Subtract *backwards* because timer is counting *down* */
#define tickdiff(s,t) (((t).it_value.tv_sec-(s).it_value.tv_sec)*1000000 + \
	(t).it_value.tv_usec - (s).it_value.tv_usec)
#define MINTICK 1

#else

#ifndef USE_FTIME
#if 0
#ifndef HAVE_FTIME
#define HAVE_FTIME 1
#endif
#ifndef HAVE_SYS_TIMEB_H
#define HAVE_SYS_TIMEB_H 1
#endif
#endif
#define USE_FTIME HAVE_FTIME && HAVE_SYS_TIMEB_H
#endif

#if USE_FTIME
#include <sys/timeb.h>
typedef struct timeb timetype;
#define gettime(s) (void)ftime(s)
#define tickdiff(s,t) (((s).time-(t).time)*1000 + (s).millitm - (t).millitm)
#define MINTICK	0

#else

#error No clock available

#endif /* USE_FTIME */
#endif /* USE_GETITIMER */
#endif /* USE_GETTIMEOFDAY */
#endif /* USE_CLOCK_GETTIME */
#endif /* USE_GETHRTIME */


#include "rand_int.h"

/* Number of elements in the given array */
#define elemsof(x) ((unsigned)(sizeof(x)/sizeof(*x)))

/*
* Accumulators to estimate entropy in the pool.
*/

unsigned randBits = 0; /* Bits of entropy in pool; used also by SCM/ssleay-linkage. */
static RAND_word32 randFrac = 0; /* Fraction of a bit of entropy in pool */
static unsigned randInBits = 0; /* Bits of entropy added to pool */

/*
* Estimate the amount of entropy in an input value x by seeing how
* different it is from what has come before.
*
* This is based on computing the delta from the previous value, and the
* second-order delta from the previous delta, and so on, for h orders.
* The minimum of any of those deltas is returned as the entropy estimate.
* (Which must, of course, have a logarithm taken to produce a "number
* of bits" output.)
*
* This requires a pointer to a h-word history table of previous deltas.
* A value of h = 3 is generally good, but some things (like keystroke
* timings) feed deltas and not input values into this, so that removes
* the first level.
*/
static RAND_word32
RAND_estimate(RAND_word32 x, RAND_word32 *history, unsigned h)
	{
	RAND_word32 t, min = x;

	while (h--)
		{
		t = history[h];		 	/* Last delta */
		t = (x > t) ? x - t : t - x;	 /* |x - history[h]| */
		history[h] = x;
		x = t;
		if (min > x)
			min = x;
		}
	return min;
	}

/*
* Gather and estimate entropy from keyboard timings. Double letters
* are allowed, but triples and more are considered suspiscious and
* entropy is not counted. (The actual criterion is that the current
* letter has appeared more than once in the previous four letters,
* which rejects aaaa... and ababa...)
*
* The "letter" can be generalized to mouse-clicks, button-pushes, menu
* selections, or anything else that can be categorized into a finite
* number of events.
*
* Question: is there a way to achieve this effect without remembering
* the recent keystrokes so explicitly? It seems like a possible
* security hole.
*
* We incorporate entropy from the first 3 samples, but don't count them
* since only after that many do we get reliable per-sample entropy estimates.
* (This is time for the two entries in teh hist array to get initialized,
* plus the one level of delta history implicitly included in the
* ranGetEntropy timing. It has to be there unless we want to export
* knowledge about the modulus at which the timer it uses wraps.)
*/
unsigned
RAND_add_keystroke(int event)
	{
	static int pastevent[4];		/* Last 4 events */
	static RAND_word32 hist[2];
	static unsigned histcount=elemsof(hist)+1;
	/* # invalid entries in hist array */
	RAND_word32 delta;
	unsigned n = 0;
	int i;
	
	delta = RAND_get_entropy();
	delta = RAND_estimate(delta, hist, elemsof(hist));
	
	RAND_seed((unsigned char *)&event, sizeof(event));
	
	/* Check for repetitive keystroke patterns */
	i = elemsof(pastevent) - 1;
	n = (event == pastevent[i]);
	do 
		{
		n += (event == (pastevent[i] = pastevent[i-1]));
		}
	while (--i);
	pastevent[0] = event;
	
	if (histcount > 0)
		{
		/* Not yet filled hist array */
		--histcount;
		return 0;
	}
	
	return (n > 1) ? 0 : RAND_pool_add_entropy(delta);
	}

/*
* True random bit accumulation. These are extra functions for entropy 
* estimation.
*
* Entropy is expressed in terms of a delta, essentially the difference
* between the observed value and the expected value, whose logarithm
* is a measure of entropy. (The logarithm to the base 2 is entropy
* expressed in bits.)
*
* The internal amount-of-entropy accumulator is maintained in two
* halves: a counter of bits, and a fraction of a bit, expressed
* in the form of a normalized delta. If 0 <= f < 1 is a fraction
* of a bit, then 1 <= 2^f < 2, so it's remembered as
* 0 <= x = 2^f - 1 < 1, a fixed-point number.
*
* Given a new fractional-bit delta, 1+y in similar form (obtained
* by normalizing the delta into the desired form), the output
* fractional bit delta 1+z = (1+x) * (1+y). If this exceeds 2,
* divide it by 2 and add a full bit to the bit counter.
*
* The implementation, of course, actually computes z = x + y + x*y,
* where 0 <= z < 3. This can be done by adding each of the three terms
* (each of which is less than 1) and noticing the overflow. If the
* addition does not overflow, z < 1 and nothing needs to be done.
*
* If one addition overflows, 1 <= z < 2, but after overflow we get
* z-1. We want (1+z)/2-1 = (z-1)/2, so just divide the result of
* the wrapped addition by 2.
*
* If both additions overflow, the addition wraps to z-2, but we
* still want (z-1)/2 = (z-2)/2 + 1/2, so divide the wrapped result
* by 2 and add 1/2.
*
* Due to the way that the fixed-point numbers are stored, the x*y part is
* the high half of the 32-bit unsigned product of x and y. This can be
* safely underestimated if desired, if a 64-bit product is difficult to
* compute.
*
* The simplest snd safest definition is
* #define UMULH_32(r,a,b) (r) = 0
*/
#ifndef UMULH_32
#if defined(__GNUC__) && defined(__i386__)
/* Inline asm goodies */
#define UMULH_32(r,a,b) __asm__("mull %2" : "=d"(r) : "%a"(a), "mr"(b) : "ax")
#elif defined(HAVE64)
#define UMULH_32(r,a,b) ((r) = (RAND_word32)((RAND_word64)(a) * (b) >> 32))
#else
/* Underestimate the product */
#define UMULH_32(r,a,b) ((r) = ((a) >> 16) * ((b) >> 16))
#endif
#endif /* !UMULH_32 */

#define DERATING 2	/* # of bits to underestimate */

unsigned
RAND_pool_add_entropy(RAND_word32 delta)
	{
	RAND_word32 frac, t;
	unsigned n;
	
	if (delta < 1 << DERATING)
		return 0;
	
	n = 31-DERATING;
	if (!(delta & 0xffff0000))
		delta <<= 16, n -= 16;
	if (!(delta & 0xff000000))
		delta <<= 8, n -= 8;
	if (!(delta & 0xf0000000))
		delta <<= 4, n -= 4;
	if (!(delta & 0xc0000000))
		delta <<= 2, n -= 2;
	if (!(delta & 0x80000000))
		delta <<= 1, n -= 1;
	assert(n < 32);

	/* Lose high-order bit of delta */
	assert(delta & 0x80000000);
	delta <<= 1;

	frac = randFrac;
	UMULH_32(t,delta,frac);
	if ((frac += t) < t)
		{
		if ((frac += delta) < delta)
			frac = (frac >> 1) + 0x80000000ul;
		else
			frac >>= 1;
		n++;
		} 
	else 
		if ((frac += delta) < delta) 
			{
			frac >>= 1;
			n++;
			}
	randFrac = frac;

	/* n is now the count of whole bits */
	if ((randBits += n) >= (STATE_SIZE << 3))
		{
		/* Overflow - saturate at (STATE_SIZE << 3) */
		randBits = (STATE_SIZE << 3);
		randFrac = 0;
		}

	/* Also count the inflow without regard to outflow */
	if ((randInBits += n) >= (STATE_SIZE << 3))
		{
		randInBits = (STATE_SIZE << 3);
		}
	return n;
	}

/*
 * Flush any pending input. If "thorough" is set, tries to be more
 * thorough about it. Ideally, wait for 1 second of quiet, but we
 * may do something more primitive.
 *
 * kbCbreak() has the side effect of flushing the inout queue, so this
 * is not too critical.
 */
static void
kbFlush(int fd, int thorough)
    {
	if (thorough)
		sleep(5);				/* Really give the user enough time to stop typing (was just 1)...  --- Foner */
#if defined(HAVE_TCFLUSH)
	tcflush(fd, TCIFLUSH);
#elif defined(TIOCFLUSH)
#ifndef FREAD
#define FREAD 1 /* The usual value */
#endif
	ioctl(fd, TIOCFLUSH, FREAD);
#endif
	}

void
RAND_get_keyboard_randomness(int numbits)
    {
	int infd, got_tty;
	FILE *outfp;
	TERM_STATE oldstate, newstate;
	char c;
	
	if (infd=open("/dev/tty", O_RDWR, 0666) >= 0)
		{
		outfp=fdopen(infd, "w");
		setvbuf(outfp, NULL, _IONBF, 0);
		got_tty=1;
		} 
	else
		{
		/* fall back on stdin/stderr */
		infd=0;
		outfp=stderr;
		got_tty=0;
		}

	TERM_GET(infd, &oldstate);
	newstate = oldstate;
	CBREAK_ON(&newstate);
	TERM_SET(infd, &newstate);
	
	fprintf(outfp,
		"\nHi.  Yenta must create some cryptographic keys for you, and,\n"
		"to do this, needs to generate %u random bits.  This is done by\n"
		"measuring the time intervals between your keystrokes.  This only\n"
		"needs to be done once, the very first time you run Yenta.  Please\n"
		"enter some random text on your keyboard until you hear the beep:\n\n",
		numbits);
	kbFlush(infd, 0);
	
	while(numbits > 0)
		{
		fprintf(outfp, "%u          \r", numbits);
		if (read(infd, &c, 1) == 1)
			numbits -= RAND_add_keystroke(c);
		}

	fprintf(outfp, "\aDone.  Thanks!    \n");
	kbFlush(infd, 1);
	TERM_SET(infd, &oldstate);
#if 0 /* We could have gotten an existing fd, which we shouldn't close. */
	if(got_tty)
	  fclose(outfp);
#endif
	}

#if CHOICE_CLOCK_GETTIME && HAVE_CLOCK_GETRES && 0

static unsigned
ranTickSize(void)
	{
	struct timespec res;

	clock_getres(CLOCK_REALTIME, &res);
	return (unsigned)res.tv_nsec;
	}

#else /* Normal clock resolution estimation */

#define N 15	/* Number of deltas to try (at least 5, preferably odd) */

/* Function needed for qsort() */
static int
ranCompare(void const *p1, void const *p2)
	{
	return *(unsigned const *)p1 > *(unsigned const *)p2 ? 1 :
		*(unsigned const *)p1 < *(unsigned const *)p2 ? -1 : 0;
	}

/*
* Find the resolution of the high-resolution clock by sampling successive
* values until a tick boundary, at which point the delta is entered into
* a table. An average near the median of the table is taken and returned
* as the system tick size to eliminate outliers due to descheduling (high)
* or tv0 not being the "zero" time in a given tick (low).
*
* Some trickery is needed to defeat the habit systems have of always
* incrementing the microseconds field from gettimeofday() results so that
* no two calls return the same value. Thus, a "tick boundary" is assumed
* when successive calls return a difference of more than MINTICK ticks.
* (For gettimeofday(), this is set to 2 us.) This catches cases where at
* most one other task reads the clock between successive reads by this task.
* More tasks in between are rare enough that they'll get cut off by the
* median filter.
*
* When a tick boundary is found, the *first* time read during the previous
* tick (tv0) is subtracted from the new time to get microseconds per tick.
*
* Suns have a 1 us timer, and as of SunOS 4.1, they return that timer, but
* there is ~50 us of system-call overhead to get it, so this overestimates
* the tick size considerably. On SunOS 5.x/Solaris, the overhead has been
* cut to about 2.5 us, so the measured time alternates between 2 and 3 us.
* Some better algorithms will be required for future machines that really
* do achieve 1 us granularity.
*
* Current best idea: discard all this hair and use Ueli Maurer's entropy
* estimation scheme. Assign each input event (delta) a sequence number.
* 16 bits should be more than adequate. Make a table of the last time
* (by sequence number) each possibe input event occurred. For practical
* implementation, hash the event to a fixed-size code and consider two
* events identical if they have the same hash code. This will only ever
* underestimate entropy. Then use the number of bits in the difference
* between the current sequence number and the previous one as the entropy
* estimate.
*
* If it's desirable to use longer contexts, Maurer's original technique
* just groups events into non-overlapping pairs and uses the technique on
* the pairs. If you want to increment the entropy numbers on each keystroke
* for user-interface niceness, you can do the operation each time, but you
* have to halve the sequence number difference before starting, and then you
* have to halve the number of bits of entropy computed because you're adding
* them twice.
*
* You can put the even and odd events into separate tables to close Maurer's
* model exactly, or you can just dump them into the same table, which will
* be more conservative.
*/
static unsigned
ranTickSize(void)
	{
	unsigned i = 0, j = 0, diff, d[N];
	timetype tv0, tv1, tv2;
	/*
	 * TODO Get some per-run data to seed the RNG with.
	 * pid, ppid, etc.
	 */
	gettime(&tv0);
	tv1 = tv0;
	do
		{
		gettime(&tv2);
		diff = (unsigned)tickdiff(tv2, tv1);
		if (diff > MINTICK)
			{
			d[i++] = diff;
			tv0 = tv2;
			j = 0;
			}
		else
			if (++j >= 4096)	/* Always getting <= MINTICK units */
				return MINTICK + !MINTICK;
		tv1 = tv2;
		}
	while (i < N);

	/* Return average of middle 5 values (rounding up) */
	qsort(d, N, sizeof(d[0]), ranCompare);
	diff = (d[N/2-2]+d[N/2-1]+d[N/2]+d[N/2+1]+d[N/2+2]+4)/5;
#if NOISEDEBUG
	fprintf(stderr, "Tick size is %u\n", diff);
#endif
	return diff;
	}

#endif /* Clock resolution measurement selection */

/*
* Add as much timing-dependent random noise as possible
* to the randPool. Typically, this involves reading the most
* accurate system clocks available.
*
* Returns the number of ticks that have passed since the last call,
* for entropy estimation purposes.
*/
RAND_word32
RAND_get_entropy(void)
	{
	RAND_word32 delta;
	timetype t;
	static unsigned ticksize = 0;
	static timetype prevt;
	
	gettime(&t);
#if CHOICE_GETITIMER
	/* If itimer isn't started, start it */
	if (t.it_value.tv_sec == 0 && t.it_value.tv_usec == 0)
		{
		/*
		 * start the timer - assume that Yenta won't be running for
		 * more than 31 years...
		 */
		t.it_value.tv_sec = 1000000000;
		t.it_interval.tv_sec = 1000000000;
		t.it_interval.tv_usec = 0;
#ifdef SIGALRM
		signal(SIGALRM, SIG_IGN);	/* just in case.. */
#endif
		setitimer(ITIMER_REAL, &t, NULL);
		t.it_value.tv_sec = 0;
		}
	RAND_seed((unsigned char *)&t.it_value, sizeof(t.it_value));
#else
	RAND_seed((unsigned char *)&t, sizeof(t));
#endif

	if (!ticksize)
		ticksize = ranTickSize();
	delta = (RAND_word32)(tickdiff(t, prevt) / ticksize);
	prevt = t;
	
	return delta;
	}

/* +++ Slow-polling.  Gathers randomness from a variety of sources.
   +++ Ripped off from CryptLib's misc/rndunix.c and adapted to work
   +++ with the rest of this file.  Everything on this page (to ---) is it. */

/* 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 */

typedef enum { RXP_FALSE, RXP_TRUE } RXP_BOOLEAN;


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 RXP_BOOLEAN hasAlternative;   /* Whether source has alt.location */
} dataSources[] = {
	{ "/bin/vmstat", "-s", SC( -3 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/vmstat", "-s", SC( -3 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/bin/vmstat", "-c", SC( -3 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/vmstat", "-c", SC( -3 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/bin/pfstat", NULL, SC( -2 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/bin/vmstat", "-i", SC( -2 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/vmstat", "-i", SC( -2 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/ucb/netstat", "-s", SC( 2 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/netstat", "-s", SC( 2 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/sbin/netstat", "-s", SC( 2 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/etc/netstat", "-s", SC( 2 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/bin/nfsstat", NULL, SC( 2 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/ucb/netstat", "-m", SC( -1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/netstat", "-m", SC( -1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/sbin/netstat", "-m", SC( -1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/etc/netstat", "-m", SC( -1 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/ucb/netstat", "-in", SC( -1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/netstat", "-in", SC( -1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/sbin/netstat", "-in", SC( -1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/etc/netstat", "-in", SC( -1 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.1.0", SC( -1 ), NULL, 0, 0, 0, RXP_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, RXP_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, RXP_FALSE }, /* IP ? */
	{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.10.0", SC( -1 ), NULL, 0, 0, 0, RXP_FALSE }, /* TCP ? */
	{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.11.0", SC( -1 ), NULL, 0, 0, 0, RXP_FALSE }, /* TCP ? */
	{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.13.0", SC( -1 ), NULL, 0, 0, 0, RXP_FALSE }, /* TCP ? */
	{ "/usr/bin/mpstat", NULL, SC( 1 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/bin/w", NULL, SC( 1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bsd/w", NULL, SC( 1 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/bin/df", NULL, SC( 1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/bin/df", NULL, SC( 1 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/sbin/portstat", NULL, SC( 1 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/bin/iostat", NULL, SC( SC_0 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/bin/uptime", NULL, SC( SC_0 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bsd/uptime", NULL, SC( SC_0 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/bin/vmstat", "-f", SC( SC_0 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/vmstat", "-f", SC( SC_0 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/bin/vmstat", NULL, SC( SC_0 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/vmstat", NULL, SC( SC_0 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/ucb/netstat", "-n", SC( 0.5 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/netstat", "-n", SC( 0.5 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/sbin/netstat", "-n", SC( 0.5) , NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/etc/netstat", "-n", SC( 0.5) , NULL, 0, 0, 0, RXP_FALSE },
	/* Hmm, there's no good way to test for SysV vs. BSD ps. Oh well.*/
#if defined(SYSV) || defined(SVR4) || defined(SVR3)
	{ "/bin/ps", "-el", SC( 0.3 ), NULL, 0, 0, 0, RXP_TRUE },
#else
	{ "/usr/ucb/ps", "aux", SC( 0.3 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/ps", "aux", SC( 0.3 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/bin/ps", "aux", SC( 0.3 ), NULL, 0, 0, 0, RXP_FALSE },
#endif
	{ "/usr/bin/ipcs", "-a", SC( 0.5 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/bin/ipcs", "-a", SC( 0.5 ), NULL, 0, 0, 0, RXP_FALSE },
	/* Unreliable source, depends on system usage */
	{ "/etc/pstat", "-p", SC( 0.5 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/bin/pstat", "-p", SC( 0.5 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/etc/pstat", "-S", SC( 0.2 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/bin/pstat", "-S", SC( 0.2 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/etc/pstat", "-v", SC( 0.2 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/bin/pstat", "-v", SC( 0.2 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/etc/pstat", "-x", SC( 0.2 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/bin/pstat", "-x", SC( 0.2 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/etc/pstat", "-t", SC( 0.1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/bin/pstat", "-t", SC( 0.1 ), NULL, 0, 0, 0, RXP_FALSE },
	/* pstat is your friend */
	{ "/usr/bin/last", "-n 5", SC( 0.3 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bsd/last", "-5", SC( 0.3 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/etc/last", "-5", SC( 0.3 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/bsd/last", "-n 5", SC( 0.3 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.1.0", SC( 0.1 ), NULL, 0, 0, 0, RXP_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, RXP_FALSE }, /* ICMP ? */
	{ "/etc/arp", "-a", SC( 0.1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/etc/arp", "-a", SC( 0.1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/arp", "-a", SC( 0.1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/sbin/arp", "-a", SC( 0.1 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/sbin/ripquery", "-nw 1 127.0.0.1", SC( 0.1 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/bin/lpstat", "-t", SC( 0.1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/bin/lpstat", "-t", SC( 0.1 ), NULL, 0, 0, 0, RXP_TRUE },
	{ "/usr/ucb/lpstat", "-t", SC( 0.1 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/bin/tcpdump", "-c 5 -efvvx", SC( 1 ), NULL, 0, 0, 0, RXP_FALSE },
	/* This is very environment-dependent.  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, RXP_FALSE },
	{ "/usr/sbin/advfsstat", "-l 2 usr_domain", SC( 0.5 ), NULL, 0, 0, 0, RXP_FALSE },
	{ "/usr/sbin/advfsstat", "-p usr_domain", SC( SC_0 ), NULL, 0, 0, 0, RXP_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
	{ "/usr/bin/finger", "@@ml.media.mit.edu", SC( 0.9 ), NULL, 0, 0, 0, RXP_FALSE },    /* Foner. */
	/* Tee hee...  the lavarand call below is obviously insecure, since someone could eavesdrop the data!
	   Not to mention that we'd have to ship wget or its equivalent.  But you get the idea... */
	{ "/usr/local/bin/wget", "-O - http://lavarand.sgi.com/block.html", SC( 0.9 ), NULL, 0, 0, 0, RXP_FALSE },    /* Foner. */
	/*  { "/bin/cat", "/usr/spool/mqueue/syslog", SC( 0.9 ), NULL, 0, 0, 0, RXP_FALSE }, */ /* Foner. */
#endif
	{ NULL, NULL, 0, NULL, 0, 0, 0, RXP_FALSE } };

/* 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 */
	entry->pid = vfork();
	if( entry->pid == ( pid_t ) -1 )
		{
		/* The fork failed */
		close( pipedes[ 0 ] );
		close( pipedes[ 1 ] );
		return( NULL );
		}
	else
		if( entry->pid == ( pid_t ) 0 )
			{
			/* We are the child.  Make the read side of
			   the pipe be stdout */
			if( dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0 )
				exit( 127 );

			/* 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 );
#ifdef HAVE_WAITPID
		waitpid( entry->pid, NULL, 0 );
#elif defined(HAVE_WAIT4)
		wait4(entry->pid, NULL, 0, NULL);
#else
#error "I don't know how to wait for a pid"
#endif
		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 with special support for Linux.  Really for Linux >=1.3.43
   (>=2.0.12 recommended), "mknod /dev/urandom c 1 9" if you don't have this
   device, and also "mknod /dev/random c 1 8" (this assumes you're root -
   "Use Linux, be your own luser").

   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 SLOW_POLL_BUFSIZE 49152		/* Usually about 25K are filled */

void RAND_slow_poll( void )
	{
	RXP_BOOLEAN moreSources;
	struct timeval tv;
	struct passwd *passwd;
	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 = 0, i, usefulness = 0, fd;
	
	static uid_t gathererID;
	char gathererBuffer[SLOW_POLL_BUFSIZE];
	uid_t savedID;

	int old_fd2;

	/* Cryptlib closed stderr here, probably because attempting to run all
	   the stuff below could possibly emit something to it.  Unfortunately,
	   dumped devo Yentas -use- stderr for the srepl loop!  (...because -all-
	   Yentas must use stderr 'cause of the SCM bug that causes dumped images
	   under Linux to segv if they try to use stdout---the current guess is
	   because stdout is buffered, but we don't know.)

	   So what we do here is to copy the stderr file descriptor, close it while
	   we run, and then arrange to put it back when we're done.  Since we preempt
	   everything else (certainly all other SCM tasks) while we're running, this
	   should be okay.  --- Foner */

	old_fd2 = dup(2);				/* Save away the old stderr. */
	close(2);

/*	fclose( stderr ); */	/* Arrghh!!  It's Stuart code!! */

	/* Make sure we don't call popen() as root */
	if( gathererID == ( uid_t ) -1
	    && ( passwd = getpwnam( "nobody" ) ) != NULL )
		gathererID = passwd->pw_uid;
	savedID = getuid();
	setuid( gathererID );

	/* 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
			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
				printf( "Skipping %s\n",
					dataSources[ i + 1 ].path );
#endif /* DEBUG_RANDOM */
				i++;
				}
			}
		}

	/* Suck all the data we can get from each of the sources */
	moreSources = RXP_TRUE;
	while( moreSources && bufPos <= SLOW_POLL_BUFSIZE )
		{

		/* 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;
#ifdef __hpux
		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 != NULL && \
				FD_ISSET( dataSources[ i ].pipeFD, &fds ) )
				{
				size_t noBytes;

				if((noBytes = fread(gathererBuffer + bufPos, 1,
						    SLOW_POLL_BUFSIZE - 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 */
						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 = RXP_FALSE;
		FD_ZERO( &fds );
		for( i = 0; dataSources[ i ].path != NULL; i++ )
			if( dataSources[ i ].pipe != NULL )
				{
				FD_SET( dataSources[ i ].pipeFD, &fds );
				moreSources = RXP_TRUE;
				}
		}
#ifdef DEBUG_RANDOM
	printf( "Got %d bytes, usefulness = %d\n", bufPos, usefulness );
#endif /* DEBUG_RANDOM */

	RAND_seed(gathererBuffer, SLOW_POLL_BUFSIZE);
	memset(gathererBuffer, 0, SLOW_POLL_BUFSIZE);
	while (usefulness >= 3) {
		/* Add 24 bits to entropy count. (Compensates for derating.) */
		RAND_pool_add_entropy(0x4000000);
		usefulness -= 3;
	}
	RAND_pool_add_entropy(32 << usefulness);
	/* Add remaining bits to entropy count. */	
	setuid(savedID);

	dup2(old_fd2, 2);
	close(old_fd2);
	}
/* --- End of CryptLib slow-poll stuff. */

/* If keyboard_available is 0, we aren't allowed to ask for keyboard input.
   NOTA BENE that this means that it's the caller's responsibility to check
   randBits and ensure that we got enough randomness!  If we're allowed to
   use the keyboard, then we'll make sure we get enough. */
void RAND_force_entropy(int numbits, int keyboard_available) {
	FILE *fh;

	if (numbits > STATE_SIZE << 3) numbits = STATE_SIZE << 3;
	
	if (numbits <= randBits) return;
	
	RAND_pool_add_entropy(RAND_get_entropy());

	if (numbits <= randBits) return;

#ifdef DEVRANDOM
	/* 
	 * Use a random entropy pool device.  Linux 1.3.x and FreeBSD-Current have this.
	 * Use /dev/urandom if you can as /dev/random will block if it runs out of random entries.
	 */
	if ((fh = fopen(DEVRANDOM, "r")) != NULL)
	{
		unsigned char buf[STATE_SIZE];
		int d = (numbits - randBits + 7) >> 3, r, n;
		r = fread((unsigned char *)buf,1,d,fh);
		/* we don't care how many bytes we read,
		 * we will just copy the 'stack' if there is
		 * nothing else :-) */
		fclose(fh);
		if (r > 0) {
			RAND_seed(buf,d);
			memset(buf,0,d);
			for (n = r; n >= 3; n -= 3)
				/* Add 24 bits to entropy count.  (Compensates for derating.) */
				RAND_pool_add_entropy(0x4000000);
			RAND_pool_add_entropy(32 << n);
			/* Add remaining bits to entropy count. */
			return;
		}
	}
#endif
	if (numbits <= randBits) return;

	RAND_slow_poll();

	if (numbits <= randBits) return;

	if (keyboard_available) {
		RAND_get_keyboard_randomness(numbits - randBits);
	}
	return;
}
