Overview:
=========
- This is the PRNGD "Pseudo Random Number Generator Daemon".
  It offers an EGD compatible interface to obtain random data and is
  intended to be used as an entropy source to feed other software,
  especially software based on OpenSSL.
- Like EGD it calls system programs to collect entropy.
- Unlike EGD it does not generate a pool of random bits that can be
  called from other software.
  Rather more it feeds the bits gathered into its internal PRNG from which
  the "random bits" are obtained when requested. This way, PRNGD is
  never drained and can never block (unlike EGD), so it is also suitable
  to seed inetd-started programs.
  It also features a seed-save file, so that it is immediately usable
  after system start.
- PRNGD is intended to replace EGD.
- If you have a UNIX version providing /dev/urandom or /dev/random you
  probably won't need PRNGD at all.

License:
========
- This software is free. You can do with it whatever you want.
  I would however kindly ask you to acknowledge the use of this
  package, if you are going use it in your software, which you might
  be going to distribute. I would also like to receive a note if you
  are a satisfied user :-)

Disclaimer:
===========
- This software is provided ``as is''. You are using it at your own risk.
  I will take no liability in any case.

Author:
=======
- Lutz Jaenicke <Lutz.Jaenicke@aet.TU-Cottbus.DE>

Download:
=========
- The latest version of PRNGD can be accessed via
  http://ftp.aet.TU-Cottbus.DE/personen/jaenicke/postfix_tls/prngd.html

Usage:
======
Usage of PRNGD is simple:

- Adjust the Makefile (and config.h) to fit your machine and compile "prngd".
  Install it at a place you like (e.g. /usr/local/sbin).
- Generate an /etc/prngd.conf file with commands to gather entropy. The
  format of the file is taken from the OpenSSH-portable package. See the
  included examples in the contrib/OS subdirectories _and_ read the
  file 00README.gatherers.
- Generate an initial seed by some means. If you already have a real EGD, use
    egc.pl /path/to/EGD-SOCKET read 255 > /etc/prngd-seed
    (egc.pl is part of the EGD source package)
  or cat some logfiles together
    cat /var/adm/syslog/mail.log /var/adm/syslog/syslog.log > /etc/prngd-seed
  (prngd will start without initial seed and collect entropy as fast as it
  can on startup. If you can supply initial seed it is even better.)
  This step is only relevant before the first start.
- Start prngd:
    /usr/local/sbin/prngd /var/run/egd-pool
  This will create the socket at /var/run/egd-pool for you. If there is
  already an unused socket, it will be removed automatically in order to
  put the new one. If another file or directory with this name exists,
  prngd will stop. prngd needs 'write' permission in the directory within
  which the socket file-descriptor must be written.
  You can specify more than one socket, prngd will server all sockets
  simultaneously from the same pool but (of course) will generate other
  random bytes for each and every call.

  It might take a moment to read the initial seed, if you provided large
  files.
  Use egc.pl (part of the EGD source package) to check that prngd really works:
    egc.pl /var/run/egd-pool get
  should yield the entropy in the PRNG pool as estimated by the PRNG.
  Obtain some random data for test
    egc.pl /var/run/egd-pool read 255
  Alternatively the tools/prngd-ctl.c tool might be used for test; please
  check out the usage instructions in the head of the file.

  Starting with OpenSSL 0.9.7 (not yet released at the time of this writing),
  the PRNG in the OpenSSL library will automatically query an egd-socket
  located at
    /var/run/egd-pool, /dev/egd-pool, or /etc/egd-pool
  It is therefore recommended to use (one of) these locations, so that
  programs using these future versions of OpenSSL can obtain their random
  seed automatically.
- You can shut down PRNGD cleanly (it will save actual random data back to
  the seed file) by sending it TERM.
    prngd --kill /var/run/egd-pool
  will send TERM for you.

PRNGD supports both UNIX sockets (as shown in the examples) as well as
TCP sockets (localhost only!). There is no port number registered (yet),
so pick a free port on your system, e.g. 708 when running with root permissions
and you want to offer it as a system service, or 4840 without root permissions.
Both ports are not assigned to any service as of
  http://www.isi.edu/in-notes/iana/assignments/port-numbers
To have PRNGD listen on both the Unix socket and TCP do
  prngd [other options] /var/run/egd-pool tcp/localhost:708 tcp/localhost:4840
In checking TCP operation with egc.pl I had to list the TCP ports in
/etc/services;
prngd		708/tcp		# prngd/EGD system service
prngd-user	4840/tcp	# prngd/EGD user service
  egc.pl localhost:prngd get
PRNGD itself by now only handles numerical port numbers.

egc.pl is part of the EGD package. You already have EGD, don't you??
Don't miss the original EGD!!!
  http://www.lothar.com/tech/crypto/

Porting:
========
- PRNGD has been developed on HP-UX 10.20 and (SuSE-)Linux. Support for
  other platforms has been provided by:
  Solaris 2.6: Louis LeBlanc <leblanc@mirror-image.com>
  Solaris 7: Phil Howard <phil-openssh-unix-dev@ipal.net>
  NeXTstep 3: Michael Weiser <michael@weiser.saale-net.de>
  NeXTstep 3 (HPPA): Jacques Distler <distler@golem.ph.utexas.edu>
  IRIX 6.5: Michael Weiser <michael@weiser.saale-net.de>
  Tru64: James Bourne <jbourne@MtRoyal.AB.CA>
  AIX32: Bernhard Simon <simon@zid.tuwien.ac.at>
  AIX41: Jim Knoble <jmknoble@pobox.com>
  AIX43: Joerg Petersen <j.petersen@msh.de> and Peter Samuelson
	 <peter@cadcamlab.org>
  AIX51: Rich Holland <holland@guidancetech.com>
  Unixware 1: Dave Dykstra <dwd@bell-labs.com>
  Unixware 7: George Walsh <gjmwalsh@netscape.net> and John Hughes
	      <john@Calva.COM> (The original port from George Walsh produced
	      "bind(): invalid argument" errors but they don't seem to occur
	      for John Huges anymore.)
  SCO OpenServer 5: Boyd Lynn Gerber <gerberb@zenez.com>,
	      David Leska <leska@nspiv.cz>
  SCO 3: Gert Doering <gert@greenie.muc.de>
  OSF1: Daniel Carroll <dan@mesastate.edu>
  ATT-NCR: Daniel Carroll <dan@mesastate.edu>
  MacOS-X: KOBAYASHI Atsushi <loudear@is.luvnet.com>
  OpenUNIX 8: Boyd Lynn Gerber <gerberb@zenez.com>
  ReliantUNIX (>=5.43): Robert Dahlem <Robert.Dahlem@ffm2.siemens.de>
  Ultrix V4.5: Bernhard Simon <simon@zid.tuwien.ac.at>
  Unicos: Marcin Mogielnicki <mar@ghandalf.pism.pl>
  Tandem Himalay: Simon Goldrei <Simon.Goldrei@webpay.com.au>
  nsr-tandem-nsk: Bates, Tom" <tom.bates@hp.com>
  FreeBSD: Bjoern A. Zeeb <bzeeb@zabbadoz.net>
  Some of the initially contributed patches have been improved by other
  contributors. I'll have to find another way of acknowledging all of them.
  Read the ChangeLog to learn about contributors.
- To port PRNGD to a new platform:
  * Check out the compiler and flags in Makefile
  * IMPORTANT: Adjust the path names in config.h, as these files are used to
    obtain seeding by size and modification/access times very frequently!!
  * Provide a prngd.conf file. The format is compatible to OpenSSH, so you
    can use a file created by the OpenSSH install process for you.
  * Send feedback to me, so that it can be added to the distribution :-)

Acknowledgements:
=================
- The above mentioned people spent their time for porting. Please also check
  out the ChangeLog file, I might have forgotten somebody here :-)
- Theo de Raadt <deraadt@cvs.openbsd.org> made a lot of excellent suggestions
  on how to make PRNGD bullet proof with respect to signal handling,
  number of open file descriptors and, and, and...
- Scott Hamilton <sah@uow.edu.au> rewrote the error handling and logging
  after 0.9.7 (and in fact realized parts of Theo's suggestions :-).
- Thomas Binder <binder@arago.de> provided the prngd-ctl tool.

Todo:
=====
- Too long to be listed :-)
- Engage "autoconf" to make this thing easier to port and configure.


===== bsd-daemon.c =====
/*-
 * Copyright (c) 1990, 1993
 *	The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */


#ifndef HAVE_DAEMON

#if defined(LIBC_SCCS) && !defined(lint)
static char rcsid[] = "$OpenBSD: daemon.c,v 1.2 1996/08/19 08:22:13 tholo Exp $";
#endif /* LIBC_SCCS and not lint */

#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#ifdef HAVE_PATHS_H
# include <paths.h>
#endif 

#include "prngd.h"

int
daemon(int nochdir, int noclose)
{
	int fd;

	switch(fork()) {
	case -1:
		error_fatal("failed to fork()", errno);
		return (-1);
	case 0:
		break;
	default:
		_exit(EXIT_SUCCESS);
	}

	if (setsid() == -1)
		return (-1);

	if (!nochdir)
		(void)chdir("/");

	if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
		(void)dup2(fd, STDIN_FILENO);
		(void)dup2(fd, STDOUT_FILENO);
		(void)dup2(fd, STDERR_FILENO);
		if (fd > 2)
			(void)close (fd);
	}
	return (0);
}

#endif /* !HAVE_DAEMON */


===== bsd-snprintf.c =====
/**************************************************************
 * Original:
 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
 * A bombproof version of doprnt (dopr) included.
 * Sigh.  This sort of thing is always nasty do deal with.  Note that
 * the version here does not include floating point...
 *
 * snprintf() is used instead of sprintf() as it does limit checks
 * for string length.  This covers a nasty loophole.
 *
 * The other functions are there to prevent NULL pointers from
 * causing nast effects.
 *
 * More Recently:
 *  Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43
 *  This was ugly.  It is still ugly.  I opted out of floating point
 *  numbers, but the formatter understands just about everything
 *  from the normal C string format, at least as far as I can tell from
 *  the Solaris 2.5 printf(3S) man page.
 *
 *  Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1
 *    Ok, added some minimal floating point support, which means this
 *    probably requires libm on most operating systems.  Don't yet
 *    support the exponent (e,E) and sigfig (g,G).  Also, fmtint()
 *    was pretty badly broken, it just wasn't being exercised in ways
 *    which showed it, so that's been fixed.  Also, formated the code
 *    to mutt conventions, and removed dead code left over from the
 *    original.  Also, there is now a builtin-test, just compile with:
 *           gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm
 *    and run snprintf for results.
 * 
 *  Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i
 *    The PGP code was using unsigned hexadecimal formats. 
 *    Unfortunately, unsigned formats simply didn't work.
 *
 *  Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8
 *    The original code assumed that both snprintf() and vsnprintf() were
 *    missing.  Some systems only have snprintf() but not vsnprintf(), so
 *    the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF.
 *
 *  Ben Lindstrom <mouring@eviladmin.org> 09/27/00 for OpenSSH
 *    Welcome to the world of %lld and %qd support.  With other
 *    long long support.  This is needed for sftp-server to work
 *    right.
 *
 *  Ben Lindstrom <mouring@eviladmin.org> 02/12/01 for OpenSSH
 *    Removed all hint of VARARGS stuff and banished it to the void,
 *    and did a bit of KNF style work to make things a bit more
 *    acceptable.  Consider stealing from mutt or enlightenment.
 **************************************************************/

#include <ctype.h>
#include <string.h>

#include "prngd.h"

#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF)

static void 
dopr(char *buffer, size_t maxlen, const char *format, va_list args);

static void 
fmtstr(char *buffer, size_t *currlen, size_t maxlen, char *value, int flags, 
       int min, int max);

static void 
fmtint(char *buffer, size_t *currlen, size_t maxlen, long value, int base, 
       int min, int max, int flags);

static void 
fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
      int min, int max, int flags);

static void
dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c);

/*
 * dopr(): poor man's version of doprintf
 */

/* format read states */
#define DP_S_DEFAULT 0
#define DP_S_FLAGS   1
#define DP_S_MIN     2
#define DP_S_DOT     3
#define DP_S_MAX     4
#define DP_S_MOD     5
#define DP_S_CONV    6
#define DP_S_DONE    7

/* format flags - Bits */
#define DP_F_MINUS 	(1 << 0)
#define DP_F_PLUS  	(1 << 1)
#define DP_F_SPACE 	(1 << 2)
#define DP_F_NUM   	(1 << 3)
#define DP_F_ZERO  	(1 << 4)
#define DP_F_UP    	(1 << 5)
#define DP_F_UNSIGNED 	(1 << 6)

/* Conversion Flags */
#define DP_C_SHORT     1
#define DP_C_LONG      2
#define DP_C_LDOUBLE   3
#define DP_C_LONG_LONG 4

#define char_to_int(p) (p - '0')
#define abs_val(p) (p < 0 ? -p : p)

#ifndef MAX
# define MAX(a,b) (((a)>(b))?(a):(b))
# define MIN(a,b) (((a)<(b))?(a):(b))
#endif

static void 
dopr(char *buffer, size_t maxlen, const char *format, va_list args)
{
	char *strvalue;
	char ch;
	long value;
	long double fvalue;
	int min = 0;
	int max = -1;
	int state = DP_S_DEFAULT;
	int flags = 0;
	int cflags = 0;
	size_t currlen = 0;
  
	ch = *format++;

	while (state != DP_S_DONE) {
		if ((ch == '\0') || (currlen >= maxlen)) 
			state = DP_S_DONE;

		switch(state) {
			case DP_S_DEFAULT:
				if (ch == '%') 
					state = DP_S_FLAGS;
				else 
					dopr_outch(buffer, &currlen, maxlen, ch);
				ch = *format++;
				break;
			case DP_S_FLAGS:
				switch (ch) {
					case '-':
						flags |= DP_F_MINUS;
						ch = *format++;
						break;
					case '+':
						flags |= DP_F_PLUS;
						ch = *format++;
						break;
					case ' ':
						flags |= DP_F_SPACE;
						ch = *format++;
						break;
					case '#':
						flags |= DP_F_NUM;
						ch = *format++;
						break;
					case '0':
						flags |= DP_F_ZERO;
						ch = *format++;
						break;
					default:
						state = DP_S_MIN;
						break;
				}
				break;
			case DP_S_MIN:
				if (isdigit((unsigned char)ch)) {
					min = 10*min + char_to_int (ch);
					ch = *format++;
				} else if (ch == '*') {
					min = va_arg (args, int);
					ch = *format++;
					state = DP_S_DOT;
				} else 
					state = DP_S_DOT;
				break;
			case DP_S_DOT:
				if (ch == '.') {
					state = DP_S_MAX;
					ch = *format++;
				} else 
					state = DP_S_MOD;
				break;
			case DP_S_MAX:
				if (isdigit((unsigned char)ch)) {
					if (max < 0)
						max = 0;
					max = 10*max + char_to_int(ch);
					ch = *format++;
				} else if (ch == '*') {
					max = va_arg (args, int);
					ch = *format++;
					state = DP_S_MOD;
				} else 
					state = DP_S_MOD;
				break;
			case DP_S_MOD:
				switch (ch) {
					case 'h':
						cflags = DP_C_SHORT;
						ch = *format++;
						break;
					case 'l':
						cflags = DP_C_LONG;
						ch = *format++;
						if (ch == 'l') {
							cflags = DP_C_LONG_LONG;
							ch = *format++;
						}
						break;
					case 'q':
						cflags = DP_C_LONG_LONG;
						ch = *format++;
						break;
					case 'L':
						cflags = DP_C_LDOUBLE;
						ch = *format++;
						break;
					default:
						break;
				}
				state = DP_S_CONV;
				break;
			case DP_S_CONV:
				switch (ch) {
					case 'd':
					case 'i':
						if (cflags == DP_C_SHORT) 
							value = va_arg(args, int);
						else if (cflags == DP_C_LONG)
							value = va_arg(args, long int);
						else if (cflags == DP_C_LONG_LONG)
							value = va_arg (args, long long);
						else
							value = va_arg (args, int);
						fmtint(buffer, &currlen, maxlen, value, 10, min, max, flags);
						break;
					case 'o':
						flags |= DP_F_UNSIGNED;
						if (cflags == DP_C_SHORT)
							value = va_arg(args, unsigned int);
						else if (cflags == DP_C_LONG)
							value = va_arg(args, unsigned long int);
						else if (cflags == DP_C_LONG_LONG)
							value = va_arg(args, unsigned long long);
						else
							value = va_arg(args, unsigned int);
						fmtint(buffer, &currlen, maxlen, value, 8, min, max, flags);
						break;
					case 'u':
						flags |= DP_F_UNSIGNED;
						if (cflags == DP_C_SHORT)
							value = va_arg(args, unsigned int);
						else if (cflags == DP_C_LONG)
							value = va_arg(args, unsigned long int);
						else if (cflags == DP_C_LONG_LONG)
							value = va_arg(args, unsigned long long);
						else
							value = va_arg(args, unsigned int);
						fmtint (buffer, &currlen, maxlen, value, 10, min, max, flags);
						break;
					/*FALLTHROUGH*/
					case 'X':
						flags |= DP_F_UP;
					case 'x':
						flags |= DP_F_UNSIGNED;
						if (cflags == DP_C_SHORT)
							value = va_arg(args, unsigned int);
						else if (cflags == DP_C_LONG)
							value = va_arg(args, unsigned long int);
						else if (cflags == DP_C_LONG_LONG)
							value = va_arg(args, unsigned long long);
						else
							value = va_arg(args, unsigned int);
						fmtint(buffer, &currlen, maxlen, value, 16, min, max, flags);
						break;
					case 'f':
						if (cflags == DP_C_LDOUBLE)
							fvalue = va_arg(args, long double);
						else
							fvalue = va_arg(args, double);
						/* um, floating point? */
						fmtfp(buffer, &currlen, maxlen, fvalue, min, max, flags);
						break;
					/*FALLTHROUGH*/
					case 'E':
						flags |= DP_F_UP;
					case 'e':
						if (cflags == DP_C_LDOUBLE)
							fvalue = va_arg(args, long double);
						else
							fvalue = va_arg(args, double);
						break;
					/*FALLTHROUGH*/
					case 'G':
						flags |= DP_F_UP;
					case 'g':
						if (cflags == DP_C_LDOUBLE)
							fvalue = va_arg(args, long double);
						else
							fvalue = va_arg(args, double);
						break;
					case 'c':
						dopr_outch(buffer, &currlen, maxlen, va_arg(args, int));
						break;
					case 's':
						strvalue = va_arg(args, char *);
						if (max < 0) 
							max = maxlen; /* ie, no max */
						fmtstr(buffer, &currlen, maxlen, strvalue, flags, min, max);
						break;
					case 'p':
						strvalue = va_arg(args, void *);
						fmtint(buffer, &currlen, maxlen, (long) strvalue, 16, min, max, flags);
						break;
					case 'n':
						if (cflags == DP_C_SHORT) {
							short int *num;
							num = va_arg(args, short int *);
							*num = (short)currlen;
						} else if (cflags == DP_C_LONG) {
							long int *num;
							num = va_arg(args, long int *);
							*num = currlen;
						} else if (cflags == DP_C_LONG_LONG) {
							long long *num;
							num = va_arg(args, long long *);
							*num = currlen;
						} else {
							int *num;
							num = va_arg(args, int *);
							*num = currlen;
						}
						break;
					case '%':
						dopr_outch(buffer, &currlen, maxlen, ch);
						break;
					case 'w': /* not supported yet, treat as next char */
						ch = *format++;
						break;
					default: /* Unknown, skip */
					break;
				}
				ch = *format++;
				state = DP_S_DEFAULT;
				flags = cflags = min = 0;
				max = -1;
				break;
			case DP_S_DONE:
				break;
			default: /* hmm? */
				break; /* some picky compilers need this */
		}
	}
	if (currlen < maxlen - 1) 
		buffer[currlen] = '\0';
	else 
		buffer[maxlen - 1] = '\0';
}

