summaryrefslogtreecommitdiff
path: root/cipher/rndunix.c
diff options
context:
space:
mode:
Diffstat (limited to 'cipher/rndunix.c')
-rw-r--r--cipher/rndunix.c820
1 files changed, 0 insertions, 820 deletions
diff --git a/cipher/rndunix.c b/cipher/rndunix.c
deleted file mode 100644
index 71f75dfc..00000000
--- a/cipher/rndunix.c
+++ /dev/null
@@ -1,820 +0,0 @@
-/****************************************************************************
- * *
- * BeOS Randomness-Gathering Code *
- * Copyright Peter Gutmann, Paul Kendall, and Chris Wedgwood 1996-1998 *
- * Copyright (C) 1998, 1999 Werner Koch
- * *
- ****************************************************************************/
-
-/* General includes */
-
-#include <config.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-
-/* OS-specific includes */
-
-#ifdef __osf__
- /* Somewhere in the morass of system-specific cruft which OSF/1 pulls in
- * via the following includes are various endianness defines, so we
- * undefine the cryptlib ones, which aren't really needed for this module
- * anyway */
-#undef BIG_ENDIAN
-#undef LITTLE_ENDIAN
-#endif /* __osf__ */
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <pwd.h>
-#ifndef __QNX__
-#include <sys/errno.h>
-#include <sys/ipc.h>
-#endif /* __QNX__ */
-#include <sys/time.h> /* SCO and SunOS need this before resource.h */
-#ifndef __QNX__
-#include <sys/resource.h>
-#endif /* __QNX__ */
-#ifdef _AIX
-#include <sys/select.h>
-#endif /* _AIX */
-#ifndef __QNX__
-#include <sys/shm.h>
-#include <sys/signal.h>
-#endif /* __QNX__ */
-#include <sys/stat.h>
-#include <sys/types.h> /* Verschiedene komische Typen */
-#if defined( __hpux ) && ( OS_VERSION == 9 )
-#include <vfork.h>
-#endif /* __hpux 9.x, after that it's in unistd.h */
-#include <sys/wait.h>
-/* #include <kitchensink.h> */
-#include <errno.h>
-
-#include "types.h" /* for byte and u32 typedefs */
-#ifndef IS_MODULE
-#include "dynload.h"
-#endif
-#include "util.h"
-
-#ifndef EAGAIN
- #define EAGAIN EWOULDBLOCK
-#endif
-
-#define GATHER_BUFSIZE 49152 /* Usually about 25K are filled */
-
-/* The structure containing information on random-data sources. Each
- * record contains the source and a relative estimate of its usefulness
- * (weighting) which is used to scale the number of kB of output from the
- * source (total = data_bytes / usefulness). Usually the weighting is in the
- * range 1-3 (or 0 for especially useless sources), resulting in a usefulness
- * rating of 1...3 for each kB of source output (or 0 for the useless
- * sources).
- *
- * If the source is constantly changing (certain types of network statistics
- * have this characteristic) but the amount of output is small, the weighting
- * is given as a negative value to indicate that the output should be treated
- * as if a minimum of 1K of output had been obtained. If the source produces
- * a lot of output then the scale factor is fractional, resulting in a
- * usefulness rating of < 1 for each kB of source output.
- *
- * In order to provide enough randomness to satisfy the requirements for a
- * slow poll, we need to accumulate at least 20 points of usefulness (a
- * typical system should get about 30 points).
- *
- * Some potential options are missed out because of special considerations.
- * pstat -i and pstat -f can produce amazing amounts of output (the record
- * is 600K on an Oracle server) which floods the buffer and doesn't yield
- * anything useful (apart from perhaps increasing the entropy of the vmstat
- * output a bit), so we don't bother with this. pstat in general produces
- * quite a bit of output, but it doesn't change much over time, so it gets
- * very low weightings. netstat -s produces constantly-changing output but
- * also produces quite a bit of it, so it only gets a weighting of 2 rather
- * than 3. The same holds for netstat -in, which gets 1 rather than 2.
- *
- * Some binaries are stored in different locations on different systems so
- * alternative paths are given for them. The code sorts out which one to
- * run by itself, once it finds an exectable somewhere it moves on to the
- * next source. The sources are arranged roughly in their order of
- * usefulness, occasionally sources which provide a tiny amount of
- * relatively useless data are placed ahead of ones which provide a large
- * amount of possibly useful data because another 100 bytes can't hurt, and
- * it means the buffer won't be swamped by one or two high-output sources.
- * All the high-output sources are clustered towards the end of the list
- * for this reason. Some binaries are checked for in a certain order, for
- * example under Slowaris /usr/ucb/ps understands aux as an arg, but the
- * others don't. Some systems have conditional defines enabling alternatives
- * to commands which don't understand the usual options but will provide
- * enough output (in the form of error messages) to look like they're the
- * real thing, causing alternative options to be skipped (we can't check the
- * return either because some commands return peculiar, non-zero status even
- * when they're working correctly).
- *
- * In order to maximise use of the buffer, the code performs a form of run-
- * length compression on its input where a repeated sequence of bytes is
- * replaced by the occurrence count mod 256. Some commands output an awful
- * lot of whitespace, this measure greatly increases the amount of data we
- * can fit in the buffer.
- *
- * When we scale the weighting using the SC() macro, some preprocessors may
- * give a division by zero warning for the most obvious expression
- * 'weight ? 1024 / weight : 0' (and gcc 2.7.2.2 dies with a division by zero
- * trap), so we define a value SC_0 which evaluates to zero when fed to
- * '1024 / SC_0' */
-
-#define SC( weight ) ( 1024 / weight ) /* Scale factor */
-#define SC_0 16384 /* SC( SC_0 ) evalutes to 0 */
-
-static struct RI {
- const char *path; /* Path to check for existence of source */
- const char *arg; /* Args for source */
- const int usefulness; /* Usefulness of source */
- FILE *pipe; /* Pipe to source as FILE * */
- int pipeFD; /* Pipe to source as FD */
- pid_t pid; /* pid of child for waitpid() */
- int length; /* Quantity of output produced */
- const int hasAlternative; /* Whether source has alt.location */
-} dataSources[] = {
-
- { "/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 1 },
- { "/usr/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 0},
- { "/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 1 },
- { "/usr/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 0},
- { "/usr/bin/pfstat", NULL, SC(-2), NULL, 0, 0, 0, 0},
- { "/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 1 },
- { "/usr/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 0},
- { "/usr/ucb/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 },
- { "/usr/bin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 },
- { "/usr/sbin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1},
- { "/usr/etc/netstat", "-s", SC(2), NULL, 0, 0, 0, 0},
- { "/usr/bin/nfsstat", NULL, SC(2), NULL, 0, 0, 0, 0},
- { "/usr/ucb/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 },
- { "/usr/bin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 },
- { "/usr/sbin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 },
- { "/usr/etc/netstat", "-m", SC(-1), NULL, 0, 0, 0, 0 },
- { "/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 },
- { "/usr/ucb/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 },
- { "/usr/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 },
- { "/usr/sbin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1},
- { "/usr/etc/netstat", "-in", SC(-1), NULL, 0, 0, 0, 0},
- { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.1.0",
- SC(-1), NULL, 0, 0, 0, 0 }, /* UDP in */
- { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.4.0",
- SC(-1), NULL, 0, 0, 0, 0 }, /* UDP out */
- { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.4.3.0",
- SC(-1), NULL, 0, 0, 0, 0 }, /* IP ? */
- { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.10.0",
- SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */
- { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.11.0",
- SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */
- { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.13.0",
- SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */
- { "/usr/bin/mpstat", NULL, SC(1), NULL, 0, 0, 0, 0 },
- { "/usr/bin/w", NULL, SC(1), NULL, 0, 0, 0, 1 },
- { "/usr/bsd/w", NULL, SC(1), NULL, 0, 0, 0, 0 },
- { "/usr/bin/df", NULL, SC(1), NULL, 0, 0, 0, 1 },
- { "/bin/df", NULL, SC(1), NULL, 0, 0, 0, 0 },
- { "/usr/sbin/portstat", NULL, SC(1), NULL, 0, 0, 0, 0 },
- { "/usr/bin/iostat", NULL, SC(SC_0), NULL, 0, 0, 0, 0 },
- { "/usr/bin/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 1 },
- { "/usr/bsd/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 0 },
- { "/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 1 },
- { "/usr/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 0 },
- { "/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 1 },
- { "/usr/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 0 },
- { "/usr/ucb/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 },
- { "/usr/bin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 },
- { "/usr/sbin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1 },
- { "/usr/etc/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 0 },
-#if defined( __sgi ) || defined( __hpux )
- { "/bin/ps", "-el", SC(0.3), NULL, 0, 0, 0, 1 },
-#endif /* __sgi || __hpux */
- { "/usr/ucb/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 },
- { "/usr/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1 },
- { "/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 0 },
- { "/usr/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 1 },
- { "/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 0 },
- /* Unreliable source, depends on system usage */
- { "/etc/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 1 },
- { "/bin/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 0 },
- { "/etc/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 1 },
- { "/bin/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 0 },
- { "/etc/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 1 },
- { "/bin/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 0 },
- { "/etc/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 1 },
- { "/bin/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 0 },
- { "/etc/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 },
- { "/bin/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 0 },
- /* pstat is your friend */
- { "/usr/bin/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 1 },
-#ifdef __sgi
- { "/usr/bsd/last", "-50", SC(0.3), NULL, 0, 0, 0, 0 },
-#endif /* __sgi */
-#ifdef __hpux
- { "/etc/last", "-50", SC(0.3), NULL, 0, 0, 0, 0 },
-#endif /* __hpux */
- { "/usr/bsd/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 0 },
- { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.1.0",
- SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */
- { "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.3.0",
- SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */
- { "/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 },
- { "/usr/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 },
- { "/usr/bin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1 },
- { "/usr/sbin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 0 },
- { "/usr/sbin/ripquery", "-nw 1 127.0.0.1",
- SC(0.1), NULL, 0, 0, 0, 0 },
- { "/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 },
- { "/usr/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 },
- { "/usr/ucb/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 0 },
- { "/usr/bin/tcpdump", "-c 5 -efvvx", SC(1), NULL, 0, 0, 0, 0 },
- /* This is very environment-dependant. If network traffic is low, it'll
- * probably time out before delivering 5 packets, which is OK because
- * it'll probably be fixed stuff like ARP anyway */
- { "/usr/sbin/advfsstat", "-b usr_domain",
- SC(SC_0), NULL, 0, 0, 0, 0},
- { "/usr/sbin/advfsstat", "-l 2 usr_domain",
- SC(0.5), NULL, 0, 0, 0, 0},
- { "/usr/sbin/advfsstat", "-p usr_domain",
- SC(SC_0), NULL, 0, 0, 0, 0},
- /* This is a complex and screwball program. Some systems have things
- * like rX_dmn, x = integer, for RAID systems, but the statistics are
- * pretty dodgy */
-#if 0
- /* The following aren't enabled since they're somewhat slow and not very
- * unpredictable, however they give an indication of the sort of sources
- * you can use (for example the finger might be more useful on a
- * firewalled internal network) */
- { "/usr/bin/finger", "@ml.media.mit.edu", SC(0.9), NULL, 0, 0, 0, 0 },
- { "/usr/local/bin/wget", "-O - http://lavarand.sgi.com/block.html",
- SC(0.9), NULL, 0, 0, 0, 0 },
- { "/bin/cat", "/usr/spool/mqueue/syslog", SC(0.9), NULL, 0, 0, 0, 0 },
-#endif /* 0 */
- { NULL, NULL, 0, NULL, 0, 0, 0, 0 }
-};
-
-static byte *gather_buffer; /* buffer for gathering random noise */
-static int gather_buffer_size; /* size of the memory buffer */
-static uid_t gatherer_uid;
-
-/* The message structure used to communicate with the parent */
-typedef struct {
- int usefulness; /* usefulness of data */
- int ndata; /* valid bytes in data */
- char data[500]; /* gathered data */
-} GATHER_MSG;
-
-/* Under SunOS popen() doesn't record the pid of the child process. When
- * pclose() is called, instead of calling waitpid() for the correct child, it
- * calls wait() repeatedly until the right child is reaped. The problem is
- * that this reaps any other children that happen to have died at that
- * moment, and when their pclose() comes along, the process hangs forever.
- * The fix is to use a wrapper for popen()/pclose() which saves the pid in
- * the dataSources structure (code adapted from GNU-libc's popen() call).
- *
- * Aut viam inveniam aut faciam */
-
-static FILE *
-my_popen(struct RI *entry)
-{
-
- int pipedes[2];
- FILE *stream;
-
- /* Create the pipe */
- if (pipe(pipedes) < 0)
- return (NULL);
-
- /* Fork off the child ("vfork() is like an OS orgasm. All OS's want to
- * do it, but most just end up faking it" - Chris Wedgwood). If your OS
- * supports it, you should try to use vfork() here because it's somewhat
- * more efficient */
-#if defined( sun ) || defined( __ultrix__ ) || defined( __osf__ ) || \
- defined(__hpux)
- entry->pid = vfork();
-#else /* */
- entry->pid = fork();
-#endif /* Unixen which have vfork() */
- if (entry->pid == (pid_t) - 1) {
- /* The fork failed */
- close(pipedes[0]);
- close(pipedes[1]);
- return (NULL);
- }
-
- if (entry->pid == (pid_t) 0) {
- struct passwd *passwd;
-
- /* We are the child. Make the read side of the pipe be stdout */
- if (dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
- exit(127);
-
- /* Now that everything is set up, give up our permissions to make
- * sure we don't read anything sensitive. If the getpwnam() fails,
- * we default to -1, which is usually nobody */
- if (gatherer_uid == (uid_t)-1 && \
- (passwd = getpwnam("nobody")) != NULL)
- gatherer_uid = passwd->pw_uid;
-
- setuid(gatherer_uid);
-
- /* Close the pipe descriptors */
- close(pipedes[STDIN_FILENO]);
- close(pipedes[STDOUT_FILENO]);
-
- /* Try and exec the program */
- execl(entry->path, entry->path, entry->arg, NULL);
-
- /* Die if the exec failed */
- exit(127);
- }
-
- /* We are the parent. Close the irrelevant side of the pipe and open
- * the relevant side as a new stream. Mark our side of the pipe to
- * close on exec, so new children won't see it */
- close(pipedes[STDOUT_FILENO]);
-
- fcntl(pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
-
- stream = fdopen(pipedes[STDIN_FILENO], "r");
-
- if (stream == NULL) {
- int savedErrno = errno;
-
- /* The stream couldn't be opened or the child structure couldn't be
- * allocated. Kill the child and close the other side of the pipe */
- kill(entry->pid, SIGKILL);
- if (stream == NULL)
- close(pipedes[STDOUT_FILENO]);
- else
- fclose(stream);
-
- waitpid(entry->pid, NULL, 0);
-
- entry->pid = 0;
- errno = savedErrno;
- return (NULL);
- }
-
- return (stream);
-}
-
-static int
-my_pclose(struct RI *entry)
-{
- int status = 0;
-
- if (fclose(entry->pipe))
- return (-1);
-
- /* We ignore the return value from the process because some programs
- * return funny values which would result in the input being discarded
- * even if they executed successfully. This isn't a problem because the
- * result data size threshold will filter out any programs which exit
- * with a usage message without producing useful output */
- if (waitpid(entry->pid, NULL, 0) != entry->pid)
- status = -1;
-
- entry->pipe = NULL;
- entry->pid = 0;
- return (status);
-}
-
-
-/* Unix slow poll (without special support for Linux)
- *
- * If a few of the randomness sources create a large amount of output then
- * the slowPoll() stops once the buffer has been filled (but before all the
- * randomness sources have been sucked dry) so that the 'usefulness' factor
- * remains below the threshold. For this reason the gatherer buffer has to
- * be fairly sizeable on moderately loaded systems. This is something of a
- * bug since the usefulness should be influenced by the amount of output as
- * well as the source type */
-
-
-static int
-slow_poll(FILE *dbgfp, int dbgall, size_t *nbytes )
-{
- int moreSources;
- struct timeval tv;
- fd_set fds;
- #if defined( __hpux )
- size_t maxFD = 0;
- #else
- int maxFD = 0;
- #endif /* OS-specific brokenness */
- int bufPos, i, usefulness = 0;
-
-
- /* Fire up each randomness source */
- FD_ZERO(&fds);
- for (i = 0; dataSources[i].path != NULL; i++) {
- /* Since popen() is a fairly heavy function, we check to see whether
- * the executable exists before we try to run it */
- if (access(dataSources[i].path, X_OK)) {
- if( dbgfp && dbgall )
- fprintf(dbgfp, "%s not present%s\n", dataSources[i].path,
- dataSources[i].hasAlternative ?
- ", has alternatives" : "");
- dataSources[i].pipe = NULL;
- }
- else
- dataSources[i].pipe = my_popen(&dataSources[i]);
-
- if (dataSources[i].pipe != NULL) {
- dataSources[i].pipeFD = fileno(dataSources[i].pipe);
- if (dataSources[i].pipeFD > maxFD)
- maxFD = dataSources[i].pipeFD;
- #ifdef O_NONBLOCK /* Ohhh what a hack (used for Atari) */
- fcntl(dataSources[i].pipeFD, F_SETFL, O_NONBLOCK);
- #else
- #warning O_NONBLOCK is missing
- #endif
- FD_SET(dataSources[i].pipeFD, &fds);
- dataSources[i].length = 0;
-
- /* If there are alternatives for this command, don't try and
- * execute them */
- while (dataSources[i].hasAlternative) {
- if( dbgfp && dbgall )
- fprintf(dbgfp, "Skipping %s\n", dataSources[i + 1].path);
- i++;
- }
- }
- }
-
-
- /* Suck all the data we can get from each of the sources */
- bufPos = 0;
- moreSources = 1;
- while (moreSources && bufPos <= gather_buffer_size) {
- /* Wait for data to become available from any of the sources, with a
- * timeout of 10 seconds. This adds even more randomness since data
- * becomes available in a nondeterministic fashion. Kudos to HP's QA
- * department for managing to ship a select() which breaks its own
- * prototype */
- tv.tv_sec = 10;
- tv.tv_usec = 0;
-
- #if defined( __hpux ) && ( OS_VERSION == 9 )
- if (select(maxFD + 1, (int *)&fds, NULL, NULL, &tv) == -1)
- #else /* */
- if (select(maxFD + 1, &fds, NULL, NULL, &tv) == -1)
- #endif /* __hpux */
- break;
-
- /* One of the sources has data available, read it into the buffer */
- for (i = 0; dataSources[i].path != NULL; i++) {
- if( dataSources[i].pipe && FD_ISSET(dataSources[i].pipeFD, &fds)) {
- size_t noBytes;
-
- if ((noBytes = fread(gather_buffer + bufPos, 1,
- gather_buffer_size - bufPos,
- dataSources[i].pipe)) == 0) {
- if (my_pclose(&dataSources[i]) == 0) {
- int total = 0;
-
- /* Try and estimate how much entropy we're getting
- * from a data source */
- if (dataSources[i].usefulness)
- if (dataSources[i].usefulness < 0)
- total = (dataSources[i].length + 999)
- / -dataSources[i].usefulness;
- else
- total = dataSources[i].length
- / dataSources[i].usefulness;
- if( dbgfp )
- fprintf(dbgfp,
- "%s %s contributed %d bytes, "
- "usefulness = %d\n", dataSources[i].path,
- (dataSources[i].arg != NULL) ?
- dataSources[i].arg : "",
- dataSources[i].length, total);
- if( dataSources[i].length )
- usefulness += total;
- }
- dataSources[i].pipe = NULL;
- }
- else {
- int currPos = bufPos;
- int endPos = bufPos + noBytes;
-
- /* Run-length compress the input byte sequence */
- while (currPos < endPos) {
- int ch = gather_buffer[currPos];
-
- /* If it's a single byte, just copy it over */
- if (ch != gather_buffer[currPos + 1]) {
- gather_buffer[bufPos++] = ch;
- currPos++;
- }
- else {
- int count = 0;
-
- /* It's a run of repeated bytes, replace them
- * with the byte count mod 256 */
- while ((ch == gather_buffer[currPos])
- && currPos < endPos) {
- count++;
- currPos++;
- }
- gather_buffer[bufPos++] = count;
- noBytes -= count - 1;
- }
- }
-
- /* Remember the number of (compressed) bytes of input we
- * obtained */
- dataSources[i].length += noBytes;
- }
- }
- }
-
- /* Check if there is more input available on any of the sources */
- moreSources = 0;
- FD_ZERO(&fds);
- for (i = 0; dataSources[i].path != NULL; i++) {
- if (dataSources[i].pipe != NULL) {
- FD_SET(dataSources[i].pipeFD, &fds);
- moreSources = 1;
- }
- }
- }
-
- if( dbgfp ) {
- fprintf(dbgfp, "Got %d bytes, usefulness = %d\n", bufPos, usefulness);
- fflush(dbgfp);
- }
- *nbytes = bufPos;
- return usefulness;
-}
-
-/****************
- * Start the gatherer process which writes messages of
- * type GATHERER_MSG to pipedes
- */
-static void
-start_gatherer( int pipefd )
-{
- FILE *dbgfp = NULL;
- int dbgall;
-
- {
- const char *s = getenv("GNUPG_RNDUNIX_DBG");
- if( s ) {
- dbgfp = (*s=='-' && !s[1])? stdout : fopen(s, "a");
- if( !dbgfp )
- g10_log_info("can't open debug file `%s': %s\n",
- s, strerror(errno) );
- else
- fprintf(dbgfp,"\nSTART RNDUNIX DEBUG pid=%d\n", (int)getpid());
- }
- dbgall = !!getenv("GNUPG_RNDUNIX_DBGALL");
- }
- /* close all files but the ones we need */
- { int nmax, n1, n2, i;
- if( (nmax=sysconf( _SC_OPEN_MAX )) < 0 ) {
- #ifdef _POSIX_OPEN_MAX
- nmax = _POSIX_OPEN_MAX;
- #else
- nmax = 20; /* assume a reasonable value */
- #endif
- }
- n1 = fileno( stderr );
- n2 = dbgfp? fileno( dbgfp ) : -1;
- for(i=0; i < nmax; i++ ) {
- if( i != n1 && i != n2 && i != pipefd )
- close(i);
- }
- errno = 0;
- }
-
-
-
- /* Set up the buffer */
- gather_buffer_size = GATHER_BUFSIZE;
- gather_buffer = malloc( gather_buffer_size );
- if( !gather_buffer ) {
- g10_log_error("out of core while allocating the gatherer buffer\n");
- exit(2);
- }
-
- /* Reset the SIGC(H)LD handler to the system default. This is necessary
- * because if the program which cryptlib is a part of installs its own
- * SIGC(H)LD handler, it will end up reaping the cryptlib children before
- * cryptlib can. As a result, my_pclose() will call waitpid() on a
- * process which has already been reaped by the installed handler and
- * return an error, so the read data won't be added to the randomness
- * pool. There are two types of SIGC(H)LD naming, the SysV SIGCLD and
- * the BSD/Posix SIGCHLD, so we need to handle either possibility */
- #ifdef SIGCLD
- signal(SIGCLD, SIG_DFL);
- #else
- signal(SIGCHLD, SIG_DFL);
- #endif
-
- fclose(stderr); /* Arrghh!! It's Stuart code!! */
-
- for(;;) {
- GATHER_MSG msg;
- size_t nbytes;
- const char *p;
-
- msg.usefulness = slow_poll( dbgfp, dbgall, &nbytes );
- p = gather_buffer;
- while( nbytes ) {
- msg.ndata = nbytes > sizeof(msg.data)? sizeof(msg.data) : nbytes;
- memcpy( msg.data, p, msg.ndata );
- nbytes -= msg.ndata;
- p += msg.ndata;
-
- while( write( pipefd, &msg, sizeof(msg) ) != sizeof(msg) ) {
- if( errno == EINTR )
- continue;
- if( errno == EAGAIN ) {
- struct timeval tv;
- tv.tv_sec = 0;
- tv.tv_usec = 50000;
- select(0, NULL, NULL, NULL, &tv);
- continue;
- }
- if( errno == EPIPE ) /* parent has exited, so give up */
- exit(0);
-
- /* we can't do very much here because stderr is closed */
- if( dbgfp )
- fprintf(dbgfp, "gatherer can't write to pipe: %s\n",
- strerror(errno) );
- /* we start a new poll to give the system some time */
- nbytes = 0;
- break;
- }
- }
- }
- /* we are killed when the parent dies */
-}
-
-
-static int
-read_a_msg( int fd, GATHER_MSG *msg )
-{
- char *buffer = (char*)msg;
- size_t length = sizeof( *msg );
- int n;
-
- do {
- do {
- n = read(fd, buffer, length );
- } while( n == -1 && errno == EINTR );
- if( n == -1 )
- return -1;
- buffer += n;
- length -= n;
- } while( length );
- return 0;
-}
-
-
-static int
-gather_random( void (*add)(const void*, size_t, int), int requester,
- size_t length, int level )
-{
- static pid_t gatherer_pid = 0;
- static int pipedes[2];
- GATHER_MSG msg;
- size_t n;
-
- if( !gatherer_pid ) {
- /* make sure we are not setuid */
- if( getuid() != geteuid() )
- BUG();
- /* time to start the gatherer process */
- if( pipe( pipedes ) ) {
- g10_log_error("pipe() failed: %s\n", strerror(errno));
- return -1;
- }
- gatherer_pid = fork();
- if( gatherer_pid == -1 ) {
- g10_log_error("can't for gatherer process: %s\n", strerror(errno));
- return -1;
- }
- if( !gatherer_pid ) {
- start_gatherer( pipedes[1] );
- /* oops, can't happen */
- return -1;
- }
- }
-
- /* now read from the gatherer */
- while( length ) {
- int goodness;
- ulong subtract;
-
- if( read_a_msg( pipedes[0], &msg ) ) {
- g10_log_error("reading from gatherer pipe failed: %s\n",
- strerror(errno));
- return -1;
- }
-
-
- if( level > 1 ) {
- if( msg.usefulness > 30 )
- goodness = 100;
- else if ( msg.usefulness )
- goodness = msg.usefulness * 100 / 30;
- else
- goodness = 0;
- }
- else if( level ) {
- if( msg.usefulness > 15 )
- goodness = 100;
- else if ( msg.usefulness )
- goodness = msg.usefulness * 100 / 15;
- else
- goodness = 0;
- }
- else
- goodness = 100; /* goodness of level 0 is always 100 % */
-
- n = msg.ndata;
- if( n > length )
- n = length;
- (*add)( msg.data, n, requester );
-
- /* this is the trick how e cope with the goodness */
- subtract = (ulong)n * goodness / 100;
- /* subtract at least 1 byte to avoid infinite loops */
- length -= subtract ? subtract : 1;
- }
-
- return 0;
-}
-
-
-
-#ifndef IS_MODULE
-static
-#endif
-const char * const gnupgext_version = "RNDUNIX ($Revision$)";
-
-
-static struct {
- int class;
- int version;
- void *func;
-} func_table[] = {
- { 40, 1, gather_random },
-};
-
-/****************
- * Enumerate the names of the functions together with informations about
- * this function. Set sequence to an integer with a initial value of 0 and
- * do not change it.
- * If what is 0 all kind of functions are returned.
- * Return values: class := class of function:
- * 10 = message digest algorithm info function
- * 11 = integer with available md algorithms
- * 20 = cipher algorithm info function
- * 21 = integer with available cipher algorithms
- * 30 = public key algorithm info function
- * 31 = integer with available pubkey algorithms
- * 40 = get read_random_source() function
- * 41 = get fast_random_poll function
- * version = interface version of the function/pointer
- * (currently this is 1 for all functions)
- */
-
-#ifndef IS_MODULE
-static
-#endif
-void *
-gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
-{
- void *ret;
- int i = *sequence;
-
- do {
- if ( i >= DIM(func_table) || i < 0 ) {
- return NULL;
- }
- *class = func_table[i].class;
- *vers = func_table[i].version;
- ret = func_table[i].func;
- i++;
- } while ( what && what != *class );
-
- *sequence = i;
- return ret;
-}
-
-#ifndef IS_MODULE
-void
-rndunix_constructor(void)
-{
- register_internal_cipher_extension( gnupgext_version,
- gnupgext_enum_func );
-}
-#endif
-
-