static void
fmtstr(char *buffer, size_t *currlen, size_t maxlen,
       char *value, int flags, int min, int max)
{
	int padlen, strln;     /* amount to pad */
	int cnt = 0;
  
	if (value == 0) 
		value = "<NULL>";

	for (strln = 0; value[strln]; ++strln); /* strlen */
	padlen = min - strln;
	if (padlen < 0) 
		padlen = 0;
	if (flags & DP_F_MINUS) 
		padlen = -padlen; /* Left Justify */

	while ((padlen > 0) && (cnt < max)) {
		dopr_outch(buffer, currlen, maxlen, ' ');
		--padlen;
		++cnt;
	}
	while (*value && (cnt < max)) {
		dopr_outch(buffer, currlen, maxlen, *value++);
		++cnt;
	}
	while ((padlen < 0) && (cnt < max)) {
		dopr_outch(buffer, currlen, maxlen, ' ');
		++padlen;
		++cnt;
	}
}

/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */

static void 
fmtint(char *buffer, size_t *currlen, size_t maxlen,
       long value, int base, int min, int max, int flags)
{
	unsigned long uvalue;
	char convert[20];
	int signvalue = 0;
	int place = 0;
	int spadlen = 0; /* amount to space pad */
	int zpadlen = 0; /* amount to zero pad */
	int caps = 0;
  
	if (max < 0)
		max = 0;

	uvalue = value;

	if (!(flags & DP_F_UNSIGNED)) {
		if (value < 0) {
			signvalue = '-';
			uvalue = -value;
		} else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
			signvalue = '+';
		else if (flags & DP_F_SPACE)
			signvalue = ' ';
	}
  
	if (flags & DP_F_UP) 
		caps = 1; /* Should characters be upper case? */

	do {
		convert[place++] =
			(caps? "0123456789ABCDEF":"0123456789abcdef")
			[uvalue % (unsigned)base];
		uvalue = (uvalue / (unsigned)base );
	} while (uvalue && (place < 20));
	if (place == 20) 
		place--;
	convert[place] = 0;

	zpadlen = max - place;
	spadlen = min - MAX (max, place) - (signvalue ? 1 : 0);
	if (zpadlen < 0)
		zpadlen = 0;
	if (spadlen < 0)
		spadlen = 0;
	if (flags & DP_F_ZERO) {
		zpadlen = MAX(zpadlen, spadlen);
		spadlen = 0;
	}
	if (flags & DP_F_MINUS) 
		spadlen = -spadlen; /* Left Justifty */


	/* Spaces */
	while (spadlen > 0) {
		dopr_outch(buffer, currlen, maxlen, ' ');
		--spadlen;
	}

	/* Sign */
	if (signvalue) 
		dopr_outch(buffer, currlen, maxlen, signvalue);

	/* Zeros */
	if (zpadlen > 0) {
		while (zpadlen > 0) {
			dopr_outch(buffer, currlen, maxlen, '0');
			--zpadlen;
		}
	}

	/* Digits */
	while (place > 0) 
		dopr_outch(buffer, currlen, maxlen, convert[--place]);
  
	/* Left Justified spaces */
	while (spadlen < 0) {
		dopr_outch (buffer, currlen, maxlen, ' ');
		++spadlen;
	}
}

static long double 
pow10(int exp)
{
	long double result = 1;

	while (exp) {
		result *= 10;
		exp--;
	}
  
	return result;
}

static long 
round(long double value)
{
	long intpart = value;

	value -= intpart;
	if (value >= 0.5)
		intpart++;

	return intpart;
}

static void 
fmtfp(char *buffer, size_t *currlen, size_t maxlen, long double fvalue, 
      int min, int max, int flags)
{
	char iconvert[20];
	char fconvert[20];
	int signvalue = 0;
	int iplace = 0;
	int fplace = 0;
	int padlen = 0; /* amount to pad */
	int zpadlen = 0; 
	int caps = 0;
	long intpart;
	long fracpart;
	long double ufvalue;
  
	/* 
	 * AIX manpage says the default is 0, but Solaris says the default
	 * is 6, and sprintf on AIX defaults to 6
	 */
	if (max < 0)
		max = 6;

	ufvalue = abs_val(fvalue);

	if (fvalue < 0)
		signvalue = '-';
	else if (flags & DP_F_PLUS)  /* Do a sign (+/i) */
		signvalue = '+';
	else if (flags & DP_F_SPACE)
		signvalue = ' ';

	intpart = ufvalue;

	/* 
	 * Sorry, we only support 9 digits past the decimal because of our 
	 * conversion method
	 */
	if (max > 9)
		max = 9;

	/* We "cheat" by converting the fractional part to integer by
	 * multiplying by a factor of 10
	 */
	fracpart = round((pow10 (max)) * (ufvalue - intpart));

	if (fracpart >= pow10 (max)) {
		intpart++;
		fracpart -= pow10 (max);
	}

	/* Convert integer part */
	do {
		iconvert[iplace++] =
		  (caps? "0123456789ABCDEF":"0123456789abcdef")[intpart % 10];
		intpart = (intpart / 10);
	} while(intpart && (iplace < 20));
	if (iplace == 20) 
		iplace--;
	iconvert[iplace] = 0;

	/* Convert fractional part */
	do {
		fconvert[fplace++] =
		  (caps? "0123456789ABCDEF":"0123456789abcdef")[fracpart % 10];
		fracpart = (fracpart / 10);
	} while(fracpart && (fplace < 20));
	if (fplace == 20) 
		fplace--;
	fconvert[fplace] = 0;

	/* -1 for decimal point, another -1 if we are printing a sign */
	padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 
	zpadlen = max - fplace;
	if (zpadlen < 0)
		zpadlen = 0;
	if (padlen < 0) 
		padlen = 0;
	if (flags & DP_F_MINUS) 
		padlen = -padlen; /* Left Justifty */

	if ((flags & DP_F_ZERO) && (padlen > 0)) {
		if (signvalue) {
			dopr_outch(buffer, currlen, maxlen, signvalue);
			--padlen;
			signvalue = 0;
		}
		while (padlen > 0) {
			dopr_outch(buffer, currlen, maxlen, '0');
			--padlen;
		}
	}
	while (padlen > 0) {
		dopr_outch(buffer, currlen, maxlen, ' ');
		--padlen;
	}
	if (signvalue) 
		dopr_outch(buffer, currlen, maxlen, signvalue);

	while (iplace > 0) 
		dopr_outch(buffer, currlen, maxlen, iconvert[--iplace]);

	/*
	 * Decimal point.  This should probably use locale to find the correct
	 * char to print out.
	 */
	dopr_outch(buffer, currlen, maxlen, '.');

	while (fplace > 0) 
		dopr_outch(buffer, currlen, maxlen, fconvert[--fplace]);

	while (zpadlen > 0) {
		dopr_outch(buffer, currlen, maxlen, '0');
		--zpadlen;
	}

	while (padlen < 0) {
		dopr_outch(buffer, currlen, maxlen, ' ');
		++padlen;
	}
}

static void 
dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c)
{
	if (*currlen < maxlen)
		buffer[(*currlen)++] = c;
}
#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */

#ifndef HAVE_VSNPRINTF
int 
vsnprintf(char *str, size_t count, const char *fmt, va_list args)
{
	str[0] = 0;
	dopr(str, count, fmt, args);

	return(strlen(str));
}
#endif /* !HAVE_VSNPRINTF */

#ifndef HAVE_SNPRINTF
int 
snprintf(char *str,size_t count,const char *fmt,...)
{
	va_list ap;

	va_start(ap, fmt);
	(void) vsnprintf(str, count, fmt, ap);
	va_end(ap);

	return(strlen(str));
}

#ifdef TEST_SNPRINTF
int 
main(void)
{
#define LONG_STRING 1024
	char buf1[LONG_STRING];
	char buf2[LONG_STRING];
	char *fp_fmt[] = {
		"%-1.5f",
		"%1.5f",
		"%123.9f",
		"%10.5f",
		"% 10.5f",
		"%+22.9f",
		"%+4.9f",
		"%01.3f",
		"%4f",
		"%3.1f",
		"%3.2f",
		NULL
	};
	double fp_nums[] = { 
		-1.5, 
		134.21, 
		91340.2, 
		341.1234, 
		0203.9, 
		0.96, 
		0.996, 
		0.9996, 
		1.996, 
		4.136, 
		0
	};
	char *int_fmt[] = {
		"%-1.5d",
		"%1.5d",
		"%123.9d",
		"%5.5d",
		"%10.5d",
		"% 10.5d",
		"%+22.33d",
		"%01.3d",
		"%4d",
		"%lld",
		"%qd",
		NULL
	};
	long long int_nums[] = { -1, 134, 91340, 341, 0203, 0, 9999999 };
	int x, y;
	int fail = 0;
	int num = 0;

	printf("Testing snprintf format codes against system sprintf...\n");

	for (x = 0; fp_fmt[x] != NULL ; x++) {
		for (y = 0; fp_nums[y] != 0 ; y++) {
			snprintf(buf1, sizeof (buf1), fp_fmt[x], fp_nums[y]);
			sprintf (buf2, fp_fmt[x], fp_nums[y]);
			if (strcmp (buf1, buf2)) {
				printf("snprintf doesn't match Format: %s\n\t"
                                       "snprintf = %s\n\tsprintf  = %s\n", 
					fp_fmt[x], buf1, buf2);
				fail++;
			}
			num++;
		}
	}
	for (x = 0; int_fmt[x] != NULL ; x++) {
		for (y = 0; int_nums[y] != 0 ; y++) {
			snprintf(buf1, sizeof (buf1), int_fmt[x], int_nums[y]);
			sprintf(buf2, int_fmt[x], int_nums[y]);
			if (strcmp (buf1, buf2)) {
				printf("snprintf doesn't match Format: %s\n\t"
				       "snprintf = %s\n\tsprintf  = %s\n", 
					int_fmt[x], buf1, buf2);
				fail++;
			}
			num++;
		}
	}
	printf("%d tests failed out of %d.\n", fail, num);
	return(0);
}
#endif /* SNPRINTF_TEST */

#endif /* !HAVE_SNPRINTF */


===== close_on_exec.c =====
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include "prngd.h"

/*
 * Set or remove "close on exec" flag for file descriptor.'
 * Inspired by close_on_exec() function in Wietse Venema's Postfix.
 * On failure, there is nothing left what we can do.
 */
#define PATTERN FD_CLOEXEC

void close_on_exec(int fd, int on)
{
  int flags;

  if ((flags = fcntl(fd, F_GETFD, 0)) == -1) {
    error_fatal("fcntl() failed to get file descriptor flags", errno);
    exit(EXIT_FAILURE);
  }
  if (fcntl(fd, F_SETFD, on ? flags | PATTERN : flags & ~PATTERN) == -1) {
    error_fatal("fcntl() failed to set file descriptor flags", errno);
    exit(EXIT_FAILURE);
  }
}


===== conffile.c =====
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

#include "prngd.h"

#define WHITESPACE " \t\n"

void parse_configfile(const char *cmdpath, entropy_source_t **entropy_source_p)
{
  FILE *conf;
  int linenum;
  int num_cmds = 64, cur_cmd = 0;
  int arg;
  char msg_buf[1024];
  double est;
  char buffer[1024], cmd[1024], fullpath[1024], *cp;
  entropy_source_t *entropy_source;

  entropy_source = (entropy_source_t*) my_malloc(num_cmds *
  	sizeof(entropy_source_t));

  if (!(conf = fopen(cmdpath, "r"))) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
    	"could not open command-sourcefile %.100s", cmdpath);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, errno);
    exit(EXIT_FAILURE);
  }
 
  linenum = 0;
  while (fgets(buffer, 1023, conf)) {
    linenum++;
    cp = buffer + strspn(buffer, WHITESPACE);
    if ((*cp == '\0') || (*cp == '#'))
	continue;

    if (*cp != '"') {
      (void)snprintf(msg_buf, 1024, "Bad entropy command %.100s:%d\n", cmdpath,
      	linenum);
      msg_buf[sizeof(msg_buf) - 1] = '\0';
      error_error(msg_buf, 0);
      continue;
    }

    cp = strtok(cp, "\"");
    if (cp == NULL) {
      (void)snprintf(msg_buf, 1024, "missing or bad command string, %.100s:%d -- ignored\n",
              cmdpath, linenum);
      msg_buf[sizeof(msg_buf) - 1] = '\0';
      error_error(msg_buf, 0);
      continue;
    }
    (void)strncpy(cmd, cp, sizeof(cmd));
    cmd[sizeof(cmd)-1] = '\0';

    if ((cp = strtok(NULL, WHITESPACE)) == NULL) {
      (void)snprintf(msg_buf, 1024, "missing command cmdpath, %.100s:%d -- ignored",
	      cmdpath, linenum);
      msg_buf[sizeof(msg_buf) - 1] = '\0';
      error_error(msg_buf, 0);
      continue;
    }

    /* did configure mark this as dead? */
    if (strncmp("undef", cp, 5) == 0)
      continue;
    (void)strncpy(fullpath, cp, sizeof(fullpath));
    fullpath[sizeof(fullpath)-1] = '\0';

    /* third token, entropy rate estimate for this command */
    if ((cp = strtok(NULL, WHITESPACE)) == NULL) {
      (void)snprintf(msg_buf, 1024, "missing entropy estimate, %.100s:%d -- ignored",
	      cmdpath, linenum);
      msg_buf[sizeof(msg_buf) - 1] = '\0';
      error_error(msg_buf, 0);
      continue;
    }
    est = atof(cp);

    /* end of line */
    if ((cp = strtok(NULL, WHITESPACE)) != NULL) {
      (void)snprintf(msg_buf, 1024, "garbage at end of %.100s:%d -- ignored",
	      cmdpath, linenum);
      msg_buf[sizeof(msg_buf) - 1] = '\0';
      error_error(msg_buf, 0);
      continue;
    }

    /*
     * Now that the line is scanned in, fit it into the entropy_cmd table.
     */

    entropy_source[cur_cmd].path = malloc(strlen(fullpath) + 1);
    if (entropy_source[cur_cmd].path == NULL) {
	error_fatal("could not allocate entropy-command-table", errno);
	exit(EXIT_FAILURE);
    }
    (void)strcpy(entropy_source[cur_cmd].path, fullpath);

    entropy_source[cur_cmd].cmdstring = malloc(strlen(cmd) + 1);
    if (entropy_source[cur_cmd].cmdstring == NULL) {
	error_fatal("could not allocate entropy-command-table", errno);
	exit(EXIT_FAILURE);
    }
    (void)strcpy(entropy_source[cur_cmd].cmdstring, cmd);

    /* split the command args */
    cp = strtok(cmd, WHITESPACE);
    arg = 0;
    do {
      char *s = malloc(strlen(cp) + 1);
      if (!s) {
	error_fatal("could not allocate entropy-command-table", errno);
	exit(EXIT_FAILURE);
      }
      (void)strncpy(s, cp, strlen(cp) + 1);
      entropy_source[cur_cmd].args[arg] = s;
      arg++;
    } while ((arg < 5) && (cp = strtok(NULL, WHITESPACE)));
    while (arg < 5)
      entropy_source[cur_cmd].args[arg++] = NULL;

    if (strtok(NULL, WHITESPACE)) {
	(void)snprintf(msg_buf, 1024, "ignored extra command elements (max 5), %.100s:%d",
               cmdpath, linenum);
	msg_buf[sizeof(msg_buf) - 1] = '\0';
      	error_error(msg_buf, 0);
    }

    entropy_source[cur_cmd].rate = est;
    /* Initialise other values */
    entropy_source[cur_cmd].sticky_badness = 1;
    
    cur_cmd++;

    /* If we've filled the array, reallocate it twice the size */
    /* Do this now because even if this we're on the last command,
     * we need another slot to mark the last entry */
    if (cur_cmd == num_cmds) {
      num_cmds *= 2;
      entropy_source = realloc(entropy_source,
			       num_cmds * sizeof(entropy_source_t));
      if (!entropy_source) { 
	error_fatal("could not allocate entropy-command-table", errno);
	exit(EXIT_FAILURE);
      }
    }


  }
  (void)fclose(conf);

  /*
   * Zero out the last entry in the table and resize the array to save some
   * memory, evn though it shouldn't be much.
   */
  (void)memset(entropy_source + cur_cmd, 0, sizeof(entropy_source_t));

  entropy_source = realloc(entropy_source,
			   (cur_cmd + 1)*sizeof(entropy_source_t));
  if (!entropy_source) { 
	error_fatal("could not allocate entropy-command-table", errno);
	exit(EXIT_FAILURE);
  }

  *entropy_source_p = entropy_source;
}


===== config.h =====

#ifdef NCR_MP_RAS2
typedef int ssize_t;
#define HAVE_GETRUSAGE
#define O_RSYNC		0
#define SOCKLEN_T	int
#define PATH_TMP	"/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD	"/etc/passwd"
#define PATH_WTMP	"/var/adm/wtmp"
#define PATH_UTMP	"/var/adm/utmp"
#define PATH_SYSLOG	"/etc/.osm"
#define PATH_MAILLOG	"/etc/.osm"
#define rlimit ucb_rlimit
#include <../ucbinclude/sys/resource.h>
#undef rlimit
#define _SYS_RESOURCE_H
#endif

#ifdef NCR_MP_RAS3
#define HAVE_DAEMON
#define HAVE_GETRUSAGE
#define O_RSYNC		0
#define SOCKLEN_T	size_t
#define PATH_TMP	"/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD	"/etc/passwd"
#define PATH_WTMP	"/var/adm/wtmp"
#define PATH_UTMP	"/var/adm/utmp"
#define PATH_SYSLOG	"/etc/.osm"
#define PATH_MAILLOG	"/etc/.osm"
#endif

#ifdef UNIXWARE1
#define DONT_CHMOD_SOCKET
#define O_RSYNC		0
#define SOCKLEN_T       int
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmpx"
#define PATH_UTMP       "/var/adm/utmpx"
#define PATH_SYSLOG	"/etc/.osm"
#define PATH_MAILLOG	"/var/mail/:log"
#endif

#ifdef LINUX2
#define HAVE_DAEMON
#define HAVE_GETRUSAGE
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#define SOCKLEN_T	socklen_t
#define PATH_TMP	"/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD	"/etc/passwd"
#define PATH_WTMP	"/var/log/wtmp"
#define PATH_UTMP	"/var/run/utmp"
#define PATH_SYSLOG	"/var/log/messages"
#define PATH_MAILLOG	"/var/log/mail"
#endif

#if defined(HPUX10) || defined(HPUX11)
#define HAVE_GETRUSAGE
#ifdef HPUX11
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#endif
#define SOCKLEN_T	int
#define PATH_TMP	"/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD	"/etc/passwd"
#define PATH_WTMP	"/var/adm/wtmp"
#define PATH_UTMP	"/etc/utmp"
#define PATH_SYSLOG	"/var/adm/syslog/syslog.log"
#define PATH_MAILLOG	"/var/adm/syslog/mail.log"
#endif

#ifdef TRU64
#define HAVE_GETRUSAGE
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#define SOCKLEN_T	size_t
#define PATH_TMP	"/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD	"/etc/passwd"
#define PATH_WTMP	"/var/adm/wtmp"
#define PATH_UTMP	"/var/adm/utmp"
#define PATH_SYSLOG	"/var/adm/syslog.dated/current/daemon.log"
#define PATH_MAILLOG	"/var/adm/syslog.dated/current/mail.log"
#endif

#ifdef OSF1
#define HAVE_GETRUSAGE
#define SOCKLEN_T	size_t
#define PATH_TMP	"/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD	"/etc/passwd"
#define PATH_WTMP	"/var/adm/wtmp"
#define PATH_UTMP	"/var/adm/utmp"
#define PATH_SYSLOG	"/var/adm/syslog.dated/current/daemon.log"
#define PATH_MAILLOG	"/var/adm/syslog.dated/current/mail.log"
#endif

#ifdef SOLARIS
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#define HAVE_GETRUSAGE
#define SOCKLEN_T       socklen_t
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmpx"
#define PATH_UTMP       "/var/adm/utmpx"
#define PATH_SYSLOG     "/var/adm/messages"
#endif

#ifdef SOLARIS26
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#define HAVE_GETRUSAGE
#define SOCKLEN_T       size_t
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmpx"
#define PATH_UTMP       "/var/adm/utmpx"
#define PATH_SYSLOG     "/var/adm/messages"
#endif

#ifdef SOLARIS_251
#define HAVE_GETRUSAGE
#define SOCKLEN_T       int
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmpx"
#define PATH_UTMP       "/var/adm/utmpx"
#define PATH_SYSLOG     "/var/adm/messages"
#define IS_UNIX_SOCKET(m)  (S_ISSOCK(m) || S_ISFIFO(m))
#include <sys/resource.h>
int getrusage(int who, struct rusage *rusage);
#endif

#ifdef SOLARIS_OLD
#define HAVE_GETRUSAGE
#define SOCKLEN_T       int
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmp"
#define PATH_UTMP       "/var/adm/utmp"
#define PATH_SYSLOG     "/var/adm/messages"
#endif

#ifdef MACOSX
#define HAVE_GETRUSAGE
/* not supported */
#define O_RSYNC 0
#define O_SYNC 0
/* in ansi string.h but undefined in -posix */
#define bzero(b,len) memset(b,0,len)
#ifndef FD_CLOEXEC
#define FD_CLOEXEC	1
#endif
#define PATH_TMP        "/private/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/private/var/log/wtmp"
#define PATH_UTMP       "/private/var/run/utmp"
#define PATH_SYSLOG     "/private/var/log/system.log"
#endif

#ifdef FREEBSD
#define HAVE_GETRUSAGE
/* not yet supported */
#define O_RSYNC	0
#ifndef O_SYNC
#define O_SYNC	O_FSYNC
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/log/wtmp"
#define PATH_UTMP       "/var/run/utmp"
#define PATH_SYSLOG     "/var/log/messages"
#endif

#endif

#ifdef NEXTSTEP
#define HAVE_GETRUSAGE
/* not supported */
#define SA_RESTART 0
#define O_RSYNC 0
/* replace with corresponding bsd call */
#define setsid() setpgrp(0, getpid())
/* in ansi string.h but undefined in -posix */
#define bzero(b,len) memset(b,0,len)
#ifndef FD_CLOEXEC
#define FD_CLOEXEC	1
#endif
#define PATH_TMP        "/private/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/private/adm/wtmp"
#define PATH_UTMP       "/private/etc/utmp"
#define PATH_SYSLOG     "/private/adm/messages"
#endif

#ifdef IRIX62
#define HAVE_GETRUSAGE
#define SOCKLEN_T       int
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmpx"
#define PATH_UTMP       "/var/adm/utmpx"
#define PATH_SYSLOG     "/var/adm/SYSLOG"
#endif

#ifdef IRIX65
#define HAVE_GETRUSAGE
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#define SOCKLEN_T       int
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmpx"
#define PATH_UTMP       "/var/adm/utmpx"
#define PATH_SYSLOG     "/var/adm/SYSLOG"
#endif

#ifdef AIX32
extern void closelog();
#define HAVE_GETRUSAGE
#define NEED_SYS_SELECT_H
#define SOCKLEN_T       int
#define O_RSYNC         0
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmp"
#define PATH_UTMP       "/etc/utmp"
#define PATH_SYSLOG     "/var/spool/mqueue/syslog"
#endif

#ifdef AIX43
#define HAVE_GETRUSAGE
#define SOCKLEN_T	socklen_t
#define PATH_TMP	"/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD	"/etc/passwd"
#define PATH_WTMP	"/var/adm/wtmp"
#define PATH_UTMP	"/etc/utmp"
#define PATH_SYSLOG	"/var/adm/messages"
#define PATH_MAILLOG	"/var/spool/mqueue/syslog"
#endif

#ifdef AIX41
#define HAVE_GETRUSAGE
#define NEED_SYS_SELECT_H
#define SOCKLEN_T	int
#define O_RSYNC		0
#define PATH_TMP	"/tmp"
#define PATH_VAR_TMP	"/var/tmp"
#define PATH_PASSWD	"/etc/passwd"
#define PATH_WTMP	"/var/adm/wtmp"
#define PATH_UTMP	"/etc/utmp"
#define PATH_SYSLOG	"/var/adm/messages"
#define PATH_MAILLOG	"/var/spool/mqueue/syslog"
#endif

#ifdef AIX51
#define HAVE_GETRUSAGE
#define SOCKLEN_T     socklen_t
#define PATH_TMP      "/tmp"
#define PATH_VAR_TMP  "/var/tmp"
#define PATH_PASSWD   "/etc/passwd"
#define PATH_WTMP     "/var/adm/wtmp"
#define PATH_UTMP     "/etc/utmp"
#define PATH_SYSLOG   "/var/log/messages"
#endif

#if defined(ULTRIX)
typedef int     ssize_t;
extern void closelog(void);
#include <sys/syslog.h>
#define HAVE_GETRUSAGE
#define SOCKLEN_T       int
#define SA_RESTART      0
#define O_RSYNC         0
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmp"
#define PATH_UTMP       "/etc/utmp"
#define PATH_SYSLOG     "/var/spool/mqueue/syslog"
#endif

#ifdef UNIXWARE7
#define HAVE_GETRUSAGE
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#define SOCKLEN_T	size_t
#define O_RSYNC		0
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmp"
#define PATH_UTMP       "/etc/utmp"
#define PATH_SYSLOG     "/var/adm/syslog"
/*
 * Strange thing on Unixware 7, sockets manifest itself as FIFOs
 * John Hughes <john@Calva.COM>
 */
#define IS_UNIX_SOCKET(m)  (S_ISSOCK(m) || S_ISFIFO(m))
#endif

#ifdef OpenUNIX8
#define HAVE_GETRUSAGE
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#define SOCKLEN_T	size_t
#define O_RSYNC		0
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmp"
#define PATH_UTMP       "/etc/utmp"
#define PATH_SYSLOG     "/var/adm/syslog"
#define IS_UNIX_SOCKET(m)  (S_ISSOCK(m) || S_ISFIFO(m))
#endif

#ifdef SCO
#ifdef SCO3
typedef	int	ssize_t;
extern void closelog(void);
#define ftruncate	chsize
#define SA_RESTART	0
#define SOMAXCONN 5
#define NO_UNIX_SOCKET
#else
#define HAVE_GETRUSAGE
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#endif
#define SOCKLEN_T	int
#define O_RSYNC		0
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmp"
#define PATH_UTMP       "/etc/utmp"
#define PATH_SYSLOG     "/var/adm/syslog"
#ifdef S_ISSOCK
#define IS_UNIX_SOCKET(m)  (S_ISSOCK(m) || S_ISFIFO(m))
#else
#define IS_UNIX_SOCKET(m)  S_ISFIFO(m)
#endif
#endif

#ifdef SUNOS4
#define HAVE_GETRUSAGE
#define SOCKLEN_T	int
#define SA_RESTART	0
#define O_RSYNC		0
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmp"
#define PATH_UTMP       "/etc/utmp"
#define PATH_SYSLOG     "/var/adm/messages"
#define PATH_MAILLOG    "/var/log/syslog"

typedef int ssize_t;

#ifndef EXIT_SUCCESS
#define	EXIT_SUCCESS	0
#endif

#define difftime(time1,time0) ((double)(time1) - (double)(time0))
#define memmove(dst,src,len) bcopy((char *)(src), (char *)(dst), (int)(len))

extern char *sys_errlist[];

#define strerror(n) (sys_errlist[(n)])

/* explicit declaration of functions */

#include <memory.h>

extern int accept(int, struct sockaddr *, int *);
extern int bind(int, struct sockaddr *, int);
extern void bcopy(char *, char *, int);
extern void bzero(char *, int);
extern int connect(int, struct sockaddr *, int);
extern int fchmod(int, int);
extern int fclose(/* FILE * */);
extern int fprintf(/* FILE *, const char *, ... */);
extern int getrlimit(/* int, struct rlimit * */);
extern int getrusage(/* int, struct rusage * */);
extern int ftruncate(int, off_t);
extern int gettimeofday(struct timeval *, struct timezone *);
extern int listen(int, int);
extern void perror(char *);
extern int remove(const char *);
extern int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
extern int setsockopt(/* int, int, int, char *, int */);
extern int shutdown(int, int);
extern int socket(int, int, int);
extern int sscanf(const char *, const char *, ...);
extern long time(long *);
extern int on_exit(void (*)(), caddr_t arg);
extern openlog(const char *, int, int);
extern syslog(int, const char *, ...);
extern closelog(void);
#endif

#ifdef RELIANTUNIX
#define O_RSYNC		0
#undef HAVE_SNPRINTF
#undef HAVE_VSNPRINTF
#define HAVE_GETRUSAGE
#define SOCKLEN_T       size_t
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/var/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/var/adm/wtmpx"
#define PATH_UTMP       "/var/adm/utmpx"
#define PATH_SYSLOG     "/var/adm/log/messages"
#define IS_UNIX_SOCKET(m)  (S_ISSOCK(m) || S_ISFIFO(m))
#endif

#ifdef UNICOS
#define HAVE_DAEMON
#define HAVE_SNPRINTF
#define HAVE_VSNPRINTF
#define O_RSYNC         0
#define SA_RESTART 0
#define PATH_TMP        "/tmp"
#define PATH_VAR_TMP    "/usr/tmp"
#define PATH_PASSWD     "/etc/passwd"
#define PATH_WTMP       "/etc/wtmp"
#define PATH_UTMP       "/etc/utmp"
/* System logging on Unicos is different, so the following settings probably
 * are not perfect. */
#define PATH_SYSLOG "/usr/adm/syslog/daylog"
#define PATH_MAILLOG "/usr/spool/mqueue/syslog"
#endif

#ifdef TANDEM
#define O_RSYNC         0
#define SA_RESTART      0
#define IS_UNIX_SOCKET(m)  (S_ISSOCK(m) || S_ISFIFO(m))
#ifdef HAVE_FLOSS_H
#include <floss.h>
#endif
#endif

#ifndef RANDSAVENAME
#define RANDSAVENAME	"/etc/prngd-seed"
#endif
#ifndef CONFIGFILE
#define CONFIGFILE	"/etc/prngd.conf"
#endif
#ifndef SOCKETMODE
#define SOCKETMODE	0777
#endif


#define BITS_PER_BYTE	8

/*
 * If not available, we cannot perform the check and will always succeed.
 */
#ifndef IS_UNIX_SOCKET
# ifdef S_ISSOCK
#  define IS_UNIX_SOCKET(m)	(S_ISSOCK(m))
# else
#  define IS_UNIX_SOCKET(m)	(1)
# endif
#else
# ifndef S_ISSOCK
#  define S_ISSOCK		(1)
# endif
#endif

/*
 * Some platforms don't have the SHUT_* macros
 */
#ifndef SHUT_RDWR
#define SHUT_RDWR	2
#endif

/*
 * If SOCKLEN_T is not defined, use a default.
 */
#ifndef SOCKLEN_T
#define SOCKLEN_T	int
#endif

/*
 * The pool size of the OpenSSL PRNG
 */
#define PRNGD_STATE_SIZE	(1024 * 4)

#ifndef SEED_STAT_INTERVAL
#define SEED_STAT_INTERVAL	17
#endif
#ifndef SEED_EXT_INTERVAL
#define SEED_EXT_INTERVAL	49
#endif

#define MAX_GATHERER_BYTES	100000

/*
 * Define the minimum ENTROPY_NEEDED to be 256, as one can retrieve 255 bytes
 * with on egd-query.
 */
#ifndef ENTROPY_NEEDED
#define ENTROPY_NEEDED		256
#endif

/*
 * Define the minimum of entropy we want to have in the pool on a regular
 * basis. If we come below this threshold, the gatherer processes are fired
 * up continously until we come back over the threshold.
 */
#ifndef THRESHOLD
#define THRESHOLD		4
#endif
#define ENTROPY_THRESHOLD	(ENTROPY_NEEDED * BITS_PER_BYTE * THRESHOLD)

/*
 * We will only accept a certain limit of open connections. We define a
 * reserve of open filedescriptors since we want to be able to open the
 * config file for re-reading and since from startup descriptors may
 * still be open.
 */
#ifndef OPEN_FD_RESERVE
#define OPEN_FD_RESERVE		10
#endif


===== error_handlers.c =====
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

#include "prngd.h"

void*
my_malloc(size_t size)
{
	void* buf = NULL;
	buf = malloc(size);

	if (buf == NULL) {
		error_fatal("malloc() failed", errno);
		exit(EXIT_FAILURE);
	}
	return buf;
}


int
my_pipe(int filedes[2])
{
	int rv;
	rv = pipe(filedes);

	if (rv == -1) {
		error_error("pipe() failed", errno);
	}
	return rv;
}


void
my_dup2(int fd1, int fd2)
{
	int rv;
	rv = dup2(fd1, fd2);

	if (rv == -1) {
		error_error("dup2() failed", errno);
	}
}


void
my_gettimeofday(struct timeval* tp, void* null)
{
	int rv;
	rv = gettimeofday(tp, null);

	if (rv == -1) {
		error_error("gettimeofday() failed", errno);
	}
}


void
my_shutdown(int s, int how)
{
	int rv;
	rv = shutdown(s, how);

	if (rv == -1) {
#ifdef	ENOTCONN
	    if (errno != ENOTCONN)
#endif
		error_error("shutdown() failed", errno);
	}
}


===== error_log.c =====
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>

#include "prngd.h"


/* functions that are only used by this module */
static void error_syslog(int, const char *, int);
static void initialise_syslog(void);


/* a buffer that is used to copy the message given by the user and and
   message from errno if it is also provided. This is so malloc() doesn't
   have to by relied upon at a later stage. */
#define MSG_BUF_SIZE 1024
static char msg_buf[MSG_BUF_SIZE];

/* indicates if openlog(3) has been called yet */
static int syslog_opened = 0;


static void
initialise_syslog(void)
{
	int rv;

	openlog("prngd", LOG_PID|LOG_CONS|LOG_NOWAIT, SYSLOG_FACILITY);
#ifdef SUNOS4
	rv = on_exit((void (*)()) closelog, NULL);
#else
	rv = atexit(closelog);
#endif

	if (rv != 0) {
#ifdef SUNOS4
		perror("prngd: failed to register closelog(3) with on_exit(3)");
#else
		perror("prngd: failed to register closelog(3) with atexit(3)");
#endif
	}
	else {
		syslog_opened = 1;
	}
}


static void
error_syslog(int priority, const char* msg, int my_errno)
{
	char* errno_msg = NULL;
	int user_msg_size;
	int buffer_left;

	if (! syslog_opened) {
		initialise_syslog();
	}

	user_msg_size = strlen(msg);

	/* if we have errno change it to a error string if there will be
	   enough room in msg_buf to copy the user message and atleast some
	   of the errno msg */
	if (my_errno != 0 && user_msg_size < MSG_BUF_SIZE) {
		errno_msg = strerror(my_errno);
	}

	/* it is possible that errno was out of range */
	if (errno_msg != NULL) {

		/* 1 char for newline and 2 for ": " */
		buffer_left = sizeof(msg_buf) - user_msg_size - 3;
		(void)strncpy(msg_buf, msg, user_msg_size);
		(void)strncpy(&(msg_buf[user_msg_size]), ": ", 3);
		(void)strncpy(&(msg_buf[user_msg_size + 2]), errno_msg,
			buffer_left);
		msg_buf[sizeof(msg_buf) - 1] = '\0';
		syslog(priority, msg_buf);
		(void)fprintf(stderr, "%s\n", msg_buf);
	}
	else {
		syslog(priority, msg);
		(void)fprintf(stderr, "%s\n", msg);
	}
}


void
error_fatal(const char* msg, int my_errno)
{
	error_syslog(LOG_ALERT, msg, my_errno);
}


void
error_error(const char* msg, int my_errno)
{
	error_syslog(LOG_ERR, msg, my_errno);
}


void
error_notice(const char* msg, int my_errno)
{
	error_syslog(LOG_NOTICE, msg, my_errno);
}


===== non_blocking.c =====
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include "prngd.h"

/*
 * Set or remove "non_blocking" flag for file descriptor.'
 * Inspired by non_blocking() function in Wietse Venema's Postfix.
 * On failure, there is nothing left what we can do.
 */
#ifdef FNDELAY
#define PATTERN FNDELAY
#else
#define PATTERN O_NONBLOCK
#endif

void non_blocking(int fd, int on)
{
  int flags;

  if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
    error_fatal("fcntl() failed to get file descriptor flags", errno);
    exit(EXIT_FAILURE);
  }
  if (fcntl(fd, F_SETFL, on ? flags | PATTERN : flags & ~PATTERN) == -1) {
    error_fatal("fnctl() failed to set file descriptor flags", errno);
    exit(EXIT_FAILURE);
  }
}


===== obtain_limit.c =====
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
#include <unistd.h>
#include <errno.h>

#include "prngd.h"

#ifdef NEED_SYS_SELECT_H
#include <sys/select.h>
#endif /* NEED_SYS_SELECT_H */

/*
 * Try to obtain the maximum allowed number of open files.
 * Compare with FD_SETSIZE and return whatever is smaller.
 * Partly inspired by open_limit() function in Wietse Venema's Postfix.
 */
#ifndef RLIMIT_NOFILE
#ifdef RLIMIT_OFILE
#define RLIMIT_NOFILE RLIMIT_OFILE
#endif
#endif

int obtain_limit(void)
{
    int limit = -1;
#ifdef RLIMIT_NOFILE
    struct rlimit rl;
#endif

#ifdef RLIMIT_NOFILE
    if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
	error_error("getrlimit() failed", errno);
        return (-1);
    }
    limit = rl.rlim_cur;
#endif

#ifndef RLIMIT_NOFILE
    limit = getdtablesize();
#endif

    if (limit> FD_SETSIZE)
      limit = FD_SETSIZE;

    return (limit);

}


===== prngd.c =====
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <assert.h>
#include <syslog.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>

#include "prngd.h"

static int randsavefd = -1;
static int pidfilefd = -1;
char *pidfile = NULL;
int debug = 0;
int fg = 0;

int devnull = -1;

int limit_openfd = 0;
int count_openfd = 0;

static void write_seedfile(void);
static void open_pidfile(const char *pidfilename)
{
  char msg_buf[1024];

  remove(pidfilename);
  pidfilefd = open(pidfilename, O_WRONLY | O_CREAT, 400);
  if (pidfilefd < 0)
  {
    (void)snprintf(msg_buf, sizeof(msg_buf),
	"could not open %s: %s\n", pidfilename, strerror(errno));
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, 0);
    exit(EXIT_FAILURE);
  }
  close_on_exec(pidfilefd, 1);
}


static void open_seedfile(const char *seedfile)
{
  int bytes, bytes_read_total;
  unsigned char buffer[PRNGD_STATE_SIZE];
  char msg_buf[1024];

  randsavefd = open(seedfile, O_RDWR | O_CREAT | O_SYNC | O_RSYNC, 400);
  if (randsavefd < 0)
  {
    (void)snprintf(msg_buf, sizeof(msg_buf),
	"could not open %s: %s\n", seedfile, strerror(errno));
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, 0);
    exit(EXIT_FAILURE);
  }
  close_on_exec(randsavefd, 1);

  /*
   * The contents of the seedfile may be sensitive, since we start seeding
   * from the file.
   */
  if (chmod(seedfile, S_IRUSR | S_IWUSR) < 0)
  {
    (void)snprintf(msg_buf, sizeof(msg_buf),
	"Could not chmod %s: %s\n", seedfile, strerror(errno));
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, 0);
    exit(EXIT_FAILURE);
  }

  /*
   * Do some initial seeding stuff to pre-stir the PRNG.
   */
  seed_internal(NULL);

  /*
   * Now read as much from the file as we can get. 
   */
  bytes_read_total = 0;
  while ((bytes = read(randsavefd, buffer, PRNGD_STATE_SIZE)) > 0)
  {
    rand_add(buffer, bytes, 0.0);
    bytes_read_total += bytes;
  }
  if (bytes < 0)
  {
    (void)snprintf(msg_buf, sizeof(msg_buf),
	"Error reading %s: %s\n", seedfile, strerror(errno));
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, 0);
    exit(EXIT_FAILURE);
  }

  /*
   * Done, let's stir around some more
   */
  seed_internal(NULL);

  if (debug)
    (void)fprintf(stderr, "Read %d bytes\n", bytes_read_total);
  /*
   * Finally, account for the bytes read. We don't know how much entropy
   * was in the bytes we've read, so we only account for the minimum needed
   * and have PRNGD do the rest. If not enough bytes are read, only account
   * the bytes. Don't care for the contents of the buffer, it doesn't hurt
   * to stir the pool.
   */
  if (bytes_read_total > ENTROPY_NEEDED)
    rand_add(buffer, PRNGD_STATE_SIZE, ENTROPY_NEEDED);
  else
    rand_add(buffer, PRNGD_STATE_SIZE, bytes_read_total);

  /*
   * Ok, we don't want to reuse the same seed again, so we will immediately
   * replace the contents of the seed-file.
   */
  write_seedfile();
}

static void write_seedfile(void)
{
  int bytes;
  unsigned char buffer[PRNGD_STATE_SIZE];

  bytes = lseek(randsavefd, 0, SEEK_SET);
  if (bytes < 0)
  {
    error_fatal("Error writing seedfile", errno);
    exit(EXIT_FAILURE);
  }
  bytes = rand_bytes(buffer, PRNGD_STATE_SIZE);
  if (bytes == 0)
  {
    error_error("Info: Random pool not (yet) seeded", 0);
  }
  else
  {
    bytes = write(randsavefd, buffer, PRNGD_STATE_SIZE);
    if (bytes < 0)
    {
      error_fatal("Error writing seedfile", errno);
      exit(EXIT_FAILURE);
    }
  }
  if (debug)
    (void)fprintf(stderr, "Wrote %d bytes back to seedfile\n", bytes);

  bytes = ftruncate(randsavefd, bytes);
}

void close_seedfile(void)
{
  if (randsavefd >= 0) {
    write_seedfile();
    (void)close(randsavefd);
  }
}

static void close_pidfile(void)
{
  if (pidfilefd >= 0) {
    (void)close(pidfilefd);
  }
}


static void killpeer(int service_socket)
{
  unsigned char buffer[256];
  char msg_buf[1024];
  int num;
  pid_t peer_id;

  buffer[0] = 0x04;
  if (write(service_socket, buffer, 1) < 1)
  {
    error_fatal("Cannot contact peer", errno);
    exit(EXIT_FAILURE);
  }
  if (read(service_socket, buffer, 1) < 1)
  {
    error_fatal("Cannot read from peer", errno);
    exit(EXIT_FAILURE);
  }
  num = buffer[0];
  if (read(service_socket, buffer, num) < num)
  {
    error_fatal("Cannot read from peer", errno);
    exit(EXIT_FAILURE);
  }
  buffer[num] = '\0';
  peer_id = (pid_t)atol((char *) buffer);
  (void)fprintf(stderr, "Killing: %ld\n", (long)peer_id);

  if (kill(peer_id, SIGTERM) < 0)
  {
    (void)snprintf(msg_buf, sizeof(msg_buf), "Cannot kill %ld", (long)peer_id);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, errno);
    exit(EXIT_FAILURE);
  }
  exit(EXIT_SUCCESS);
}

static void usage(const char *progname)
{
  (void)fprintf(stderr, "prngd %s (%s)\n", PRNGD_VERSION, PRNGD_DATE);
  (void)fprintf(stderr,
	  "Usage: %s [options] (/path/to/socket1 | tcp/localhost:port) "
		"[(/path/to/socket2 | tcp/localhost:port)] ... \n"
	  "Options:\n"
	  "\t-f/--fg: do not fork\n"
	  "\t-d/--debug: debugging on\n"
	  "\t-c/--cmdfile cmdpath: use cmdpath for entropy commands [%s]\n"
	  "\t-s/--seedfile seedpath: use seedpath as seedfile [%s]\n"
	  "\t-p/--pidfile pidfilepath: use pidfilepath as pidfile\n"
	  "\t-n/--no-seedfile: no seedfile, keep pool in memory only\n"
	  "\t-m/--mode mode: use mode for sockets [%04o]\n"
	  "\t-k/--kill: kill daemon on other side\n"
	  "\t-v/--version: print version and exit\n",
	  progname, CONFIGFILE, RANDSAVENAME, SOCKETMODE);
}

int main(int argc, char *argv[])
{
  int argp;
  int ret;
  int statval;
  int killmode = 0, killfail = 0;
  time_t seed_stat_interval = SEED_STAT_INTERVAL;
  time_t seed_ext_interval = SEED_EXT_INTERVAL;
  int i, numsock_file = 0, numsock_tcp = 0;
  char **randsock_tcp = NULL;
  char **randsock_file = NULL;
  char *cmdpath = CONFIGFILE;
  char *seedpath = RANDSAVENAME;
  char msg_buf[1024];
  unsigned int socketmode = SOCKETMODE;
  int *service_socket, service_count = 0;
  int kill_socket;
  struct stat randsock_file_stat;
  struct passwd *pwent;
  char *username = "unknown";
  char pidfilebuffer[32];
  entropy_source_t *entropy_source;

  /*
   * Process arguments 
   */
  argp = 1;
  while (argp < argc)
  {
    if (!strcmp(argv[argp], "-v") || !strcmp(argv[argp], "--version")) {
      (void)fprintf(stdout, "prngd %s (%s)\n", PRNGD_VERSION, PRNGD_DATE);
      exit(EXIT_SUCCESS);
    }
    else if (!strcmp(argv[argp], "-d") || !strcmp(argv[argp], "--debug"))
      debug = 1;
    else if (!strcmp(argv[argp], "-f") || !strcmp(argv[argp], "--fg"))
      fg = 1;
    else if ((!strcmp(argv[argp], "-c") || !strcmp(argv[argp], "--cmdfile"))
	     && (argp + 1 < argc))
      cmdpath = argv[++argp];
    else if ((!strcmp(argv[argp], "-s") || !strcmp(argv[argp], "--seedfile"))
	     && (argp + 1 < argc))
      seedpath = argv[++argp];
    else if ((!strcmp(argv[argp], "-p") || !strcmp(argv[argp], "--pidfile"))
	     && (argp + 1 < argc))
      pidfile = argv[++argp];
    else if ((!strcmp(argv[argp], "-m") || !strcmp(argv[argp], "--mode"))
	     && (argp + 1 < argc))
    {
      if (sscanf(argv[++argp], "%o", &socketmode) == 0)
      {
	(void)snprintf(msg_buf, sizeof(msg_buf),
		"Cannot interpret socket mode '%s'\n", argv[argp]);
	msg_buf[sizeof(msg_buf) - 1] = '\0';
	error_fatal(msg_buf, 0);
	exit(EXIT_FAILURE);
      }
    }
    else if (!strcmp(argv[argp], "-n") || !strcmp(argv[argp], "--no-seedfile"))
      seedpath = NULL;
    else if (!strcmp(argv[argp], "-k") || !strcmp(argv[argp], "--kill"))
      killmode = 1;
#ifndef NO_UNIX_SOCKET
    else if (argv[argp][0] == '/') {
      if (numsock_file == 0)
        randsock_file = malloc(sizeof(char *));
      else
	randsock_file = realloc(randsock_file,
				(numsock_file + 1) * sizeof(char *));
      if (randsock_file == NULL) {
	error_fatal("Could not allocate memory", errno);
	exit(EXIT_FAILURE);
      }
      randsock_file[numsock_file++] = argv[argp];
    }
#endif /* NO_UNIX_SOCKET */
    else if (!strncmp(argv[argp], "tcp/localhost:", strlen("tcp/localhost:"))) {
      if (numsock_tcp == 0)
        randsock_tcp = malloc(sizeof(char *));
      else
	randsock_tcp = realloc(randsock_tcp,
				(numsock_tcp + 1) * sizeof(char *));
      if (randsock_tcp == NULL) {
	error_fatal("Could not allocate memory", errno);
	exit(EXIT_FAILURE);
      }
      randsock_tcp[numsock_tcp++] = argv[argp];
    } 
    else
    {
      usage(argv[0]);
      exit(EXIT_FAILURE);
    }
    argp++;
  }
  if ((numsock_file == 0) && (numsock_tcp == 0)) {
    usage(argv[0]);
    error_fatal("No listen socket given, exiting!", 0);
    exit(EXIT_FAILURE);
  }

  if (!killmode)
    parse_configfile(cmdpath, &entropy_source);

  if (debug)
    (void)fprintf(stdout, "Debugging enabled\n");

  /*
   * Obtain the maximum number of open filedescriptors and adjust the
   * counter of actual open files. As always we have open stdin, stdout,
   * and stderr.
   */
  limit_openfd = obtain_limit();
  count_openfd = 3;

  /*
   * Open /dev/null
   */
  devnull = open("/dev/null", O_RDWR);
  if (devnull == -1) {
    error_fatal("Couldn't open /dev/null", errno);
    exit(EXIT_FAILURE);
  }
  count_openfd++;

  /*
   * Now, initialize the PRNG (allocate the memory).
   */
  rand_init(PRNGD_STATE_SIZE, ENTROPY_NEEDED);


  /*
   * Start by reading back the seed saved from former runs, if usage of a
   * seedfile is wanted. 
   */
  if (!killmode && seedpath) {
    open_seedfile(seedpath);
    count_openfd++;
  }
  if (!killmode && pidfile) {
    open_pidfile(pidfile);
    count_openfd++;
  }

  if (!(service_socket = malloc((numsock_file + numsock_tcp) * sizeof(int)))) {
    error_fatal("Could not allocate memory", errno);
    exit(EXIT_FAILURE);
  }

  if (killmode) {
    for (i = 0; i < numsock_file; i++) {

    /*
     * Try to kill daemons on the other side of a unix socket. If we cannot
     * connect to a daemon, we set a flag but continue, since there may be
     * other daemons waiting for kill.
     */
      statval = stat(randsock_file[i], &randsock_file_stat);
      if ((statval < 0) && (errno != ENOENT)) {
        (void)snprintf(msg_buf, sizeof(msg_buf),
		       "Cannot stat socket position %s", randsock_file[i]);
        msg_buf[sizeof(msg_buf) - 1] = '\0';
        error_error(msg_buf, errno);
        killfail = 1;
        continue;
      }
      if ((statval < 0) && (errno == ENOENT)) {
        (void)snprintf(msg_buf, sizeof(msg_buf), "No object at position %s",
        	randsock_file[i]);
        msg_buf[sizeof(msg_buf) - 1] = '\0';
        error_fatal(msg_buf, errno);
        killfail = 1;
        continue;
      }
      if (!IS_UNIX_SOCKET(randsock_file_stat.st_mode)) {
	(void)snprintf(msg_buf, sizeof(msg_buf), "Will not touch %s: no socket",
		randsock_file[i]);
	msg_buf[sizeof(msg_buf) - 1] = '\0';
	error_error(msg_buf, errno);
	killfail = 1;
	continue;
      }

      if ((kill_socket = unix_connect(randsock_file[i], 0, 1)) < 0) {
	    (void)snprintf(msg_buf, sizeof(msg_buf),
	    	"cannot kill peer at %s: no daemon", randsock_file[i]);
	    msg_buf[sizeof(msg_buf) - 1] = '\0';
	    error_error(msg_buf, 0);
	    killfail = 1;
      }
      else {
	killpeer(kill_socket);
	my_shutdown(kill_socket, SHUT_RDWR);
	(void)close(kill_socket);
      }
    }

    for (i = 0; i < numsock_tcp; i++) {
      if ((kill_socket = tcp_connect(randsock_tcp[i], 0, 1)) < 0) {
	(void)snprintf(msg_buf, sizeof(msg_buf),
		       "cannot kill peer at %s: no daemon", randsock_tcp[i]);
	msg_buf[sizeof(msg_buf) - 1] = '\0';
	error_error(msg_buf, 0);
	/*
	 * Do no exit because there may be more work to do!
	 */
      }
      else {
	killpeer(kill_socket);
	my_shutdown(kill_socket, SHUT_RDWR);
	(void)close(kill_socket);
      }
    }
    /*
     * Everything has been done!
     */
    if (killfail)
      exit(EXIT_FAILURE);
    else
      exit(EXIT_SUCCESS);
  }


  /*
   * Set up the UNIX domain sockets to service entropy requests
   */
  for (i = 0; i < numsock_file; i++) {

    /*
     * Check out what is already available at the place of the future
     * egd-socket. If we cannot reach the place to be with "stat()",
     * do not continue, as something may be seriously wrong. If the
     * entry does already exist, remove it, but only if it is of type
     * socket! If removal fails for whatever reason, stop, as something
     * may be seriously wrong.
     */
    statval = stat(randsock_file[i], &randsock_file_stat);
    if ((statval < 0) && (errno != ENOENT)) {
      (void)snprintf(msg_buf, sizeof(msg_buf), "Cannot stat socket position %s",
      	randsock_file[i]);
      msg_buf[sizeof(msg_buf) - 1] = '\0';
      error_fatal(msg_buf, errno);
      exit(EXIT_FAILURE);
    }
    else if (!statval) {
      if (!IS_UNIX_SOCKET(randsock_file_stat.st_mode)) {
	(void)snprintf(msg_buf, sizeof(msg_buf), "Will not touch %s: no socket",
		randsock_file[i]);
	msg_buf[sizeof(msg_buf) - 1] = '\0';
	error_fatal(msg_buf, errno);
	exit(EXIT_FAILURE);
      } else {
	if ((kill_socket = unix_connect(randsock_file[i], 0, 1)) >= 0) {
	  (void)snprintf(msg_buf, sizeof(msg_buf),
		  "socket %s already used by another process, exiting.\n",
		  randsock_file[i]);
	  msg_buf[sizeof(msg_buf) - 1] = '\0';
	  error_fatal(msg_buf, 0);
	  exit(EXIT_FAILURE);
	}

	/*
         * Now there is a socket without service listening on it: we can
	 * remove it.
	 */
	if (unlink(randsock_file[i]) < 0) {
	  (void)snprintf(msg_buf, sizeof(msg_buf),
	  	"Cannot remove already existing entry %s", randsock_file[i]);
	  msg_buf[sizeof(msg_buf) - 1] = '\0';
	  error_fatal(msg_buf, errno);
	  exit(EXIT_FAILURE);
	}
      }
    }

    service_socket[service_count++] = unix_listen(randsock_file[i], 1, 1);
    if (chmod(randsock_file[i], socketmode) < 0) {
      (void)snprintf(msg_buf, sizeof(msg_buf), "Could not chmod socket to %04o",
		     socketmode);
      msg_buf[sizeof(msg_buf) - 1] = '\0';
      error_fatal(msg_buf, errno);
      exit(EXIT_FAILURE);
    }
    count_openfd++;
  }

  /*
   * Set up the TCP sockets to service entropy requests
   */
  for (i = 0; i < numsock_tcp; i++) {
    service_socket[service_count++] = tcp_listen(randsock_tcp[i], 1, 1);
    count_openfd++;
  }


  /*
   * If not in debugging mode, make myself a daemon 
   */
  if (!debug)
  {
    ret = fg ? fg : daemon(0, 0);
    if (ret < 0)
    {
      error_fatal("Could not daemonize", errno);
      exit(EXIT_FAILURE);
    }

    if ((pwent = getpwuid(getuid())) != NULL)
      username = pwent->pw_name;
    /*
     * The setup is finished, and we are daemonized, so we must now switch
     * to syslog...
     */
    (void)snprintf(msg_buf, sizeof(msg_buf),
    	"prngd %s (%s) started up for user %s", PRNGD_VERSION, PRNGD_DATE,
	username);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_notice(msg_buf, 0);
    count_openfd++;
    (void)snprintf(msg_buf, sizeof(msg_buf),
    	"have %d out of %d filedescriptors open", count_openfd, limit_openfd);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_notice(msg_buf, 0);
  }

  /*
   * Maybe we have changed our pid, let's add some more of it. 
   */
  seed_internal(NULL);

  if (!killmode && pidfile) {
    memset(pidfilebuffer, 0, sizeof(pidfilebuffer));
    snprintf(pidfilebuffer, sizeof(pidfilebuffer), "%12ld\n", (long)getpid());
    pidfilebuffer[sizeof(pidfilebuffer) - 1] = '\0';
    if (write(pidfilefd, pidfilebuffer, strlen(pidfilebuffer)) < 0) {
      error_fatal("Error writing pidfile", errno);
      exit(EXIT_FAILURE);
    }
    close_pidfile();
    count_openfd--;
  }

  /* Never returns */
  main_loop(service_socket, service_count, seed_stat_interval,
	    seed_ext_interval, entropy_source, MAX_GATHERER_BYTES);

  /*
   * We never get here, but want to make the compiler happy...
   */
  return(EXIT_SUCCESS);
}


===== prngd.h =====
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/times.h>
#include <unistd.h>
#include <fcntl.h>
#include <syslog.h>
#include <stdarg.h>

#include "config.h"
#include "prngd_version.h"

#ifdef HAVE_GETRUSAGE
#include <sys/resource.h>
#endif
#ifndef HAVE_DAEMON
int daemon(int nochdir, int noclose);
#endif
#ifndef HAVE_SNPRINTF
int snprintf(char *str, size_t count, const char *fmt, ...);
#endif /* !HAVE_SNPRINTF */
#ifndef HAVE_VSNPRINTF
int vsnprintf(char *str, size_t count, const char *fmt, va_list args);
#endif /* !HAVE_SNPRINTF */

typedef struct {
  double rate;
  unsigned int badness;
  unsigned int sticky_badness;
  char *path;
  char *args[5];
  char *cmdstring;
} entropy_source_t;

typedef struct {
  struct tms tmsbuf;
  struct timeval tp;
  pid_t pid;
#ifdef HAVE_GETRUSAGE
  struct rusage usage;
#endif
  int seed_counter;
} seed_t;

extern int debug;
extern int devnull;
extern int limit_openfd;
extern int count_openfd;

extern char *pidfile;

void parse_configfile(const char *cmdpath, entropy_source_t **entropy_source);

void main_loop(int *service_socket, int numsock, time_t seed_stat_interval,
	       time_t seed_ext_interval, entropy_source_t *entropy_source,
	       int max_gatherer_bytes);

void close_seedfile(void);

void seed_internal(seed_t *seed_p);
void seed_stat(void);

void rand_add(const void *buf, int num, double entropy);
int rand_bytes(unsigned char *buf, int num);
int rand_pool(void);
void rand_init(int set_state_size, int set_entropy_needed);

/* What do we exit with when there is an error? */
#ifndef EXIT_FAILURE
#define EXIT_FAILURE 1
#endif

#define SHA_DIGEST_LENGTH 20
/* The SHA block size and message digest sizes, in bytes */

#define SHA_DATASIZE    64
#define SHA_DATALEN     16
#define SHA_DIGESTSIZE  20
#define SHA_DIGESTLEN    5
/* The structure for storing SHA info */

typedef struct sha1_ctx {
  unsigned int digest[SHA_DIGESTLEN];  /* Message digest */
  unsigned int count_l, count_h;       /* 64-bit block count */
  unsigned char block[SHA_DATASIZE];     /* SHA data buffer */
  int index;                             /* index into buffer */
} SHA1_CTX;

void SHA1_init(SHA1_CTX *ctx);
void SHA1_update(SHA1_CTX *ctx, const unsigned char *buffer, unsigned int len);
void SHA1_final(SHA1_CTX *ctx);
void SHA1_digest(SHA1_CTX *ctx, unsigned char *s);
void SHA1_copy(SHA1_CTX *dest, SHA1_CTX *src);

void close_on_exec(int fd, int on);

void non_blocking(int fd, int on);

ssize_t socket_read(int fd, void *buf, size_t num);
ssize_t socket_write(int fd, void *buf, size_t num);

int obtain_limit(void);

/*
 * error_handlers.c
 */
void* my_malloc(size_t);
int my_pipe(int[2]);
void my_dup2(int, int);
void my_gettimeofday(struct timeval*, void*);
void my_shutdown(int, int);

/*
 * error_log.c
 */
#ifndef SYSLOG_FACILITY
#define SYSLOG_FACILITY LOG_DAEMON
#endif
void intitialise_syslog(void);
void error_fatal(const char*, int);
void error_error(const char*, int);
void error_notice(const char*, int);

/*
 * unix_socket.c
 */
int unix_connect(const char *connection, int non_block, int close_exec);
int unix_listen(const char *connection, int non_block, int close_exec);

/*
 * tcp_socket.c
 */
int tcp_connect(const char *connection, int non_block, int close_exec);
int tcp_listen(const char *connection, int non_block, int close_exec);


===== prngd_version.h =====
#define PRNGD_VERSION	"0.9.29"
#define PRNGD_DATE	"12 Jul 2004"


===== rand.c =====
/*
 * Lutz's own PRNG :-)
 *
 * (Versions of "prngd" before 0.9.0 did use the OpenSSL internal PRNG.)
 *
 * Technical description:
 *
 * The entropy data is kept in a "pool" of large size (default size is 4kB
 * = 4096 bytes rounded up to full 20bytes = 4100 bytes) (* 8 bits).
 *
 * Adding seed:
 * ============
 *
 * Whenever entropy is added, an SHA1-hash of a (20+64)byte block at a
 * moving "position is created and a block of 20bytes of the new data is
 * hashed in. The 20byte hash is then written back (to be more precise:
 * XORed with the bytes at position) and position is advanced by 20bytes.
 *
 * Requesting random data:
 * =======================
 *
 * Whenever entropy is requested, the same (20+64)byte block is hashed. The
 * 20byte hash output is given back as "random data". The 20byte block is
 * also XORed into the bytes at position. Then position is advanced by 20bytes
 * to retrieve the next "random bytes" until the request is satisfied.
 *
 * In order to improve the mixing (and security), each time random data is
 * requested, the pool is mixed completly before and after serving the
 * request.
 *
 * Security:
 * =========
 *
 * Protection against unseeded PRNG:
 * - Random data is only returned, when enough entropy was seeded into the pool.
 *
 * Protection against reading PRNG state from memory/core dump:
 * - Whenever entropy is retrieved, the pool is completly mixed, entropy is
 *   retrieved, then the pool is again completly mixed. So retrieval of
 *   the state from memory would have to happen before the second mixing.
 *   Retrieval from core won't work anyway, since the second mixing will
 *   happen, even before rand_bytes() returns with the random bytes just
 *   generated.
 * - All memory locations temporarily used are memset() to 0 when finishing
 *   an operation.
 *
 * Acknowledgements:
 * =================
 *
 * First versions of PRNGD (before 0.9.0) utilized the OpenSSL PRNG by linking
 * libcrypto. Functionality like the "complete mix before retrieve" needed to
 * be done with a wrapper, the pool size was fixed and some other limitations
 * applied. Therefore the PRNG needed to be included into "prngd".
 *
 * Because the OpenSSL license is not as flexible as mine, I decided to create
 * my own PRNG. Its design is based on my experience with the OpenSSL PRNG
 * and additionally heavily inspired by Peter Gutmann's work.
 *   http://www.cs.auckland.ac.nz/~pgut001/
 * and especially the text
 *   http://www.cryptoengines.com/~peter/06_random.pdf
 * (See the last reference, section cryptlib-PRNG, for the "20+64"
 * technique :-)
 */

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

#include "prngd.h"

static int position = 0, pool_size = 0, pool_seeded = 0;
static unsigned char *pool = NULL;
static double entropy = 0, entropy_needed;

static void rand_flip_bits(void)
{
  int i;

  /*
   * Flip all bits in the pool
   */
  for (i = 0; i < pool_size; i++)
    pool[i] ^= 0xff;
}

void rand_add(const void *buf, int num, double add)
{
  int i, j, end;
  unsigned char temp_md[SHA_DIGEST_LENGTH];
  SHA1_CTX c;

  /* be absolutely sure that the pool array has been allocated */
  if (pool == NULL) {
  	error_fatal("In rand.c pool has not been allocated", 0);
	exit(EXIT_FAILURE);
  }

  /*
   * Mix new bytes into the pool. To perform this operation, read
   * SHA_DIGEST_LENGTH bytes starting from (position-SHA_DIGEST_LENGTH)
   * and the next 64bytes. Then "add" the new bytes, finally write it back
   * to "position" and advance "position".
   */
  for (i = 0; i < num; i += SHA_DIGEST_LENGTH) {
    SHA1_init(&c);
    /*
     * Read back entropy from the pool while taking account of wrap around
     * effects. First read 20bytes from "left of the current position",
     * then 64bytes starting at position.
     */
    if (position == 0)
      SHA1_update(&c, pool + pool_size - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH);
    else
      SHA1_update(&c, pool + position - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH);
    
    end = position + 64;
    if (end < pool_size)
      SHA1_update(&c, pool + position, 64);
    else {
      end %= pool_size;
      SHA1_update(&c, pool + position, pool_size - position);
      SHA1_update(&c, pool, end);
    }

    SHA1_update(&c, (unsigned char *)buf + i,
		(num - i > SHA_DIGEST_LENGTH) ? SHA_DIGEST_LENGTH : (num - i));
    SHA1_final(&c);
    SHA1_digest(&c, temp_md);
    for (j = 0; j < SHA_DIGEST_LENGTH; j++)
      pool[position + j] ^= temp_md[j];
    position += SHA_DIGEST_LENGTH;
    position %= pool_size;	/* wrap, if needed */
    if (position == 0)
      rand_flip_bits();		/* when wrapped, flip once */
  }

  (void)memset(temp_md, 0, SHA_DIGEST_LENGTH);
  (void)memset(&c, 0, sizeof(c));

  /*
   * Register the weighted entropy, but of course there cannot be more
   * entropy in the pool than its size.
   */
  entropy += add;
  if (entropy > pool_size)
    entropy = pool_size;

  /*
   * The "entropy" counter is incremented and decremented to reflect the
   * entropy added or "used up" by querying. Once enough entropy was added
   * to satisfy the minimum requirement, PRNGD will continue to serve
   * random numbers using the "pseudo" RNG even if the entropy count goes
   * back down below the minimum.
   */
  if (entropy >= entropy_needed)
    pool_seeded = 1;
}

int rand_bytes(unsigned char *buf, int num)
{
  int i, j, end;
  unsigned char temp_md[SHA_DIGEST_LENGTH];
  SHA1_CTX c;

  assert(pool != NULL);

  /*
   * Sanity: only return "random bytes", when the pool was successfully
   * seeded.
   */
  if (!pool_seeded)
    return 0;

  /*
   * Before "random bytes" are returned, make sure that the pool is mixed.
   * To achieve this goal, we run the "mixer" scheme, which is also used
   * for adding and retrieving "20+64" across the pool. Unlike the OpenSSL
   * PRNG, which only mixes once when first retrieving random bytes, we
   * always completly mix the pool before supplying the bytes.
   * In many cases, applications using OpenSSL will only do one transaction,
   * then exit, so it won't make a big difference. PRNGD will run continously,
   * so it _does_ make a difference here. By mixing the pool completly, the
   * bytes finally retrieved are influenced by all bits in the pool. Since
   * only a limited number of bytes can be retrieved at a time and by
   * default, this number (255) is much smaller than the pool size, the
   * bytes retrieved will only reveal a small amount of state information
   * when compared to the total amount of state bits.
   */
  for (i = 0; i < pool_size; i += SHA_DIGEST_LENGTH) {
    SHA1_init(&c);
    if (position == 0)
      SHA1_update(&c, pool + pool_size - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH);
    else
      SHA1_update(&c, pool + position - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH);
    
    end = position + 64;
    if (end < pool_size)
      SHA1_update(&c, pool + position, 64);
    else {
      end %= pool_size;
      SHA1_update(&c, pool + position, pool_size - position);
      SHA1_update(&c, pool, end);
    }

    SHA1_final(&c);
    SHA1_digest(&c, temp_md);
    for (j = 0; j < SHA_DIGEST_LENGTH; j++)
      pool[position + j] ^= temp_md[j];
    position += SHA_DIGEST_LENGTH;
    position %= pool_size;	/* wrap, if needed */
    if (position == 0)
      rand_flip_bits();		/* when wrapped, flip once */
  }

  /*
   * Ok, now retrieve the entropy requested!
   */
  rand_flip_bits();
  for (i = 0; i < num; i += SHA_DIGEST_LENGTH) {
    SHA1_init(&c);
    /*
     * Read back entropy from the pool while taking account of wrap around
     * effects. First read 20bytes from "left of the current position",
     * then 64bytes starting at position.
     */
    if (position == 0)
      SHA1_update(&c, pool + pool_size - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH);
    else
      SHA1_update(&c, pool + position - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH);
    
    end = position + 64;
    if (end < pool_size)
      SHA1_update(&c, pool + position, 64);
    else {
      end %= pool_size;
      SHA1_update(&c, pool + position, pool_size - position);
      SHA1_update(&c, pool, end);
    }

    SHA1_final(&c);
    SHA1_digest(&c, temp_md);
    for (j = 0; j < SHA_DIGEST_LENGTH; j++)
      pool[position + j] ^= temp_md[j];
    position += SHA_DIGEST_LENGTH;
    position %= pool_size;	/* wrap, if needed */
    for (j = i; (j < num) && (j - i < SHA_DIGEST_LENGTH); j++)
      buf[j] = temp_md[j - i];
  }

  /*
   * Now that the entropy has been retrieved, the pool is mixed again.
   * If somebody could gain access to the memory, he would not find any
   * (useful) traces of the pool state left.
   */
  rand_flip_bits();
  for (i = 0; i < pool_size; i += SHA_DIGEST_LENGTH) {
    SHA1_init(&c);
    if (position == 0)
      SHA1_update(&c, pool + pool_size - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH);
    else
      SHA1_update(&c, pool + position - SHA_DIGEST_LENGTH, SHA_DIGEST_LENGTH);
    
    end = position + 64;
    if (end < pool_size)
      SHA1_update(&c, pool + position, 64);
    else {
      end %= pool_size;
      SHA1_update(&c, pool + position, pool_size - position);
      SHA1_update(&c, pool, end);
    }

    SHA1_final(&c);
    SHA1_digest(&c, temp_md);
    for (j = 0; j < SHA_DIGEST_LENGTH; j++)
      pool[position + j] ^= temp_md[j];
    position += SHA_DIGEST_LENGTH;
    position %= pool_size;	/* wrap, if needed */
    if (position == 0)
      rand_flip_bits();		/* when wrapped, flip once */
  }

  (void)memset(&c, 0, sizeof(c));
  (void)memset(temp_md, 0, SHA_DIGEST_LENGTH);

  /*
   * When entropy was retrieved, reduce the "entropy counter". Do not go
   * below 0, because this would not make sense.
   */
  entropy -= num;
  if (entropy < 0)
    entropy = 0;

  return 1;
}

int rand_pool(void)
{

 /*
  * Return the amount of (weighted) entropy available in bits. If not
  * enough entropy is available yet, return "0" to flag that a call to
  * rand_bytes() would fail.
  */

  if (!pool_seeded)
    return 0;
  else
    return (int)(entropy * BITS_PER_BYTE);
}

void rand_init(int set_pool_size, int set_entropy_needed)
{
  /*
   * Set the pool size. For simplicity (we must be able to walk back and
   * forward), the pool_size shall be a multiple of SHA_DIGEST_LENGTH.
   * In order to work appropriately (we always mix 20+64=84bytes) the
   * minimum _technical_ pool size is set to 100bytes.
   */
  pool_size = set_pool_size;
  if (pool_size < 100)
    pool_size = 100;
  if (pool_size % SHA_DIGEST_LENGTH)
    pool_size = (pool_size / SHA_DIGEST_LENGTH + 1) * SHA_DIGEST_LENGTH;
  pool = my_malloc(pool_size);

  /*
   * Remember the minimum seed needed.
   */
  entropy_needed = set_entropy_needed;
}


===== seed.c =====
 /*
  * Internal seed functions
  */

#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "prngd.h"

static const char *statfiles[] = {
#ifdef PATH_TMP
PATH_TMP,
#endif
#ifdef PATH_VAR_TMP
PATH_VAR_TMP,
#endif
#ifdef PATH_PASSWD
PATH_PASSWD,
#endif
#ifdef PATH_WTMP
PATH_WTMP,
#endif
#ifdef PATH_UTMP
PATH_UTMP,
#endif
#ifdef PATH_SYSLOG
PATH_SYSLOG,
#endif
#ifdef PATH_MAILLOG
PATH_MAILLOG,
#endif
NULL};

 /*
  * seed_internal: internal "cheap" seeding. Call statistic functions that
  * may provide some bits that are hard to predict:
  * - times() utilizes the cumulative computer time in TICKS, so hopefully
  *   the exact amount is not too easy to guess. Might give 1 or 2 bits of
  *   entropy.
  * - gettimeofday() can have the actual time in microseconds, the last
  *   bits might be "random".
  * - getpid() is probably not too hard to guess, but well, it won't hurt.
  * - getrusage(), if available, contains several statistical data that might
  *   be hard to guess.
  * - seed_counter is a simple counter to mix in...
  * This function is especially designed to be computationally cheap, so that
  * it can be called very often, especially every time when an event occurs
  * (a connection is opened etc), so that the usage of the real time values
  * might help increasing the entropy.
  *
  * Be careful anyhow, don't count the bits.
  *
  * This function may also be called to collect the data now and give it back
  * in the supplied memory for later usage.
  */
void seed_internal(seed_t *seed_p)
{
  seed_t seed, *my_seed_p;
  static int seed_counter = 0;

  if (seed_p)
    my_seed_p = seed_p;
  else
    my_seed_p = &seed;

  (void)times(&(my_seed_p->tmsbuf));
  my_gettimeofday(&(my_seed_p->tp), NULL);
  my_seed_p->pid = getpid();
#ifdef HAVE_GETRUSAGE
  (void)getrusage(RUSAGE_SELF, &(my_seed_p->usage));
#endif
  /*
   * add in just a little more variability each time we seed
   * internally by using a counter.
   */
  if (seed_counter == 0)
    seed_counter = (int)getpid();
  my_seed_p->seed_counter = seed_counter++;

  if (!seed_p)
    rand_add(my_seed_p, sizeof(seed_t), 0.0);
}

 /*
  * seed_stat(): Get seed by stat()ing files and directories on the system.
  * This is cheaper than doing an "ls", since no external process is needed.
  * The data returned includes size and access/modification times. The logfiles
  * should change in size quite often, while the TMP directories might
  * are changed quite often.
  * Why have /etc/passwd in the list??? Because a lot of programs need the
  * user information for the uid->name translation, so they must access
  * /etc/passwd (probably via getpwent) and hence impact the access time.
  *
  * We also do not count the bits.
  */
static int pathpoint = 0;

void seed_stat(void)
{
  struct stat buf;

 /*
  * Run over the list of files with often changing status (access/modification
  * time, length) and seed it into the PRNG. Since only certain parts of
  * the information changes, we assume the amount of entropy to be rather
  * small. Use 2bits=1/4byte per check.
  */
  while (statfiles[pathpoint] != NULL) {
    if (stat(statfiles[pathpoint++], &buf) == 0) {
      rand_add(&buf, sizeof(struct stat), 0.0);
      if (statfiles[pathpoint] == NULL)
	pathpoint = 0;
      return;
    }
  }

  pathpoint = 0;
  return;
}


===== serverloop.c =====
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>

#include "prngd.h"

#ifdef NEED_SYS_SELECT_H
#include <sys/select.h>
#endif /* NEED_SYS_SELECT_H */

static volatile int caught_sigchild = 0;
static volatile int received_sighup = 0;

typedef enum
{
  wait_command, wait_second_byte, wait_third_byte, wait_fourth_byte,
  wait_read, wait_entropy1, wait_entropy2, wait_write, to_be_closed,
  to_be_error_closed
}
querystate_t;

typedef struct
{
  int fd;
  int state;
  int to_process;
  int yet_processed;
  int entropy_bits;
  unsigned char command, secbyte;
  unsigned char buffer[256];
} egd_query_t;


static void termination_handler(int received_signal)
{
  char msg_buf[128];

  if (received_signal != SIGTERM) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
	"Termination handler called with wrong signal: %d != SIGTERM",
	received_signal);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_notice(msg_buf, 0);
  }
  if (debug)
    (void)fprintf(stderr, "Caught SIGTERM, shutting down\n");
  close_seedfile();
  if (pidfile) {
    if (remove(pidfile) == -1) {
      (void)snprintf(msg_buf, sizeof(msg_buf), "Could not remove pidfile %s",
		     pidfile);
      msg_buf[sizeof(msg_buf) - 1] = '\0';
      error_error(msg_buf, errno);
      exit(EXIT_FAILURE);
    }
  }
  exit(EXIT_SUCCESS);
}

static void sighup_handler(int received_signal)
{
  char msg_buf[128];

  if (received_signal != SIGHUP) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
	"HUP handler called with wrong signal: %d != SIGHUP",
	received_signal);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_notice(msg_buf, 0);
  }
  received_sighup = 1;
}

static void child_handler(int received_signal)
{
  char msg_buf[128];

  if (received_signal != SIGCHLD) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
	"Sigchild handler called with wrong signal: %d != SIGCHLD",
	received_signal);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_notice(msg_buf, 0);
  }
  /*
   * Wait for child process to avoid zombies. This signal comes in
   * asynchronously.
   *
   * PRNGD can only have one child at a time, so recording the information
   * could be trivial. However: if a gatherer call is stuck inside a system
   * call, the processes will only die much later, even though "kill -9"
   * has been called after PRNGD's gatherer timeout. Thus, several children
   * may die at the same time. On the other hand, due to process scheduling,
   * a gatherer may die before its PID is recorded. As we must not miss the
   * exit of the actual gatherer process (so that it can be killed after
   * timeout), we only catch SIGCHLD but the evaluation is done by a
   * seperate polling routine that does know about the active gatherer.
   */
  caught_sigchild = 1;
}

static void collect_children(pid_t *gatherer_pid)
{
  pid_t child_pid;
  int gatherer_status;

  while (((child_pid = waitpid(-1, &gatherer_status, WNOHANG)) > 0)
	 || ((child_pid < 0) && (errno == EINTR))) {
    if (child_pid > 0) {
      rand_add(&gatherer_status, sizeof(gatherer_status), 0.0);
      if (WIFEXITED(gatherer_status) || WIFSIGNALED(gatherer_status)) {
        if (debug)
	  (void)fprintf(stderr,
		      "Found child died (pid = %ld, gatherer_pid = %ld)\n",
		      (long)child_pid, (long)*gatherer_pid);
        if (child_pid == *gatherer_pid)
	*gatherer_pid = -1;
      }
    }
  }
}


void main_loop(int *service_socket, int numsock, time_t seed_stat_interval,
	       time_t seed_ext_interval, entropy_source_t *entropy_source,
	       int max_gatherer_bytes)
{
  int i, i1;
  int accept_fd;
  struct sockaddr addr;
  SOCKLEN_T addrlen;
  int num, numbytes, error;
  int pipedes[2];
  time_t last_seed_stat = 0, last_seed_ext = 0;
  int max_query = 0;
  int alloc_query = 0;
  int prev_location = 0;
  egd_query_t *egd_query = NULL;
  egd_query_t *egd_query_old;
  int max_fd;
  int max_query_old;
  pid_t gatherer_pid;
  int gather_fd;
  int gatherer_entry;
  int gatherer_bytes;
  int first_gather = 1;
  int entropy_required;
  double est = 0.0;
  time_t gather_start;
  unsigned char gatherbuf[10240];
  char msg_buf[1024];
  struct sigaction new_action;
  fd_set rfds, wfds, efds;
  struct timeval timeout;
  int saved_errno;

  gatherer_pid = -1;
  gather_fd = -1;
  gatherer_entry = 0;

  gatherer_bytes = 0;		/* Initialize to make gcc happy */
  gather_start = time(NULL);	/* Initialize to make gcc happy */

  /*
   * Set up the signal handling. TERM signals shall lead to clean
   * shutdown of prngd (save the seed and exit).
   * HUP signals shall lead to a re-read of the config file.
   * SIGPIPE might occur when a peer shuts down the connection. Of course,
   * we don't want prngd to be affected in any way (it should simply close
   * the connection), so SIGPIPE shall be ignored.
   */
  (void)memset(&new_action, 0, sizeof(struct sigaction));
  new_action.sa_handler = termination_handler;
  (void)sigemptyset(&new_action.sa_mask);
  new_action.sa_flags |= SA_RESTART;
  (void)sigaction(SIGTERM, &new_action, NULL);

  (void)memset(&new_action, 0, sizeof(struct sigaction));
  new_action.sa_handler = sighup_handler;
  (void)sigemptyset(&new_action.sa_mask);
  new_action.sa_flags |= SA_RESTART;
  (void)sigaction(SIGHUP, &new_action, NULL);

  (void)memset(&new_action, 0, sizeof(struct sigaction));
  new_action.sa_handler = child_handler;
  (void)sigemptyset(&new_action.sa_mask);
  new_action.sa_flags |= SA_RESTART;
  (void)sigaction(SIGCHLD, &new_action, NULL);

  (void)memset(&new_action, 0, sizeof(struct sigaction));
  new_action.sa_handler = SIG_IGN;
  (void)sigemptyset(&new_action.sa_mask);
  new_action.sa_flags |= SA_RESTART;
  (void)sigaction(SIGPIPE, &new_action, NULL);

  for (;;)
  {
    FD_ZERO(&rfds);
    FD_ZERO(&wfds);
    FD_ZERO(&efds);
    max_fd = 0;
    /*
     * Do not arm select for the listener socket if we are not ready
     * to accept another connection.
     */
    if (count_openfd < limit_openfd - OPEN_FD_RESERVE) {
      for (i = 0; i < numsock; i++)
      {
        FD_SET(service_socket[i], &rfds);
        if (service_socket[i] > max_fd)
	max_fd = service_socket[i];
      }
    }
    if (gather_fd != -1)
    {
      FD_SET(gather_fd, &rfds);
#ifndef SCO3
      FD_SET(gather_fd, &efds);
#endif
      if (gather_fd > max_fd)
	max_fd = gather_fd;
    }
    entropy_required = 0;
    for (i = 0; i < max_query; i++)
    {
      if (egd_query[i].fd > max_fd)
	max_fd = egd_query[i].fd;
      FD_SET(egd_query[i].fd, &efds);
      if ((egd_query[i].state == wait_command) ||
	  (egd_query[i].state == wait_second_byte) ||
	  (egd_query[i].state == wait_third_byte) ||
	  (egd_query[i].state == wait_fourth_byte) ||
	  (egd_query[i].state == wait_read))
	FD_SET(egd_query[i].fd, &rfds);
      else if (egd_query[i].state == wait_write)
	FD_SET(egd_query[i].fd, &wfds);
      else if ((egd_query[i].state == wait_entropy1) ||
	       (egd_query[i].state == wait_entropy2))
        entropy_required = 1;
    }

    /*
     * If we just entered the loop and gather for the first time, we
     * don't want to wait. We also want to refill our pool when drained.
     * If there are connections waiting for random numbers to be generated,
     * go ahead.
     */
    if (first_gather || (rand_pool() < (ENTROPY_THRESHOLD)) ||
        (entropy_required && (rand_pool() > 0)))
    {
      timeout.tv_sec = 0;
      timeout.tv_usec = 1;
    }
    else {
      timeout.tv_sec = (seed_stat_interval < seed_ext_interval ?
			 seed_stat_interval : seed_ext_interval);
      timeout.tv_usec = 0;
      if ((gatherer_pid > 0) && (gather_fd < 0))
	timeout.tv_sec = 1;	/* if we are still waiting for a child, don't
				   sit long in select() */
    }
    num = select(max_fd + 1, &rfds, &wfds, &efds, &timeout);
    saved_errno = errno;

    collect_children(&gatherer_pid);

    if (received_sighup) {
      received_sighup = 0;
      if (debug)
	(void)fprintf(stderr, "Received SIGHUP\n");
    }

    if (time(0) >= last_seed_stat + seed_stat_interval) {
      seed_stat();
      last_seed_stat = time(0);
    }

    seed_internal(NULL);

    if (num < 0) {
      if (saved_errno == EINTR)
        continue;		/* Ignore rfds and friends, since invalid */
      else {
	error_fatal("select() failed", saved_errno);
	exit(EXIT_FAILURE);
      }
    }

    /*
     * First thing to do: check, whether new connections are waiting.
     * The queue on the listen() socket is of limited length, so
     * querying processes might run into "connection refused" errors,
     * when the queuelength is exceeded.
     */
    max_query_old = max_query;
    for (i = 0; i < numsock; i++)
    {
      if (count_openfd >= limit_openfd - OPEN_FD_RESERVE) {
	(void)snprintf(msg_buf, sizeof(msg_buf),
		"could not accept connection: no more slots (%d of %d)\n",
		count_openfd, limit_openfd - OPEN_FD_RESERVE);
	msg_buf[sizeof(msg_buf) - 1] = '\0';
	error_notice(msg_buf, 0);
	continue;	/* do not accept new connection */
      }
      if (FD_ISSET(service_socket[i], &rfds))
      {
        addrlen = (SOCKLEN_T) sizeof(addr);
        accept_fd = accept(service_socket[i], &addr, &addrlen);
        if (accept_fd < 0)
	  continue;		/*
				 * Ignore and stay alive 
				 */

	count_openfd++;
	non_blocking(accept_fd, 1);
	close_on_exec(accept_fd, 1);

        /*
         * Create a new structure for the incoming request 
         */
        if (max_query + 1 > alloc_query)
        {
	  egd_query_old = egd_query;
	  if (alloc_query == 0)
	    egd_query = malloc((max_query + 1) * sizeof(egd_query_t));
	  else
	    egd_query =
	        realloc(egd_query_old,
		        (max_query + 1) * sizeof(egd_query_t));
	  if (!egd_query)
	  {
	    error_error("realloc() failed", errno);
	    (void)close(accept_fd);	/*
				 * Better this than complete shut down 
				 */
	    count_openfd--;
	    egd_query = egd_query_old;
	    continue;
	  }
	  alloc_query = max_query + 1;
        }
        /*
         * This routine is safe here, as in case of error we do "continue;"
         * in case of problems. So we have succesfully reached this point.
         */
        max_query++;
        egd_query[max_query - 1].fd = accept_fd;
        egd_query[max_query - 1].state = wait_command;
	if (debug) {
          (void)fprintf(stderr, "Opening service fd %d\n",
	  	egd_query[max_query-1].fd);
	}
	/*
	 * Finally, mix information about the connection into the pool.
	 * Maybe its coming from TCP and has some foreign port number
	 * in it. Only count it as '0', because maybe there is no
	 * entropy in it at all.
	 */
	rand_add(&addr, addrlen, 0.0);
      }
    }


    if (gather_fd != -1) {
      if (FD_ISSET(gather_fd, &rfds)) {
	/*
	 * Bytes are coming back from the gatherer process. Read chunks of
	 * up to 10240 bytes and feed them into the PRNG
	 */
	numbytes = socket_read(gather_fd, gatherbuf, 10240);
	rand_add(gatherbuf, numbytes, est * numbytes);
	if (debug)
	  (void)fprintf(stderr, "Read %d bytes from gatherer\n", numbytes);
	gatherer_bytes += numbytes;
	if ((numbytes <= 0) || (gatherer_bytes >= max_gatherer_bytes)) {
	  if (debug)
	    (void)fprintf(stderr, "Closing connection to gatherer\n");
	  (void)close(gather_fd);
	  gather_fd = -1;
	  count_openfd--;
	}
      }
      else if (FD_ISSET(gather_fd, &efds)) {
	if (debug)
	  (void)fprintf(stderr, "Closing connection to gatherer (efds)\n");
	(void)close(gather_fd);
	gather_fd = -1;
	count_openfd--;
      }
      if (gather_fd == -1) {
	/*
	 * The formerly running gatherer has just been shut down for normal
	 * or error conditions. Choose the next one.
	 */
	gatherer_entry++;
        if (entropy_source[gatherer_entry].path == NULL) {
	  first_gather = 0;	/* done */
	  gatherer_entry = 0;
	}
      }
    }

    collect_children(&gatherer_pid);

    if ((gatherer_pid > 0) &&
	(difftime(time(NULL), gather_start) > seed_ext_interval / 2 + 1)) {
      if (debug)
	(void)fprintf(stderr, "Gathering time exceeded, kill process %ld\n",
		      (long)gatherer_pid);
      if (kill(gatherer_pid, SIGKILL) == -1) {
      	error_error("kill() failed", errno);
      }
      gatherer_pid = -1;
      if (gather_fd != -1) {
	(void)close(gather_fd);
	gather_fd = -1;
	count_openfd--;
	gatherer_entry++;
	if (entropy_source[gatherer_entry].path == NULL) {
	  first_gather = 0;	/* done */
	  gatherer_entry = 0;
	}
      }
    }

    collect_children(&gatherer_pid);

    /*
     * Call a gatherer, if it is time to do so. When starting up, call
     * all gatherers once to obtain initial seeding.
     */
    if (((time(0) >= last_seed_ext + seed_ext_interval) || first_gather ||
	(rand_pool() < (ENTROPY_THRESHOLD))) &&
	(gatherer_pid == -1) && (gather_fd == -1))
    {
      last_seed_ext = time(0);
      /*
       * time to call another gatherer 
       */

      /*
       * Select the next gatherer to be used
       */
      if ((gatherer_entry == 0) &&
		(entropy_source[gatherer_entry].path == NULL)) {
        first_gather = 0;	/* no gatherer available */
        continue;
      }

      if (my_pipe(pipedes) < 0)
	continue;		/*
				 * We cannot do anything about it 
				 */

      est = entropy_source[gatherer_entry].rate; /* for later use */
      gatherer_bytes = 0;

      gatherer_pid = fork();
      if (gatherer_pid == -1) {
	error_error("Could not fork", errno);
	(void)close(pipedes[0]);
	(void)close(pipedes[1]);
	continue;
      }
      if (gatherer_pid == 0) {
	/*
         * Child
	 */
	my_dup2(devnull, STDIN_FILENO);
        my_dup2(pipedes[1], STDOUT_FILENO);
        my_dup2(pipedes[1], STDERR_FILENO);
        (void)close(pipedes[0]);
        (void)close(pipedes[1]);
        (void)close(devnull); 
	if (execl(entropy_source[gatherer_entry].path,
	      entropy_source[gatherer_entry].args[0],
	      entropy_source[gatherer_entry].args[1],
	      entropy_source[gatherer_entry].args[2],
	      entropy_source[gatherer_entry].args[3],
	      entropy_source[gatherer_entry].args[4],
	      NULL) == -1)
	{
		(void)snprintf(msg_buf, sizeof(msg_buf),
			"Failed to execl(%s, %s, %s, %s, %s, %s)",
			entropy_source[gatherer_entry].path,
			entropy_source[gatherer_entry].args[0] ?
			entropy_source[gatherer_entry].args[0] : "",
			entropy_source[gatherer_entry].args[1] ?
			entropy_source[gatherer_entry].args[1] : "",
			entropy_source[gatherer_entry].args[2] ?
			entropy_source[gatherer_entry].args[2] : "",
			entropy_source[gatherer_entry].args[3] ?
			entropy_source[gatherer_entry].args[3] : "",
			entropy_source[gatherer_entry].args[4] ?
			entropy_source[gatherer_entry].args[4] : "");
		msg_buf[sizeof(msg_buf) - 1] = '\0';
		error_fatal(msg_buf, errno);
		_exit(EXIT_FAILURE);
	}
      }
      else {
	/*
	 * Parent
	 */
	(void)close(pipedes[1]);
	gather_fd = pipedes[0];
	count_openfd++;
	non_blocking(gather_fd, 1);
	gather_start = time(NULL);
	if (debug)
	{
	  (void)fprintf(stderr, "Spawned gatherer (pid = %ld): %s (%s",
		(long)gatherer_pid,
		entropy_source[gatherer_entry].path,
		entropy_source[gatherer_entry].args[0]);
	  i = 1;
	  while ((i < 5) && (entropy_source[gatherer_entry].args[i])) {
	    (void)fprintf(stderr, " %s",
	    	entropy_source[gatherer_entry].args[i++]);
	  }
	  (void)fprintf(stderr, ")\n");
	}
	collect_children(&gatherer_pid);
      }
      continue;

    }
    /*
     * Finally, serve the active sockets. First step: check errors reported
     * and mark the corresponding descriptor "to_be_error_closed". Perform
     * the loop only over the sockets already open, as the data returned
     * from select() obviously cannot make sense for the connections
     * freshly opened.
     * Service is in the sequence the fds were opened. The generation of
     * random numbers is performed in a seperate loop later on, as this
     * takes some time. Service all available I/O operations first.
     */
    for (i = 0; i < max_query_old; i++)
    {
      if (FD_ISSET(egd_query[i].fd, &efds))
      {
	if (debug)
	  (void)fprintf(stderr, "Error flagged for service fd %d\n",
	  	egd_query[i].fd);
	egd_query[i].state = to_be_error_closed;
      }
      else if (FD_ISSET(egd_query[i].fd, &rfds) ||
	       FD_ISSET(egd_query[i].fd, &wfds)) {
      switch (egd_query[i].state)
      {
      case wait_command:
	error = socket_read(egd_query[i].fd, &(egd_query[i].command), 1);
	if (error == -1)
	  egd_query[i].state = to_be_error_closed;
	else if (error != 1)
	  egd_query[i].state = to_be_closed;
	else if (egd_query[i].command > 4)
	  egd_query[i].state = to_be_error_closed;
	else if (egd_query[i].command == 0)
	{
	  numbytes = rand_pool();
	  egd_query[i].buffer[0] = numbytes / 16777216;
	  egd_query[i].buffer[1] = (numbytes % 16777216) / 65536;
	  egd_query[i].buffer[2] = (numbytes % 65536) / 256;
	  egd_query[i].buffer[3] = numbytes % 256;
	  egd_query[i].to_process = 4;
	  egd_query[i].yet_processed = 0;
	  egd_query[i].state = wait_write;
	}
	else if ((egd_query[i].command == 1) ||
		 (egd_query[i].command == 2) ||
		 (egd_query[i].command == 3))
	  egd_query[i].state = wait_second_byte;
	else if (egd_query[i].command == 4)
	{
	  egd_query[i].buffer[0] = 12;
	  (void)snprintf((char *) (egd_query[i].buffer + 1), 
			 sizeof(egd_query[i].buffer) - 1, "%12ld",
			 (long)getpid());
	  egd_query[i].buffer[sizeof(egd_query[i].buffer) - 1] = '\0';
	  egd_query[i].to_process = 13;
	  egd_query[i].yet_processed = 0;
	  egd_query[i].state = wait_write;
	}
	break;
      case wait_second_byte:
	error = socket_read(egd_query[i].fd, &(egd_query[i].secbyte), 1);
	if (error != 1)
	  egd_query[i].state = to_be_error_closed;
	else if (egd_query[i].command == 1)
	{
	  seed_internal(NULL);	/* Mix in just before query */
	  seed_stat();
	  if (rand_pool() > 0) {
	    egd_query[i].buffer[0] = (char)egd_query[i].secbyte;
	    egd_query[i].to_process = egd_query[i].secbyte + 1;
            egd_query[i].yet_processed = 0;
            egd_query[i].state = wait_entropy1;
	  }
	  else {
	    numbytes = 0;
	    egd_query[i].buffer[0] = (char)0;
	    egd_query[i].to_process =  1;
	    egd_query[i].yet_processed = 0;
	    egd_query[i].state = wait_write;
	  }
	}
	else if (egd_query[i].command == 2)
	{
	  seed_internal(NULL);	/* Mix in just before query */
	  seed_stat();
	  egd_query[i].to_process = egd_query[i].secbyte;
	  egd_query[i].yet_processed = 0;
	  egd_query[i].state = wait_entropy2;
	}
	else if (egd_query[i].command == 3)
	{
	  egd_query[i].entropy_bits = egd_query[i].secbyte * 256;
	  egd_query[i].state = wait_third_byte;
	}
	break;
      case wait_third_byte:
	error = socket_read(egd_query[i].fd, &(egd_query[i].secbyte), 1);
	if (error != 1)
	  egd_query[i].state = to_be_error_closed;
	else
	{
	  egd_query[i].entropy_bits += egd_query[i].secbyte;
	  egd_query[i].state = wait_fourth_byte;
	}
	break;
      case wait_fourth_byte:
	error = socket_read(egd_query[i].fd, &(egd_query[i].secbyte), 1);
	if (error != 1)
	  egd_query[i].state = to_be_error_closed;
	else
	{
	  egd_query[i].to_process = egd_query[i].secbyte;
	  egd_query[i].yet_processed = 0;
	  egd_query[i].state = wait_read;
	}
	break;
      case wait_read:
	num = egd_query[i].to_process - egd_query[i].yet_processed;
	error = socket_read(egd_query[i].fd, egd_query[i].buffer, num);
	if (error <= 0)
	  egd_query[i].state = to_be_error_closed;
	else
	{
	  rand_add(egd_query[i].buffer, error,
		   (double) error * egd_query[i].entropy_bits / BITS_PER_BYTE /
		   egd_query[i].to_process);
	  egd_query[i].yet_processed += error;
	  if (egd_query[i].yet_processed >= egd_query[i].to_process)
	    egd_query[i].state = wait_command;
	}
	break;
      case wait_write:
	error = socket_write(egd_query[i].fd,
		      &(egd_query[i].buffer[egd_query[i].yet_processed]),
		      egd_query[i].to_process -
		      egd_query[i].yet_processed);
	if (error <= 0)
	  egd_query[i].state = to_be_error_closed;
	else
	{
	  egd_query[i].yet_processed += error;
	  if (egd_query[i].yet_processed == egd_query[i].to_process) {
	    egd_query[i].state = wait_command;
	    (void)fprintf(stderr, "Sent %d bytes to service %d\n",
			  egd_query[i].to_process, egd_query[i].fd);
	  }
	}
	break;
      default:
	break;
      }
      }
    }

    /*
     * Now retrieve entropy for those processes waiting for it.
     * Only retrieve one chunk of entropy, such that we don't hang on
     * here too long. For fairness, we record the location of the last
     * query-connection, so that we can continue with the next one.
     *
     * Calls to rand_bytes() need not be checked for failure, as the
     * rand_pool() check in the loop condition is present.
     */
    for (i = 0; (i < max_query_old) && (rand_pool() > 0); i++) {
      i1 = (prev_location + i) % max_query_old;
      if (egd_query[i1].state == wait_entropy1) {
	seed_internal(NULL);	/* Mix in just before query */
	seed_stat();
	rand_bytes(egd_query[i1].buffer + 1, egd_query[i1].secbyte);
	egd_query[i1].state = wait_write;
	prev_location = (i1 + 1) % max_query_old;
	break;
      }
      if (egd_query[i1].state == wait_entropy2) {
	seed_internal(NULL);	/* Mix in just before query */
	seed_stat();
	rand_bytes(egd_query[i1].buffer, egd_query[i1].secbyte);
	egd_query[i1].state = wait_write;
	prev_location = (i1 + 1) % max_query_old;
	break;
      }
    }

    /*
     * Perform the final cleanup
     */
    for (i = 0; i < max_query; i++) {
      if ((egd_query[i].state == to_be_closed) ||
	  (egd_query[i].state == to_be_error_closed)) {
	if (debug)
	  (void)fprintf(stderr, "Closing service fd %d, error=%d\n",
			  egd_query[i].fd,
			  (egd_query[i].state == to_be_error_closed));
	else if (egd_query[i].state == to_be_error_closed) {
	  (void)snprintf(msg_buf, sizeof(msg_buf),
	  	"closing service fd %d for error.", egd_query[i].fd);
	  msg_buf[sizeof(msg_buf) - 1] = '\0';
	  error_notice(msg_buf, 0);
	}
	(void)close(egd_query[i].fd);
	count_openfd--;
	/* Remove delivered entropy */
	(void)memset(egd_query[i].buffer, 0, 256);
	if (i < prev_location)
	  prev_location--;	/* No need to wrap around, we only have to care
				 * about fairness.
				 */
	if (i < max_query - 1)
	{
	  (void)memmove(egd_query + i, egd_query + max_query - 1,
		  sizeof(egd_query_t));
	  i--;
	}
	max_query--;
      }
    }


    collect_children(&gatherer_pid);

  }

}


===== sha1.c =====
/*
 * PRNGD note:
 * I did not write this part myself, I merely took this item from mhash-0.8.5
 * and include it with my software, as the licensing (stated below) is free!
 * The only changes I made are to the interface. The SHA structure is now
 * called SHA1_CTX, the functions are called SHA1_*(). Datatypes are
 * "unsigned int" for 32bits and "unsigned char" for 8bits (this is at least
 * true for the platforms PRNGD runs on :-).
 */

/* sha.c - Implementation of the Secure Hash Algorithm
 *
 * Copyright (C) 1995, A.M. Kuchling
 *
 * Distribute and use freely; there are no restrictions on further 
 * dissemination and usage except those imposed by the laws of your 
 * country of residence.
 *
 * Adapted to pike and some cleanup by Niels Möller.
 */

/* $Id: sha1.c,v 1.2 2001/02/22 19:14:56 jaenicke Exp $ */

/* SHA: NIST's Secure Hash Algorithm */

/* Based on SHA code originally posted to sci.crypt by Peter Gutmann
   in message <30ajo5$oe8@ccu2.auckland.ac.nz>.
   Modified to test for endianness on creation of SHA objects by AMK.
   Also, the original specification of SHA was found to have a weakness
   by NSA/NIST.  This code implements the fixed version of SHA.
*/

/* Here's the first paragraph of Peter Gutmann's posting:
   
The following is my SHA (FIPS 180) code updated to allow use of the "fixed"
SHA, thanks to Jim Gillogly and an anonymous contributor for the information on
what's changed in the new version.  The fix is a simple change which involves
adding a single rotate in the initial expansion function.  It is unknown
whether this is an optimal solution to the problem which was discovered in the
SHA or whether it's simply a bandaid which fixes the problem with a minimum of
effort (for example the reengineering of a great many Capstone chips).
*/

#include <string.h>
#include "prngd.h"

void SHA1_copy(SHA1_CTX *dest, SHA1_CTX *src)
{
  int i;

  dest->count_l=src->count_l;
  dest->count_h=src->count_h;
  for(i=0; i<SHA_DIGESTLEN; i++)
    dest->digest[i]=src->digest[i];
  for(i=0; i < src->index; i++)
    dest->block[i] = src->block[i];
  dest->index = src->index;
}


/* The SHA f()-functions.  The f1 and f3 functions can be optimized to
   save one boolean operation each - thanks to Rich Schroeppel,
   rcs@cs.arizona.edu for discovering this */

/*#define f1(x,y,z) ( ( x & y ) | ( ~x & z ) )          // Rounds  0-19 */
#define f1(x,y,z)   ( z ^ ( x & ( y ^ z ) ) )           /* Rounds  0-19 */
#define f2(x,y,z)   ( x ^ y ^ z )                       /* Rounds 20-39 */
/*#define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) )   // Rounds 40-59 */
#define f3(x,y,z)   ( ( x & y ) | ( z & ( x | y ) ) )   /* Rounds 40-59 */
#define f4(x,y,z)   ( x ^ y ^ z )                       /* Rounds 60-79 */

/* The SHA Mysterious Constants */

#define K1  0x5A827999L                                 /* Rounds  0-19 */
#define K2  0x6ED9EBA1L                                 /* Rounds 20-39 */
#define K3  0x8F1BBCDCL                                 /* Rounds 40-59 */
#define K4  0xCA62C1D6L                                 /* Rounds 60-79 */

/* SHA initial values */

#define h0init  0x67452301L
#define h1init  0xEFCDAB89L
#define h2init  0x98BADCFEL
#define h3init  0x10325476L
#define h4init  0xC3D2E1F0L

/* 32-bit rotate left - kludged with shifts */

#define ROTL(n,X)  ( ( (X) << (n) ) | ( (X) >> ( 32 - (n) ) ) )

/* The initial expanding function.  The hash function is defined over an
   80-word expanded input array W, where the first 16 are copies of the input
   data, and the remaining 64 are defined by

        W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ]

   This implementation generates these values on the fly in a circular
   buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
   optimization.

   The updated SHA changes the expanding function by adding a rotate of 1
   bit.  Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor
   for this information */

#define expand(W,i) ( W[ i & 15 ] = \
		      ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
				 W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) )


/* The prototype SHA sub-round.  The fundamental sub-round is:

        a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data;
        b' = a;
        c' = ROTL( 30, b );
        d' = c;
        e' = d;

   but this is implemented by unrolling the loop 5 times and renaming the
   variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration.
   This code is then replicated 20 times for each of the 4 functions, using
   the next 20 values from the W[] array each time */

#define subRound(a, b, c, d, e, f, k, data) \
    ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )

/* Initialize the SHA values */

void SHA1_init(SHA1_CTX *ctx)
{
  /* Set the h-vars to their initial values */
#ifndef lint
  ctx->digest[ 0 ] = h0init;
  ctx->digest[ 1 ] = h1init; /*CONSTANTCONDITION*/
  ctx->digest[ 2 ] = h2init;
  ctx->digest[ 3 ] = h3init;
  ctx->digest[ 4 ] = h4init;
#endif /* lint */

  /* Initialize bit count */
  ctx->count_l = ctx->count_h = 0;
  
  /* Initialize buffer */
  ctx->index = 0;
}

/* Perform the SHA transformation.  Note that this code, like MD5, seems to
   break some optimizing compilers due to the complexity of the expressions
   and the size of the basic block.  It may be necessary to split it into
   sections, e.g. based on the four subrounds

   Note that this function destroys the data area */

static void sha_transform(SHA1_CTX *ctx, unsigned int *data )
{
  unsigned int A, B, C, D, E;     /* Local vars */

  /* Set up first buffer and local data buffer */
  A = ctx->digest[0];
  B = ctx->digest[1];
  C = ctx->digest[2];
  D = ctx->digest[3];
  E = ctx->digest[4];

  /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
  subRound( A, B, C, D, E, f1, K1, data[ 0] );
  subRound( E, A, B, C, D, f1, K1, data[ 1] );
  subRound( D, E, A, B, C, f1, K1, data[ 2] );
  subRound( C, D, E, A, B, f1, K1, data[ 3] );
  subRound( B, C, D, E, A, f1, K1, data[ 4] );
  subRound( A, B, C, D, E, f1, K1, data[ 5] );
  subRound( E, A, B, C, D, f1, K1, data[ 6] );
  subRound( D, E, A, B, C, f1, K1, data[ 7] );
  subRound( C, D, E, A, B, f1, K1, data[ 8] );
  subRound( B, C, D, E, A, f1, K1, data[ 9] );
  subRound( A, B, C, D, E, f1, K1, data[10] );
  subRound( E, A, B, C, D, f1, K1, data[11] );
  subRound( D, E, A, B, C, f1, K1, data[12] );
  subRound( C, D, E, A, B, f1, K1, data[13] );
  subRound( B, C, D, E, A, f1, K1, data[14] );
  subRound( A, B, C, D, E, f1, K1, data[15] );
  subRound( E, A, B, C, D, f1, K1, expand( data, 16 ) );
  subRound( D, E, A, B, C, f1, K1, expand( data, 17 ) );
  subRound( C, D, E, A, B, f1, K1, expand( data, 18 ) );
  subRound( B, C, D, E, A, f1, K1, expand( data, 19 ) );

  subRound( A, B, C, D, E, f2, K2, expand( data, 20 ) );
  subRound( E, A, B, C, D, f2, K2, expand( data, 21 ) );
  subRound( D, E, A, B, C, f2, K2, expand( data, 22 ) );
  subRound( C, D, E, A, B, f2, K2, expand( data, 23 ) );
  subRound( B, C, D, E, A, f2, K2, expand( data, 24 ) );
  subRound( A, B, C, D, E, f2, K2, expand( data, 25 ) );
  subRound( E, A, B, C, D, f2, K2, expand( data, 26 ) );
  subRound( D, E, A, B, C, f2, K2, expand( data, 27 ) );
  subRound( C, D, E, A, B, f2, K2, expand( data, 28 ) );
  subRound( B, C, D, E, A, f2, K2, expand( data, 29 ) );
  subRound( A, B, C, D, E, f2, K2, expand( data, 30 ) );
  subRound( E, A, B, C, D, f2, K2, expand( data, 31 ) );
  subRound( D, E, A, B, C, f2, K2, expand( data, 32 ) );
  subRound( C, D, E, A, B, f2, K2, expand( data, 33 ) );
  subRound( B, C, D, E, A, f2, K2, expand( data, 34 ) );
  subRound( A, B, C, D, E, f2, K2, expand( data, 35 ) );
  subRound( E, A, B, C, D, f2, K2, expand( data, 36 ) );
  subRound( D, E, A, B, C, f2, K2, expand( data, 37 ) );
  subRound( C, D, E, A, B, f2, K2, expand( data, 38 ) );
  subRound( B, C, D, E, A, f2, K2, expand( data, 39 ) );

#ifndef lint
  subRound( A, B, C, D, E, f3, K3, expand( data, 40 ) );
  subRound( E, A, B, C, D, f3, K3, expand( data, 41 ) );
  subRound( D, E, A, B, C, f3, K3, expand( data, 42 ) );
  subRound( C, D, E, A, B, f3, K3, expand( data, 43 ) );
  subRound( B, C, D, E, A, f3, K3, expand( data, 44 ) );
  subRound( A, B, C, D, E, f3, K3, expand( data, 45 ) );
  subRound( E, A, B, C, D, f3, K3, expand( data, 46 ) );
  subRound( D, E, A, B, C, f3, K3, expand( data, 47 ) );
  subRound( C, D, E, A, B, f3, K3, expand( data, 48 ) );
  subRound( B, C, D, E, A, f3, K3, expand( data, 49 ) );
  subRound( A, B, C, D, E, f3, K3, expand( data, 50 ) );
  subRound( E, A, B, C, D, f3, K3, expand( data, 51 ) );
  subRound( D, E, A, B, C, f3, K3, expand( data, 52 ) );
  subRound( C, D, E, A, B, f3, K3, expand( data, 53 ) );
  subRound( B, C, D, E, A, f3, K3, expand( data, 54 ) );
  subRound( A, B, C, D, E, f3, K3, expand( data, 55 ) );
  subRound( E, A, B, C, D, f3, K3, expand( data, 56 ) );
  subRound( D, E, A, B, C, f3, K3, expand( data, 57 ) );
  subRound( C, D, E, A, B, f3, K3, expand( data, 58 ) );
  subRound( B, C, D, E, A, f3, K3, expand( data, 59 ) );

  subRound( A, B, C, D, E, f4, K4, expand( data, 60 ) );
  subRound( E, A, B, C, D, f4, K4, expand( data, 61 ) );
  subRound( D, E, A, B, C, f4, K4, expand( data, 62 ) );
  subRound( C, D, E, A, B, f4, K4, expand( data, 63 ) );
  subRound( B, C, D, E, A, f4, K4, expand( data, 64 ) );
  subRound( A, B, C, D, E, f4, K4, expand( data, 65 ) );
  subRound( E, A, B, C, D, f4, K4, expand( data, 66 ) );
  subRound( D, E, A, B, C, f4, K4, expand( data, 67 ) );
  subRound( C, D, E, A, B, f4, K4, expand( data, 68 ) );
  subRound( B, C, D, E, A, f4, K4, expand( data, 69 ) );
  subRound( A, B, C, D, E, f4, K4, expand( data, 70 ) );
  subRound( E, A, B, C, D, f4, K4, expand( data, 71 ) );
  subRound( D, E, A, B, C, f4, K4, expand( data, 72 ) );
  subRound( C, D, E, A, B, f4, K4, expand( data, 73 ) );
  subRound( B, C, D, E, A, f4, K4, expand( data, 74 ) );
  subRound( A, B, C, D, E, f4, K4, expand( data, 75 ) );
  subRound( E, A, B, C, D, f4, K4, expand( data, 76 ) );
  subRound( D, E, A, B, C, f4, K4, expand( data, 77 ) );
  subRound( C, D, E, A, B, f4, K4, expand( data, 78 ) );
  subRound( B, C, D, E, A, f4, K4, expand( data, 79 ) );
#endif /* lint */

  /* Build message digest */
  ctx->digest[0] += A;
  ctx->digest[1] += B;
  ctx->digest[2] += C;
  ctx->digest[3] += D;
  ctx->digest[4] += E;
}

#if 1

#ifndef EXTRACT_UCHAR
#define EXTRACT_UCHAR(p)  (*(unsigned char *)(p))
#endif

#define STRING2INT(s) ((((((EXTRACT_UCHAR(s) << 8)    \
			 | EXTRACT_UCHAR(s+1)) << 8)  \
			 | EXTRACT_UCHAR(s+2)) << 8)  \
			 | EXTRACT_UCHAR(s+3))
#else
unsigned int STRING2INT(unsigned char *s)
{
  unsigned int r;
  int i;
  
  for (i = 0, r = 0; i < 4; i++, s++)
    r = (r << 8) | *s;
  return r;
}
#endif

static void sha_block(SHA1_CTX *ctx, const unsigned char *block)
{
  unsigned int data[SHA_DATALEN];
  int i;
  
  /* Update block count */
  if (!++ctx->count_l)
    ++ctx->count_h;

  /* Endian independent conversion */
  for (i = 0; i<SHA_DATALEN; i++, block += 4)
    data[i] = STRING2INT(block);

  sha_transform(ctx, data);
}

void SHA1_update(SHA1_CTX *ctx, const unsigned char *buffer, unsigned int len)
{
  if (ctx->index)
    { /* Try to fill partial block */
      unsigned left = SHA_DATASIZE - ctx->index;
      if (len < left)
	{
	  (void)memmove(ctx->block + ctx->index, buffer, len);
	  ctx->index += len;
	  return; /* Finished */
	}
      else
	{
	  (void)memmove(ctx->block + ctx->index, buffer, left);
	  sha_block(ctx, ctx->block);
	  buffer += left;
	  len -= left;
	}
    }
  while (len >= SHA_DATASIZE)
    {
      sha_block(ctx, buffer);
      buffer += SHA_DATASIZE;
      len -= SHA_DATASIZE;
    }
  ctx->index = len;
  if (ctx->index) 
    /* Buffer leftovers */
    (void)memmove(ctx->block, buffer, len);
}
	  
/* Final wrapup - pad to SHA_DATASIZE-byte boundary with the bit pattern
   1 0* (64-bit count of bits processed, MSB-first) */

void SHA1_final(SHA1_CTX *ctx)
{
  unsigned int data[SHA_DATALEN];
  int i;
  int words;
  
  i = ctx->index;
  /* Set the first char of padding to 0x80.  This is safe since there is
     always at least one byte free */
  ctx->block[i++] = 0x80;

  /* Fill rest of word */
  for( ; i & 3; i++)
    ctx->block[i] = 0;

  /* i is now a multiple of the word size 4 */
  words = i >> 2;
  for (i = 0; i < words; i++)
    data[i] = STRING2INT(ctx->block + 4*i);
  
  if (words > (SHA_DATALEN-2))
    { /* No room for length in this block. Process it and
       * pad with another one */
      for (i = words ; i < SHA_DATALEN; i++)
	data[i] = 0;
      sha_transform(ctx, data);
      for (i = 0; i < (SHA_DATALEN-2); i++)
	data[i] = 0;
    }
  else
    for (i = words ; i < SHA_DATALEN - 2; i++)
      data[i] = 0;
  /* Theres 512 = 2^9 bits in one block */
  data[SHA_DATALEN-2] = (ctx->count_h << 9) | (ctx->count_l >> 23);
  data[SHA_DATALEN-1] = (ctx->count_l << 9) | (ctx->index << 3);
  sha_transform(ctx, data);
}

void SHA1_digest(SHA1_CTX *ctx, unsigned char *s)
{
  int i;

  for (i = 0; i < SHA_DIGESTLEN; i++)
    {
      *s++ =         ctx->digest[i] >> 24;
      *s++ = 0xff & (ctx->digest[i] >> 16);
      *s++ = 0xff & (ctx->digest[i] >> 8);
      *s++ = 0xff &  ctx->digest[i];
    }
}


===== sockio.c =====
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "prngd.h"

/*
 * Handle read and write operations so that they are protected against
 * EINTR and EAGAIN "non-errors".
 */
ssize_t socket_read(int fildes, void *buf, size_t nbyte)
{
  ssize_t retval;

  for (;;) {
    retval = read(fildes, buf, nbyte);
    if (retval >= 0)
      break;
    else if (errno == EINTR)
      continue;
    else if (errno == EAGAIN)
      continue;
#ifdef EWOULDBLOCK
    else if (errno == EWOULDBLOCK)
      continue;
#endif
    else if (retval == -1) {
      error_error("read() in socket_read() failed", errno);
      break;
    }
    else
      break;
  }

  return retval;
}

ssize_t socket_write(int fildes, void *buf, size_t nbyte)
{
  ssize_t retval;

  for (;;) {
    retval = write(fildes, buf, nbyte);
    if (retval >= 0)
      break;
    else if (errno == EINTR)
      continue;
    else if (errno == EAGAIN)
      continue;
#ifdef EWOULDBLOCK
    else if (errno == EWOULDBLOCK)
      continue;
#endif
    else if (errno == EPIPE) {
      error_notice("write() in socket_write() failed", errno);
      break;
    }
    else if (retval == -1) {
      error_error("write() in socket_write() failed", errno);
      break;
    }
    else
      break;
  }

  return retval;
}


===== tcp_socket.c =====
/*
 * Handle TCP sockets.
 */
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "prngd.h"

/*
 * Open a connection to the specified peer. Syntax for the connection is:
 * tcp/address:port. Currently exactly tcp/localhost:port is supported.
 * Most errors are considered fatal, that a connection cannot be opened
 * (e.g. since no peer is listening) is not considered fatal.
 */
int tcp_connect(const char *connection, int non_block, int close_exec)
{
  struct sockaddr_in sockin;
  int sockfd, port;
  char msg_buf[1024];

  if (strncmp(connection, "tcp/localhost:", strlen("tcp/localhost:"))) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
		   "Invalid TCP port specification: %s\n", connection);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, 0);
    exit(EXIT_FAILURE);
  }

  port = atoi(connection + strlen("tcp/localhost:"));
  if (port <= 0) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
		   "Invalid port number %d from %s\n", port, connection);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, 0);
    exit(EXIT_FAILURE);
  }

  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd < 0) {
    error_fatal("Could not create socket", errno);
    exit(EXIT_FAILURE);
  }

  /*
   * Bind the socket to the TCP port.
   */
  (void)memset(&sockin, 0, sizeof(sockin));
  sockin.sin_family = AF_INET;
  sockin.sin_port = htons(port);
  sockin.sin_addr.s_addr = inet_addr("127.0.0.1");

  if (connect(sockfd, (struct sockaddr *) &sockin, sizeof(sockin)) < 0) {
    (void)close(sockfd);
    sockfd = -1;
  }
  else {
    non_blocking(sockfd, non_block);
    close_on_exec(sockfd, close_exec);
  }

  return sockfd;
}


/*
 * Initiate a listener socket on the specified connection. Syntax for
 * the connection is: tcp/address:port. Currently exactly tcp/localhost:port
 * is supported. All errors are considered fatal.
 */
int tcp_listen(const char *connection, int non_block, int close_exec)
{
  struct sockaddr_in sockin;
  int sockfd, port, on = 1;
  char msg_buf[1024];

  if (strncmp(connection, "tcp/localhost:", strlen("tcp/localhost:"))) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
		   "Invalid TCP port specification: %s\n", connection);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, 0);
    exit(EXIT_FAILURE);
  }

  port = atoi(connection + strlen("tcp/localhost:"));
  if (port <= 0) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
		   "Invalid port number %d from %s\n", port, connection);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, 0);
    exit(EXIT_FAILURE);
  }

  sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (sockfd < 0)
  {
    error_fatal("Could not create socket", errno);
    exit(EXIT_FAILURE);
  }
  non_blocking(sockfd, non_block);
  close_on_exec(sockfd, close_exec);

  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on,
		 (SOCKLEN_T) sizeof(on)) < 0) {
    error_fatal("Could not set SO_REUSEADDR", errno);
    exit(EXIT_FAILURE);
  }
  if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &on,
		 (SOCKLEN_T) sizeof(on)) < 0) {
    error_fatal("Could not set SO_KEEPALIVE", errno);
    exit(EXIT_FAILURE);
  }
  /*
   * Bind the socket to the TCP port.
   */
  (void)memset(&sockin, 0, sizeof(sockin));
  sockin.sin_family = AF_INET;
  sockin.sin_port = htons(port);
  sockin.sin_addr.s_addr = inet_addr("127.0.0.1");
  if (bind(sockfd, (struct sockaddr *) &sockin, sizeof(sockin)) < 0)
  {
    (void)snprintf(msg_buf, sizeof(msg_buf),
		   "Could not bind socket to %s", connection);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, errno);
    exit(EXIT_FAILURE);
  }
  if (listen(sockfd, SOMAXCONN) < 0)
  {
    error_fatal("Could not listen on socket", errno);
    exit(EXIT_FAILURE);
  }

  return sockfd;
}


===== tools/prngd-ctl.c =====
/*
 * $Id: prngd-ctl.c,v 1.2 2004/05/17 07:19:49 jaenicke Exp $
 *
 * Author:
 * Thomas Binder <binder@arago.de>
 *
 * Purpose:
 * Command line utility to query an egd-type socket. write-command currently
 * not implemented!
 *
 * Usage:
 * 1. prngd-ctl path-to-socket get
 *    -> prints number of available entropy bits
 *
 * 2. prngd-ctl path-to-socket read number-of-bytes
 *    -> reads number-of-bytes random bytes and prints them (unencoded!)
 *
 * 3. prngd-ctl path-to-socket readb number-of-bytes
 *    -> reads (blocking) number-of-bytes random bytes and prints them
 *       (unencoded!)
 *
 * 4. prngd-ctl path-to-socket pid
 *    -> prints the corresponding prngd's (or egd's) pid
 *
 * License:
 * Copyright (c) 2002 Thomas Binder.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>

static int cmd_get(int sd);
static int cmd_read(int sd, size_t bytes);
static int cmd_readb(int sd, size_t bytes);
static int cmd_pid(int sd);

int main(int argc, char *argv[])
{
    int		    sd = -1,
		    socklen,
		    ret;
    long	    bytes;
    char	    *p;
    struct sockaddr sock, *dest;

    if (argc < 3)
    {
usage:
	fprintf(stderr, "Usage: %s path-to-socket cmd [args]\n", argv[0]);
	if (sd != -1)
	    close(sd);
	exit(1);
    }
    sd = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sd == -1)
    {
	perror("socket");
	exit(1);
    }

    socklen = strlen(argv[1]) + 1 + sizeof(sock) - sizeof(sock.sa_data);
    if ((dest = (struct sockaddr*)malloc( socklen)) == NULL)
    {
	perror("malloc dest");
	close(sd);
	exit(1);
    }
    memset(dest, 0, socklen);
    dest->sa_family = AF_UNIX;
    strcpy(dest->sa_data, argv[1]);
    if (connect(sd, dest, socklen) == -1)
    {
	perror(argv[1]);
	close(sd);
	exit(1);
    }
    if (!strcasecmp(argv[2], "get"))
    {
	if (argc != 3)
	    goto usage;
	ret = cmd_get(sd);
    }
    else if (!strcasecmp(argv[2], "read"))
    {
	if (argc != 4)
	    goto usage;
	bytes = strtoul(argv[3], &p, 0);
	if (*p || (bytes < 0) || (bytes > 255))
	{
	    fprintf(stderr, "%s: Illegal number\n", argv[3]);
	    close(sd);
	    exit(1);
	}
	ret = cmd_read(sd, (size_t)bytes);
    }
    else if (!strcasecmp(argv[2], "readb"))
    {
	if (argc != 4)
	    goto usage;
	bytes = strtoul(argv[3], &p, 0);
	if (*p || (bytes < 0) || (bytes > 255))
	{
	    fprintf(stderr, "%s: Illegal number\n", argv[3]);
	    close(sd);
	    exit(1);
	}
	ret = cmd_readb(sd, (size_t)bytes);
    }
    else if (!strcasecmp(argv[2], "pid"))
    {
	if (argc != 3)
	    goto usage;
	ret = cmd_pid(sd);
    }
    else
	goto usage;
    close(sd);
    exit(ret);
}

static int cmd_get(int sd)
{
    ssize_t read_bytes,
	    wrote_bytes;
    char    buf[257];
    long    amount;

    buf[0] = 0;
    wrote_bytes = write(sd, buf, 1);
    if (wrote_bytes != (ssize_t)1)
    {
	fprintf(stderr, "write() to socket failed\n");
	return(1);
    }
    read_bytes = read(sd, buf, 4);
    if (read_bytes != (ssize_t)4)
    {
	fprintf(stderr, "read() from socket failed\n");
	return(1);
    }
    amount = ((int)buf[0] & 0xff) * 16777216;
    amount += ((int)buf[1] & 0xff) * 65536;
    amount += ((int)buf[2] & 0xff) * 256;
    amount += (int)buf[3] & 0xff;
    printf("%ld\n", amount);
    return(0);
}

static int cmd_read(int sd, size_t bytes)
{
    ssize_t read_bytes,
	    wrote_bytes;
    size_t  to_read;
    char    buf[257];

    buf[0] = 1;
    buf[1] = (char)bytes;
    wrote_bytes = write(sd, buf, 2);
    if (wrote_bytes != (ssize_t)2)
    {
	fprintf(stderr, "write() to socket failed\n");
	return(1);
    }
    read_bytes = read(sd, buf, 1);
    if (read_bytes != (ssize_t)1)
    {
	fprintf(stderr, "read() from socket failed\n");
	return(1);
    }
    to_read = (size_t)((int)buf[0] & 0xff);
    read_bytes = read(sd, buf, to_read);
    if (read_bytes != to_read)
    {
	fprintf(stderr, "read() from socket failed\n");
	return(1);
    }
    write(STDOUT_FILENO, buf, to_read);
    return(0);
}

static int cmd_readb(int sd, size_t bytes)
{
    ssize_t read_bytes,
	    wrote_bytes;
    char    buf[257];

    buf[0] = 2;
    buf[1] = (char)bytes;
    wrote_bytes = write(sd, buf, 2);
    if (wrote_bytes != (ssize_t)2)
    {
	fprintf(stderr, "write() to socket failed\n");
	return(1);
    }
    while (bytes)
    {
	read_bytes = read(sd, buf, bytes);
	if (read_bytes == -1)
	{
	    fprintf(stderr, "read() from socket failed\n");
	    return(1);
	}
	if (read_bytes == 0)
	    break;
	write(STDOUT_FILENO, buf, read_bytes);
	bytes -= read_bytes;
    }
    return(0);
}

static int cmd_pid(int sd)
{
    ssize_t read_bytes,
	    wrote_bytes;
    size_t  to_read;
    char    buf[257];

    buf[0] = 4;
    wrote_bytes = write(sd, buf, 1);
    if (wrote_bytes != (ssize_t)1)
    {
	fprintf(stderr, "write() to socket failed\n");
	return(1);
    }
    read_bytes = read(sd, buf, 1);
    if (read_bytes != (ssize_t)1)
    {
	fprintf(stderr, "read() from socket failed\n");
	return(1);
    }
    to_read = (size_t)((int)buf[0] & 0xff);
    read_bytes = read(sd, buf, to_read);
    if (read_bytes != to_read)
    {
	fprintf(stderr, "read() from socket failed\n");
	return(1);
    }
    buf[to_read] = 0;
    puts(buf);
    return(0);
}

/* EOF */


===== unix_socket.c =====
/*
 * Handle UNIX sockets.
 */
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>

#include "prngd.h"

#ifdef NO_UNIX_SOCKET
int unix_connect(const char *connection, int non_block, int close_exec)
{
  error_error("No unix domain sockets on this system", EINVAL);
  return -1;
}

int unix_listen(const char *connection, int non_block, int close_exec)
{
  error_fatal("No unix domain sockets on this system", EINVAL);
  exit(EXIT_FAILURE);
}
#else

#include <sys/un.h>

/*
 * Open a connection to the specified peer. Most errors are considered fatal,
 * that a connection cannot be opened (e.g. since no peer is listening) is not
 * considered fatal.
 */
int unix_connect(const char *connection, int non_block, int close_exec)
{
  struct sockaddr_un sockun;
  int sockfd;
  char msg_buf[1024];


  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (sockfd < 0)
  {
    error_fatal("Could not create socket", errno);
    exit(EXIT_FAILURE);
  }

  (void)memset(&sockun, 0, sizeof(sockun));
  sockun.sun_family = AF_UNIX;
  if (sizeof(sockun.sun_path) < strlen(connection) + 1) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
		   "Sockfilename too long: %s, maxlen=%ld\n", connection,
		   (long int)sizeof(sockun.sun_path));
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_error(msg_buf, 0);
    exit(EXIT_FAILURE);
  }
  (void)strcpy(sockun.sun_path, connection);

  if (connect(sockfd, (struct sockaddr *) &sockun, sizeof(sockun)) < 0) {
    (void)close(sockfd);
    sockfd = -1;
  }
  else {
    non_blocking(sockfd, non_block);
    close_on_exec(sockfd, close_exec);
  }

  return sockfd;
}

/*
 * Initiate a listener socket on the specified path. All errors are
 * considered fatal.
 */
int unix_listen(const char *connection, int non_block, int close_exec)
{
  struct sockaddr_un sockun;
  int sockfd;
  char msg_buf[1024];

  sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (sockfd < 0)
  {
    error_fatal("Could not create socket", errno);
    exit(EXIT_FAILURE);
  }
  non_blocking(sockfd, non_block);
  close_on_exec(sockfd, close_exec);

  (void)memset(&sockun, 0, sizeof(sockun));
  sockun.sun_family = AF_UNIX;
  if (sizeof(sockun.sun_path) < strlen(connection) + 1) {
    (void)snprintf(msg_buf, sizeof(msg_buf),
		   "Sockfilename too long: %s, maxlen=%ld\n", connection,
		   (long int)sizeof(sockun.sun_path));
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_error(msg_buf, 0);
    exit(EXIT_FAILURE);
  }
  (void)strcpy(sockun.sun_path, connection);

  /*
   * Bind the socket to the path.
   */
  if (bind(sockfd, (struct sockaddr *) &sockun, sizeof(sockun)) < 0)
  {
    (void)snprintf(msg_buf, sizeof(msg_buf),
		   "Could not bind socket to %s", connection);
    msg_buf[sizeof(msg_buf) - 1] = '\0';
    error_fatal(msg_buf, errno);
    exit(EXIT_FAILURE);
  }
  if (listen(sockfd, SOMAXCONN) < 0)
  {
    error_fatal("Could not listen on socket", errno);
    exit(EXIT_FAILURE);
  }

  return sockfd;
}

#endif
