summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/patches/random0001-xxx-standalone-random-translator.patch3214
-rw-r--r--debian/patches/series1
2 files changed, 3215 insertions, 0 deletions
diff --git a/debian/patches/random0001-xxx-standalone-random-translator.patch b/debian/patches/random0001-xxx-standalone-random-translator.patch
new file mode 100644
index 00000000..fe3bba2c
--- /dev/null
+++ b/debian/patches/random0001-xxx-standalone-random-translator.patch
@@ -0,0 +1,3214 @@
+From 1ea5ac6db5000a16eea08111478504599d3c3295 Mon Sep 17 00:00:00 2001
+From: Justus Winter <4winter@informatik.uni-hamburg.de>
+Date: Thu, 12 Nov 2015 22:16:49 +0100
+Subject: [PATCH hurd] xxx standalone random translator
+
+---
+ Makefile | 1 -
+ random/Makefile | 30 --
+ random/TODO | 11 -
+ random/gnupg-bithelp.h | 41 ---
+ random/gnupg-glue.h | 40 ---
+ random/gnupg-random.c | 810 -------------------------------------------------
+ random/gnupg-random.h | 47 ---
+ random/gnupg-rmd.h | 38 ---
+ random/gnupg-rmd160.c | 656 ---------------------------------------
+ random/random.c | 650 ---------------------------------------
+ random/random.h | 32 --
+ sutils/MAKEDEV.sh | 6 +-
+ trans/Makefile | 7 +-
+ trans/random.c | 682 +++++++++++++++++++++++++++++++++++++++++
+ 14 files changed, 691 insertions(+), 2360 deletions(-)
+ delete mode 100644 random/Makefile
+ delete mode 100644 random/TODO
+ delete mode 100644 random/gnupg-bithelp.h
+ delete mode 100644 random/gnupg-glue.h
+ delete mode 100644 random/gnupg-random.c
+ delete mode 100644 random/gnupg-random.h
+ delete mode 100644 random/gnupg-rmd.h
+ delete mode 100644 random/gnupg-rmd160.c
+ delete mode 100644 random/random.c
+ delete mode 100644 random/random.h
+ create mode 100644 trans/random.c
+
+diff --git a/Makefile b/Makefile
+index 3178740..6544cd2 100644
+--- a/Makefile
++++ b/Makefile
+@@ -38,7 +38,6 @@ prog-subdirs = auth proc exec term \
+ hostmux usermux ftpfs trans \
+ console-client utils sutils \
+ benchmarks fstests \
+- random \
+ procfs \
+ startup \
+ init \
+diff --git a/random/Makefile b/random/Makefile
+deleted file mode 100644
+index 0949b63..0000000
+--- a/random/Makefile
++++ /dev/null
+@@ -1,30 +0,0 @@
+-#
+-# Copyright (C) 1994,95,96,97,99,2000,2001 Free Software Foundation, Inc.
+-#
+-# This program is free software; you can redistribute it and/or
+-# modify it under the terms of the GNU General Public License as
+-# published by the Free Software Foundation; either version 2, or (at
+-# your option) any later version.
+-#
+-# This program is distributed in the hope that it will be useful, but
+-# WITHOUT ANY WARRANTY; without even the implied warranty of
+-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+-# General Public License for more details.
+-#
+-# You should have received a copy of the GNU General Public License
+-# along with this program; if not, write to the Free Software
+-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+-
+-dir := random
+-makemode := server
+-
+-CFLAGS += -D__HURD__
+-
+-target = random
+-SRCS = random.c gnupg-random.c gnupg-rmd160.c
+-OBJS = $(SRCS:.c=.o) startup_notifyServer.o
+-LCLHDRS = gnupg-random.h gnupg-rmd.h gnupg-bithelp.h random.h
+-HURDLIBS = trivfs ports fshelp ihash shouldbeinlibc
+-OTHERLIBS = -lpthread
+-
+-include ../Makeconf
+diff --git a/random/TODO b/random/TODO
+deleted file mode 100644
+index 9cc57ab..0000000
+--- a/random/TODO
++++ /dev/null
+@@ -1,11 +0,0 @@
+-* read_poll uses random_poll until the pool is filled. This is ian
+- issue at first initialization, as this requries POOLSIZE good random (level 1 from
+- gather_random) even in level 0 and 1.
+- For now, the code is only applied to level 2. Eventually, readable_pool
+- should be fixed to return 0 if initialization is not done yet and not enough bytes
+- are available. Otherwise it enters an infinite loop.
+-
+-* Permissions?
+-
+-* Off by one error in gather_random/io_write? I can only get GATHERBUFSIZE - 1
+- bytes from it.
+diff --git a/random/gnupg-bithelp.h b/random/gnupg-bithelp.h
+deleted file mode 100644
+index 188db16..0000000
+--- a/random/gnupg-bithelp.h
++++ /dev/null
+@@ -1,41 +0,0 @@
+-/* bithelp.h - Some bit manipulation helpers
+- * Copyright (C) 1999 Free Software Foundation, Inc.
+- *
+- * This file is part of GnuPG.
+- *
+- * GnuPG is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * GnuPG is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+- */
+-#ifndef G10_BITHELP_H
+-#define G10_BITHELP_H
+-
+-
+-/****************
+- * Rotate a 32 bit integer by n bytes
+- */
+-#if defined(__GNUC__) && defined(__i386__)
+-static inline u32
+-rol( u32 x, int n)
+-{
+- __asm__("roll %%cl,%0"
+- :"=r" (x)
+- :"0" (x),"c" (n));
+- return x;
+-}
+-#else
+- #define rol(x,n) ( ((x) << (n)) | ((x) >> (32-(n))) )
+-#endif
+-
+-
+-#endif /*G10_BITHELP_H*/
+diff --git a/random/gnupg-glue.h b/random/gnupg-glue.h
+deleted file mode 100644
+index cbf0a10..0000000
+--- a/random/gnupg-glue.h
++++ /dev/null
+@@ -1,40 +0,0 @@
+-#ifndef __GNUPG_GLUE_H__
+-#define __GNUPG_GLUE_H__
+-
+-#include <sys/types.h>
+-#include <random.h>
+-
+-#define SIZEOF_UNSIGNED_LONG 4
+-typedef unsigned int u32;
+-typedef unsigned char byte;
+-
+-/* GnuPG's config.h */
+-#define HAVE_GETTIMEOFDAY 1
+-#define HAVE_GETRUSAGE 1
+-#define HAVE_RAND 1
+-
+-/* GnuPG's memory.h */
+-#define m_alloc malloc
+-#define m_alloc_secure malloc
+-#define m_alloc_clear(x) calloc(x, 1)
+-#define m_alloc_secure_clear(x) calloc(x, 1)
+-#define m_free free
+-#define m_strdup strdup
+-
+-/* GnuPG's dynaload.h */
+-#define dynload_getfnc_fast_random_poll() (0)
+-#define dynload_getfnc_gather_random() &gather_random
+-int
+-gather_random( void (*add)(const void*, size_t, int), int requester,
+- size_t length, int level );
+-
+-/* GnuPG's miscellaneous stuff. */
+-#define BUG() assert(0)
+-#define _(x) x
+-#define make_timestamp() time(0)
+-#define tty_printf printf
+-#define log_info(format, args...) printf(format , ## args)
+-#define log_fatal(format, args...) { printf(format , ## args) ; exit(2); }
+-#define DIM(v) (sizeof(v)/sizeof((v)[0]))
+-
+-#endif /* __GNUPG_GLUE_H__ */
+diff --git a/random/gnupg-random.c b/random/gnupg-random.c
+deleted file mode 100644
+index 54ee3c5..0000000
+--- a/random/gnupg-random.c
++++ /dev/null
+@@ -1,810 +0,0 @@
+-/* random.c - random number generator
+- * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+- *
+- * This file is part of GnuPG.
+- *
+- * GnuPG is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * GnuPG is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+- */
+-
+-
+-/****************
+- * This random number generator is modelled after the one described
+- * in Peter Gutmann's Paper: "Software Generation of Practically
+- * Strong Random Numbers".
+- */
+-
+-#ifndef __HURD__
+-#include <config.h>
+-#else
+-#include "gnupg-glue.h"
+-#endif
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <assert.h>
+-#include <errno.h>
+-#include <string.h>
+-#include <time.h>
+-#include <sys/time.h>
+-#include <sys/types.h>
+-#include <sys/stat.h>
+-#include <unistd.h>
+-#include <fcntl.h>
+-#ifdef HAVE_GETHRTIME
+- #include <sys/times.h>
+-#endif
+-#ifdef HAVE_GETTIMEOFDAY
+- #include <sys/times.h>
+-#endif
+-#ifdef HAVE_GETRUSAGE
+- #include <sys/resource.h>
+-#endif
+-#ifdef __MINGW32__
+- #include <process.h>
+-#endif
+-#ifndef __HURD__
+-#include "util.h"
+-#endif
+-#ifndef __HURD__
+-#include "rmd.h"
+-#include "ttyio.h"
+-#include "i18n.h"
+-#include "random.h"
+-#include "rand-internal.h"
+-#include "dynload.h"
+-#else
+-#include "gnupg-rmd.h"
+-#include "gnupg-random.h"
+-#endif
+-
+-#ifndef RAND_MAX /* for SunOS */
+- #define RAND_MAX 32767
+-#endif
+-
+-
+-#if SIZEOF_UNSIGNED_LONG == 8
+- #define ADD_VALUE 0xa5a5a5a5a5a5a5a5
+-#elif SIZEOF_UNSIGNED_LONG == 4
+- #define ADD_VALUE 0xa5a5a5a5
+-#else
+- #error weird size for an unsigned long
+-#endif
+-
+-#define BLOCKLEN 64 /* hash this amount of bytes */
+-#define DIGESTLEN 20 /* into a digest of this length (rmd160) */
+-/* poolblocks is the number of digests which make up the pool
+- * and poolsize must be a multiple of the digest length
+- * to make the AND operations faster, the size should also be
+- * a multiple of ulong
+- */
+-#define POOLBLOCKS 30
+-#define POOLSIZE (POOLBLOCKS*DIGESTLEN)
+-#if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
+- #error Please make sure that poolsize is a multiple of ulong
+-#endif
+-#define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
+-
+-
+-static int is_initialized;
+-#define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
+-static char *rndpool; /* allocated size is POOLSIZE+BLOCKLEN */
+-static char *keypool; /* allocated size is POOLSIZE+BLOCKLEN */
+-static size_t pool_readpos;
+-static size_t pool_writepos;
+-static int pool_filled;
+-static int pool_balance;
+-static int just_mixed;
+-static int did_initial_extra_seeding;
+-static char *seed_file_name;
+-static int allow_seed_file_update;
+-
+-static int secure_alloc;
+-static int quick_test;
+-static int faked_rng;
+-
+-
+-#ifndef __HURD__
+-static void read_pool( byte *buffer, size_t length, int level );
+-#else
+-int read_pool( byte *buffer, size_t length, int level );
+-#endif
+-static void add_randomness( const void *buffer, size_t length, int source );
+-static void random_poll(void);
+-#ifndef __HURD__
+-static void read_random_source( int requester, size_t length, int level);
+-#else
+-static int read_random_source( int requester, size_t length, int level);
+-#endif
+-static int gather_faked( void (*add)(const void*, size_t, int), int requester,
+- size_t length, int level );
+-
+-static struct {
+- ulong mixrnd;
+- ulong mixkey;
+- ulong slowpolls;
+- ulong fastpolls;
+- ulong getbytes1;
+- ulong ngetbytes1;
+- ulong getbytes2;
+- ulong ngetbytes2;
+- ulong addbytes;
+- ulong naddbytes;
+-} rndstats;
+-
+-static void
+-initialize(void)
+-{
+- /* The data buffer is allocated somewhat larger, so that
+- * we can use this extra space (which is allocated in secure memory)
+- * as a temporary hash buffer */
+- rndpool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
+- : m_alloc_clear(POOLSIZE+BLOCKLEN);
+- keypool = secure_alloc ? m_alloc_secure_clear(POOLSIZE+BLOCKLEN)
+- : m_alloc_clear(POOLSIZE+BLOCKLEN);
+- is_initialized = 1;
+-#ifndef __HURD__
+- cipher_modules_constructor();
+-#endif
+-}
+-
+-static void
+-burn_stack (int bytes)
+-{
+- char buf[128];
+-
+- memset (buf, 0, sizeof buf);
+- bytes -= sizeof buf;
+- if (bytes > 0)
+- burn_stack (bytes);
+-}
+-
+-void
+-random_dump_stats()
+-{
+- fprintf(stderr,
+- "random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
+- " outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu\n",
+- POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
+- rndstats.naddbytes, rndstats.addbytes,
+- rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1,
+- rndstats.ngetbytes2, rndstats.getbytes2 );
+-}
+-
+-void
+-secure_random_alloc()
+-{
+- secure_alloc = 1;
+-}
+-
+-
+-int
+-quick_random_gen( int onoff )
+-{
+- int last;
+-
+- read_random_source(0,0,0); /* init */
+- last = quick_test;
+- if( onoff != -1 )
+- quick_test = onoff;
+- return faked_rng? 1 : last;
+-}
+-
+-
+-/****************
+- * Fill the buffer with LENGTH bytes of cryptographically strong
+- * random bytes. level 0 is not very strong, 1 is strong enough
+- * for most usage, 2 is good for key generation stuff but may be very slow.
+- */
+-void
+-randomize_buffer( byte *buffer, size_t length, int level )
+-{
+- char *p = get_random_bits( length*8, level, 1 );
+- memcpy( buffer, p, length );
+- m_free(p);
+-}
+-
+-
+-int
+-random_is_faked()
+-{
+- if( !is_initialized )
+- initialize();
+- return faked_rng || quick_test;
+-}
+-
+-/****************
+- * Return a pointer to a randomized buffer of level 0 and LENGTH bits
+- * caller must free the buffer.
+- * Note: The returned value is rounded up to bytes.
+- */
+-byte *
+-get_random_bits( size_t nbits, int level, int secure )
+-{
+- byte *buf, *p;
+- size_t nbytes = (nbits+7)/8;
+-
+- if( quick_test && level > 1 )
+- level = 1;
+- MASK_LEVEL(level);
+- if( level == 1 ) {
+- rndstats.getbytes1 += nbytes;
+- rndstats.ngetbytes1++;
+- }
+- else if( level >= 2 ) {
+- rndstats.getbytes2 += nbytes;
+- rndstats.ngetbytes2++;
+- }
+-
+- buf = secure && secure_alloc ? m_alloc_secure( nbytes ) : m_alloc( nbytes );
+- for( p = buf; nbytes > 0; ) {
+- size_t n = nbytes > POOLSIZE? POOLSIZE : nbytes;
+-#ifdef __HURD__
+- n =
+-#endif
+- read_pool( p, n, level );
+- nbytes -= n;
+- p += n;
+-
+- }
+- return buf;
+-}
+-
+-
+-/****************
+- * Mix the pool
+- */
+-static void
+-mix_pool(byte *pool)
+-{
+- char *hashbuf = pool + POOLSIZE;
+- char *p, *pend;
+- int i, n;
+- RMD160_CONTEXT md;
+-
+- rmd160_init( &md );
+- #if DIGESTLEN != 20
+- #error must have a digest length of 20 for ripe-md-160
+- #endif
+- /* loop over the pool */
+- pend = pool + POOLSIZE;
+- memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
+- memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
+- rmd160_mixblock( &md, hashbuf);
+- memcpy(pool, hashbuf, 20 );
+-
+- p = pool;
+- for( n=1; n < POOLBLOCKS; n++ ) {
+- memcpy(hashbuf, p, DIGESTLEN );
+-
+- p += DIGESTLEN;
+- if( p+DIGESTLEN+BLOCKLEN < pend )
+- memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
+- else {
+- char *pp = p+DIGESTLEN;
+- for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
+- if( pp >= pend )
+- pp = pool;
+- hashbuf[i] = *pp++;
+- }
+- }
+-
+- rmd160_mixblock( &md, hashbuf);
+- memcpy(p, hashbuf, 20 );
+- }
+- burn_stack (200); /* for the rmd160_mixblock() */
+-}
+-
+-
+-void
+-set_random_seed_file( const char *name )
+-{
+- if( seed_file_name )
+- BUG();
+- seed_file_name = m_strdup( name );
+-}
+-
+-/****************
+- * Read in a seed form the random_seed file
+- * and return true if this was successful
+- */
+-static int
+-read_seed_file()
+-{
+- int fd;
+- struct stat sb;
+- unsigned char buffer[POOLSIZE];
+- int n;
+-
+- if( !seed_file_name )
+- return 0;
+-
+- #ifdef HAVE_DOSISH_SYSTEM
+- fd = open( seed_file_name, O_RDONLY | O_BINARY );
+- #else
+- fd = open( seed_file_name, O_RDONLY );
+- #endif
+- if( fd == -1 && errno == ENOENT) {
+- allow_seed_file_update = 1;
+- return 0;
+- }
+-
+- if( fd == -1 ) {
+- log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
+- return 0;
+- }
+- if( fstat( fd, &sb ) ) {
+- log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
+- close(fd);
+- return 0;
+- }
+- if( !S_ISREG(sb.st_mode) ) {
+- log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
+- close(fd);
+- return 0;
+- }
+- if( !sb.st_size ) {
+- log_info(_("note: random_seed file is empty\n") );
+- close(fd);
+- allow_seed_file_update = 1;
+- return 0;
+- }
+- if( sb.st_size != POOLSIZE ) {
+- log_info(_("warning: invalid size of random_seed file - not used\n") );
+- close(fd);
+- return 0;
+- }
+- do {
+- n = read( fd, buffer, POOLSIZE );
+- } while( n == -1 && errno == EINTR );
+- if( n != POOLSIZE ) {
+- log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
+- close(fd);
+- return 0;
+- }
+-
+- close(fd);
+-
+- add_randomness( buffer, POOLSIZE, 0 );
+- /* add some minor entropy to the pool now (this will also force a mixing) */
+- { pid_t x = getpid();
+- add_randomness( &x, sizeof(x), 0 );
+- }
+- { time_t x = time(NULL);
+- add_randomness( &x, sizeof(x), 0 );
+- }
+- { clock_t x = clock();
+- add_randomness( &x, sizeof(x), 0 );
+- }
+- /* And read a few bytes from our entropy source. By using
+- * a level of 0 this will not block and might not return anything
+- * with some entropy drivers, however the rndlinux driver will use
+- * /dev/urandom and return some stuff - Do not read to much as we
+- * want to be friendly to the scare system entropy resource. */
+- read_random_source( 0, 16, 0 );
+-
+- allow_seed_file_update = 1;
+- return 1;
+-}
+-
+-void
+-update_random_seed_file()
+-{
+- ulong *sp, *dp;
+- int fd, i;
+-
+- if( !seed_file_name || !is_initialized || !pool_filled )
+- return;
+- if( !allow_seed_file_update ) {
+- log_info(_("note: random_seed file not updated\n"));
+- return;
+- }
+-
+-
+- /* copy the entropy pool to a scratch pool and mix both of them */
+- for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+- i < POOLWORDS; i++, dp++, sp++ ) {
+- *dp = *sp + ADD_VALUE;
+- }
+- mix_pool(rndpool); rndstats.mixrnd++;
+- mix_pool(keypool); rndstats.mixkey++;
+-
+- #ifdef HAVE_DOSISH_SYSTEM
+- fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
+- S_IRUSR|S_IWUSR );
+- #else
+- fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
+- #endif
+- if( fd == -1 ) {
+- log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
+- return;
+- }
+- do {
+- i = write( fd, keypool, POOLSIZE );
+- } while( i == -1 && errno == EINTR );
+- if( i != POOLSIZE ) {
+- log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno) );
+- }
+- if( close(fd) )
+- log_info(_("can't close `%s': %s\n"), seed_file_name, strerror(errno) );
+-}
+-
+-#ifdef __HURD__
+-int readable_pool( size_t length, int level )
+-{
+- size_t needed = 0;
+- size_t my_balance = pool_balance;
+- size_t available = (gatherwpos - gatherrpos + GATHERBUFSIZE) % GATHERBUFSIZE;
+-
+- if (length > POOLSIZE)
+- length = POOLSIZE;
+-
+- if (level < 2)
+- return length;
+-
+- if( !pool_filled ) {
+- if( read_seed_file() )
+- pool_filled = 1;
+- }
+-
+- if (!did_initial_extra_seeding)
+- {
+- /* Take account for initial extra seeding. */
+- needed = length;
+- if (needed < POOLSIZE/2)
+- needed = POOLSIZE/2;
+- my_balance = needed;
+-
+- if (!pool_filled && pool_writepos + needed < POOLSIZE)
+- {
+- /* If the pool is not filled yet, we couldn't read the seed
+- file. Too bad. We will now have to take account for so many
+- random_poll()s as fit into the remaining pool. */
+-
+- needed += (POOLSIZE - pool_writepos + needed + POOLSIZE/5 - 1) / (POOLSIZE/5);
+- }
+- }
+- else
+- {
+- if (!pool_filled)
+- needed += (POOLSIZE - pool_writepos + needed + POOLSIZE/5 - 1) / (POOLSIZE/5);
+- }
+-
+- /* NEEDED contains the bytes needed for initialization, MY_BALANCE the resulting
+- available bytes. */
+- if (available < needed)
+- return 0;
+- return available + my_balance - needed;
+-}
+-#endif
+-
+-#ifndef __HURD__
+-static void
+-#else
+-int
+-#endif
+-read_pool( byte *buffer, size_t length, int level )
+-{
+- int i;
+- ulong *sp, *dp;
+-
+- if( length > POOLSIZE ) {
+-#ifndef __HURD__
+- log_fatal(_("too many random bits requested; the limit is %d\n"),
+- POOLSIZE*8-1 );
+-#else
+- length = POOLSIZE;
+-#endif
+- }
+-
+- if( !pool_filled ) {
+- if( read_seed_file() )
+- pool_filled = 1;
+- }
+-
+- /* For level 2 quality (key generation) we alwas make
+- * sure that the pool has been seeded enough initially */
+- if( level == 2 && !did_initial_extra_seeding ) {
+- size_t needed;
+-
+- pool_balance = 0;
+- needed = length - pool_balance;
+- if( needed < POOLSIZE/2 )
+- needed = POOLSIZE/2;
+- else if( needed > POOLSIZE )
+- BUG();
+-#ifdef __HURD__
+- needed =
+-#endif
+- read_random_source( 3, needed, 2 );
+-#ifdef __HURD__
+- if (! needed)
+- return 0;
+- /* XXX This will succeed with needed < POOLSIZE/2 even. But
+- erroring out will waste the random we already got. */
+-#endif
+- pool_balance += needed;
+- did_initial_extra_seeding=1;
+- }
+-
+- /* for level 2 make sure that there is enough random in the pool */
+- if( level == 2 && pool_balance < length ) {
+- size_t needed;
+-
+- if( pool_balance < 0 )
+- pool_balance = 0;
+- needed = length - pool_balance;
+- if( needed > POOLSIZE )
+- BUG();
+-#ifdef __HURD__
+- needed =
+-#endif
+- read_random_source( 3, needed, 2 );
+- pool_balance += needed;
+- }
+-
+-#ifdef __HURD__
+- /* XXX This makes level 0 and 1 worse than needed at first start up. */
+- if (level == 2)
+-#endif
+- /* make sure the pool is filled */
+- while( !pool_filled )
+- random_poll();
+-
+- /* do always a fast random poll */
+- fast_random_poll();
+-
+- if( !level ) { /* no need for cryptographic strong random */
+- /* create a new pool */
+- for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+- i < POOLWORDS; i++, dp++, sp++ )
+- *dp = *sp + ADD_VALUE;
+- /* must mix both pools */
+- mix_pool(rndpool); rndstats.mixrnd++;
+- mix_pool(keypool); rndstats.mixkey++;
+- memcpy( buffer, keypool, length );
+- return length;
+- }
+- else {
+-#ifdef __HURD__
+- int amount;
+-#endif
+- /* mix the pool (if add_randomness() didn't it) */
+- if( !just_mixed ) {
+- mix_pool(rndpool);
+- rndstats.mixrnd++;
+- }
+- /* create a new pool */
+- for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
+- i < POOLWORDS; i++, dp++, sp++ )
+- *dp = *sp + ADD_VALUE;
+- /* and mix both pools */
+- mix_pool(rndpool); rndstats.mixrnd++;
+- mix_pool(keypool); rndstats.mixkey++;
+- /* read the required data
+- * we use a readpointer to read from a different position each
+- * time */
+-#ifdef __HURD__
+- if (level == 2 && length > pool_balance)
+- length = pool_balance;
+- amount = length;
+-#endif
+- while( length-- ) {
+- *buffer++ = keypool[pool_readpos++];
+- if( pool_readpos >= POOLSIZE )
+- pool_readpos = 0;
+- pool_balance--;
+- }
+- if( pool_balance < 0 )
+- pool_balance = 0;
+- /* and clear the keypool */
+- memset( keypool, 0, POOLSIZE );
+-#ifdef __HURD__
+- return amount;
+-#endif
+- }
+-}
+-
+-
+-/****************
+- * Add LENGTH bytes of randomness from buffer to the pool.
+- * source may be used to specify the randomness source.
+- * Source is:
+- * 0 - used ony for initialization
+- * 1 - fast random poll function
+- * 2 - normal poll function
+- * 3 - used when level 2 random quality has been requested
+- * to do an extra pool seed.
+- */
+-static void
+-add_randomness( const void *buffer, size_t length, int source )
+-{
+- const byte *p = buffer;
+-
+- if( !is_initialized )
+- initialize();
+- rndstats.addbytes += length;
+- rndstats.naddbytes++;
+- while( length-- ) {
+- rndpool[pool_writepos++] = *p++;
+- if( pool_writepos >= POOLSIZE ) {
+- if( source > 1 )
+- pool_filled = 1;
+- pool_writepos = 0;
+- mix_pool(rndpool); rndstats.mixrnd++;
+- just_mixed = !length;
+- }
+- }
+-}
+-
+-
+-
+-static void
+-random_poll()
+-{
+- rndstats.slowpolls++;
+- read_random_source( 2, POOLSIZE/5, 1 );
+-}
+-
+-
+-void
+-fast_random_poll()
+-{
+- static void (*fnc)( void (*)(const void*, size_t, int), int) = NULL;
+- static int initialized = 0;
+-
+- rndstats.fastpolls++;
+- if( !initialized ) {
+- if( !is_initialized )
+- initialize();
+- initialized = 1;
+- fnc = dynload_getfnc_fast_random_poll();
+- }
+- if( fnc ) {
+- (*fnc)( add_randomness, 1 );
+- return;
+- }
+-
+- /* fall back to the generic function */
+- #if HAVE_GETHRTIME
+- { hrtime_t tv;
+- tv = gethrtime();
+- add_randomness( &tv, sizeof(tv), 1 );
+- }
+- #elif HAVE_GETTIMEOFDAY
+- { struct timeval tv;
+- if( gettimeofday( &tv, NULL ) )
+- BUG();
+- add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
+- add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
+- }
+- #elif HAVE_CLOCK_GETTIME
+- { struct timespec tv;
+- if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
+- BUG();
+- add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
+- add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), 1 );
+- }
+- #else /* use times */
+- #ifndef HAVE_DOSISH_SYSTEM
+- { struct tms buf;
+- times( &buf );
+- add_randomness( &buf, sizeof buf, 1 );
+- }
+- #endif
+- #endif
+- #ifdef HAVE_GETRUSAGE
+- #ifndef RUSAGE_SELF
+- #ifdef __GCC__
+- #warning There is no RUSAGE_SELF on this system
+- #endif
+- #else
+- { struct rusage buf;
+- /* QNX/Neutrino does return ENOSYS - so we just ignore it and
+- * add whatever is in buf. In a chroot environment it might not
+- * work at all (i.e. because /proc/ is not accessible), so we better
+- * ognore all error codes and hope for the best
+- */
+- getrusage( RUSAGE_SELF, &buf );
+-
+- add_randomness( &buf, sizeof buf, 1 );
+- memset( &buf, 0, sizeof buf );
+- }
+- #endif
+- #endif
+- /* time and clock are available on all systems - so
+- * we better do it just in case one of the above functions
+- * didn't work */
+- { time_t x = time(NULL);
+- add_randomness( &x, sizeof(x), 1 );
+- }
+- { clock_t x = clock();
+- add_randomness( &x, sizeof(x), 1 );
+- }
+-}
+-
+-
+-#ifndef __HURD__
+-static void
+-#else
+-static int
+-#endif
+-read_random_source( int requester, size_t length, int level )
+-{
+- static int (*fnc)(void (*)(const void*, size_t, int), int,
+- size_t, int) = NULL;
+-#ifdef __HURD__
+- int got;
+-#endif
+- if( !fnc ) {
+- if( !is_initialized )
+- initialize();
+- fnc = dynload_getfnc_gather_random();
+- if( !fnc ) {
+- faked_rng = 1;
+- fnc = gather_faked;
+- }
+- if( !requester && !length && !level )
+-#ifndef __HURD__
+- return; /* init only */
+-#else
+- return 0;
+-#endif
+- }
+-#ifndef __HURD__
+- if( (*fnc)( add_randomness, requester, length, level ) < 0 )
+- log_fatal("No way to gather entropy for the RNG\n");
+-#else
+- got = (*fnc)( add_randomness, requester, length, level );
+- if (got < 0)
+- log_fatal("No way to gather entropy for the RNG\n");
+- return got;
+-#endif
+-}
+-
+-
+-static int
+-gather_faked( void (*add)(const void*, size_t, int), int requester,
+- size_t length, int level )
+-{
+- static int initialized=0;
+- size_t n;
+- char *buffer, *p;
+-
+- if( !initialized ) {
+- log_info(_("WARNING: using insecure random number generator!!\n"));
+- tty_printf(_("The random number generator is only a kludge to let\n"
+- "it run - it is in no way a strong RNG!\n\n"
+- "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
+- initialized=1;
+- #ifdef HAVE_RAND
+- srand(make_timestamp()*getpid());
+- #else
+- srandom(make_timestamp()*getpid());
+- #endif
+- }
+- printf("WAITING FOR %i bytes.\n", length);
+- p = buffer = m_alloc( length );
+- n = length;
+- #ifdef HAVE_RAND
+- while( n-- )
+- *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
+- #else
+- while( n-- )
+- *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
+- #endif
+- add_randomness( buffer, length, requester );
+- m_free(buffer);
+- return 0; /* okay */
+-}
+-
+diff --git a/random/gnupg-random.h b/random/gnupg-random.h
+deleted file mode 100644
+index ee18feb..0000000
+--- a/random/gnupg-random.h
++++ /dev/null
+@@ -1,47 +0,0 @@
+-/* random.h - random functions
+- * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+- *
+- * This file is part of GnuPG.
+- *
+- * GnuPG is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * GnuPG is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+- */
+-#ifndef G10_RANDOM_H
+-#define G10_RANDOM_H
+-
+-#ifndef __HURD__
+-#include "types.h"
+-#else
+-#include "gnupg-glue.h"
+-int read_pool (byte *, size_t, int);
+-int readable_pool (size_t, int);
+-#endif
+-
+-/*-- random.c --*/
+-void random_dump_stats(void);
+-void secure_random_alloc(void);
+-void set_random_seed_file(const char *);
+-void update_random_seed_file(void);
+-int quick_random_gen( int onoff );
+-int random_is_faked(void);
+-void randomize_buffer( byte *buffer, size_t length, int level );
+-byte *get_random_bits( size_t nbits, int level, int secure );
+-void fast_random_poll( void );
+-
+-/*-- rndw32.c --*/
+-#ifdef USE_STATIC_RNDW32
+-void rndw32_set_dll_name( const char *name );
+-#endif
+-
+-#endif /*G10_RANDOM_H*/
+diff --git a/random/gnupg-rmd.h b/random/gnupg-rmd.h
+deleted file mode 100644
+index 2446fc7..0000000
+--- a/random/gnupg-rmd.h
++++ /dev/null
+@@ -1,38 +0,0 @@
+-/* rmd.h - RIPE-MD hash functions
+- * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+- *
+- * This file is part of GnuPG.
+- *
+- * GnuPG is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * GnuPG is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+- */
+-#ifndef G10_RMD_H
+-#define G10_RMD_H
+-
+-#ifdef __HURD__
+-#include "gnupg-glue.h"
+-#endif
+-
+-/* we need this here because random.c must have direct access */
+-typedef struct {
+- u32 h0,h1,h2,h3,h4;
+- u32 nblocks;
+- byte buf[64];
+- int count;
+-} RMD160_CONTEXT;
+-
+-void rmd160_init( RMD160_CONTEXT *hd );
+-void rmd160_mixblock( RMD160_CONTEXT *hd, char *buffer );
+-
+-#endif /*G10_RMD_H*/
+diff --git a/random/gnupg-rmd160.c b/random/gnupg-rmd160.c
+deleted file mode 100644
+index 6610768..0000000
+--- a/random/gnupg-rmd160.c
++++ /dev/null
+@@ -1,656 +0,0 @@
+-/* rmd160.c - RIPE-MD160
+- * Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
+- *
+- * This file is part of GnuPG.
+- *
+- * GnuPG is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License as published by
+- * the Free Software Foundation; either version 2 of the License, or
+- * (at your option) any later version.
+- *
+- * GnuPG is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- *
+- * You should have received a copy of the GNU General Public License
+- * along with this program; if not, write to the Free Software
+- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+- */
+-
+-#ifndef __HURD__
+-#include <config.h>
+-#endif
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <string.h>
+-#include <assert.h>
+-#ifndef __HURD__
+-#include "util.h"
+-#include "memory.h"
+-#include "rmd.h"
+-#include "cipher.h" /* only used for the rmd160_hash_buffer() prototype */
+-#include "dynload.h"
+-
+-#include "bithelp.h"
+-#else
+-#include "gnupg-rmd.h"
+-#include "gnupg-bithelp.h"
+-#endif
+-
+-
+-/*********************************
+- * RIPEMD-160 is not patented, see (as of 25.10.97)
+- * http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html
+- * Note that the code uses Little Endian byteorder, which is good for
+- * 386 etc, but we must add some conversion when used on a big endian box.
+- *
+- *
+- * Pseudo-code for RIPEMD-160
+- *
+- * RIPEMD-160 is an iterative hash function that operates on 32-bit words.
+- * The round function takes as input a 5-word chaining variable and a 16-word
+- * message block and maps this to a new chaining variable. All operations are
+- * defined on 32-bit words. Padding is identical to that of MD4.
+- *
+- *
+- * RIPEMD-160: definitions
+- *
+- *
+- * nonlinear functions at bit level: exor, mux, -, mux, -
+- *
+- * f(j, x, y, z) = x XOR y XOR z (0 <= j <= 15)
+- * f(j, x, y, z) = (x AND y) OR (NOT(x) AND z) (16 <= j <= 31)
+- * f(j, x, y, z) = (x OR NOT(y)) XOR z (32 <= j <= 47)
+- * f(j, x, y, z) = (x AND z) OR (y AND NOT(z)) (48 <= j <= 63)
+- * f(j, x, y, z) = x XOR (y OR NOT(z)) (64 <= j <= 79)
+- *
+- *
+- * added constants (hexadecimal)
+- *
+- * K(j) = 0x00000000 (0 <= j <= 15)
+- * K(j) = 0x5A827999 (16 <= j <= 31) int(2**30 x sqrt(2))
+- * K(j) = 0x6ED9EBA1 (32 <= j <= 47) int(2**30 x sqrt(3))
+- * K(j) = 0x8F1BBCDC (48 <= j <= 63) int(2**30 x sqrt(5))
+- * K(j) = 0xA953FD4E (64 <= j <= 79) int(2**30 x sqrt(7))
+- * K'(j) = 0x50A28BE6 (0 <= j <= 15) int(2**30 x cbrt(2))
+- * K'(j) = 0x5C4DD124 (16 <= j <= 31) int(2**30 x cbrt(3))
+- * K'(j) = 0x6D703EF3 (32 <= j <= 47) int(2**30 x cbrt(5))
+- * K'(j) = 0x7A6D76E9 (48 <= j <= 63) int(2**30 x cbrt(7))
+- * K'(j) = 0x00000000 (64 <= j <= 79)
+- *
+- *
+- * selection of message word
+- *
+- * r(j) = j (0 <= j <= 15)
+- * r(16..31) = 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8
+- * r(32..47) = 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12
+- * r(48..63) = 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2
+- * r(64..79) = 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
+- * r0(0..15) = 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12
+- * r0(16..31)= 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2
+- * r0(32..47)= 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13
+- * r0(48..63)= 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14
+- * r0(64..79)= 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
+- *
+- *
+- * amount for rotate left (rol)
+- *
+- * s(0..15) = 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8
+- * s(16..31) = 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12
+- * s(32..47) = 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5
+- * s(48..63) = 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12
+- * s(64..79) = 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
+- * s'(0..15) = 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6
+- * s'(16..31)= 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11
+- * s'(32..47)= 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5
+- * s'(48..63)= 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8
+- * s'(64..79)= 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
+- *
+- *
+- * initial value (hexadecimal)
+- *
+- * h0 = 0x67452301; h1 = 0xEFCDAB89; h2 = 0x98BADCFE; h3 = 0x10325476;
+- * h4 = 0xC3D2E1F0;
+- *
+- *
+- * RIPEMD-160: pseudo-code
+- *
+- * It is assumed that the message after padding consists of t 16-word blocks
+- * that will be denoted with X[i][j], with 0 <= i <= t-1 and 0 <= j <= 15.
+- * The symbol [+] denotes addition modulo 2**32 and rol_s denotes cyclic left
+- * shift (rotate) over s positions.
+- *
+- *
+- * for i := 0 to t-1 {
+- * A := h0; B := h1; C := h2; D = h3; E = h4;
+- * A' := h0; B' := h1; C' := h2; D' = h3; E' = h4;
+- * for j := 0 to 79 {
+- * T := rol_s(j)(A [+] f(j, B, C, D) [+] X[i][r(j)] [+] K(j)) [+] E;
+- * A := E; E := D; D := rol_10(C); C := B; B := T;
+- * T := rol_s'(j)(A' [+] f(79-j, B', C', D') [+] X[i][r'(j)]
+- [+] K'(j)) [+] E';
+- * A' := E'; E' := D'; D' := rol_10(C'); C' := B'; B' := T;
+- * }
+- * T := h1 [+] C [+] D'; h1 := h2 [+] D [+] E'; h2 := h3 [+] E [+] A';
+- * h3 := h4 [+] A [+] B'; h4 := h0 [+] B [+] C'; h0 := T;
+- * }
+- */
+-
+-/* Some examples:
+- * "" 9c1185a5c5e9fc54612808977ee8f548b2258d31
+- * "a" 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe
+- * "abc" 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
+- * "message digest" 5d0689ef49d2fae572b881b123a85ffa21595f36
+- * "a...z" f71c27109c692c1b56bbdceb5b9d2865b3708dbc
+- * "abcdbcde...nopq" 12a053384a9c0c88e405a06c27dcf49ada62eb2b
+- * "A...Za...z0...9" b0e20b6e3116640286ed3a87a5713079b21f5189
+- * 8 times "1234567890" 9b752e45573d4b39f4dbd3323cab82bf63326bfb
+- * 1 million times "a" 52783243c1697bdbe16d37f97f68f08325dc1528
+- */
+-
+-static void
+-burn_stack (int bytes)
+-{
+- char buf[150];
+-
+- memset (buf, 0, sizeof buf);
+- bytes -= sizeof buf;
+- if (bytes > 0)
+- burn_stack (bytes);
+-}
+-
+-
+-
+-void
+-rmd160_init( RMD160_CONTEXT *hd )
+-{
+- hd->h0 = 0x67452301;
+- hd->h1 = 0xEFCDAB89;
+- hd->h2 = 0x98BADCFE;
+- hd->h3 = 0x10325476;
+- hd->h4 = 0xC3D2E1F0;
+- hd->nblocks = 0;
+- hd->count = 0;
+-}
+-
+-
+-
+-/****************
+- * Transform the message X which consists of 16 32-bit-words
+- */
+-static void
+-transform( RMD160_CONTEXT *hd, byte *data )
+-{
+- u32 a,b,c,d,e,aa,bb,cc,dd,ee,t;
+- #ifdef BIG_ENDIAN_HOST
+- u32 x[16];
+- { int i;
+- byte *p2, *p1;
+- for(i=0, p1=data, p2=(byte*)x; i < 16; i++, p2 += 4 ) {
+- p2[3] = *p1++;
+- p2[2] = *p1++;
+- p2[1] = *p1++;
+- p2[0] = *p1++;
+- }
+- }
+- #else
+- #if 0
+- u32 *x =(u32*)data;
+- #else
+- /* this version is better because it is always aligned;
+- * The performance penalty on a 586-100 is about 6% which
+- * is acceptable - because the data is more local it might
+- * also be possible that this is faster on some machines.
+- * This function (when compiled with -02 on gcc 2.7.2)
+- * executes on a 586-100 (39.73 bogomips) at about 1900kb/sec;
+- * [measured with a 4MB data and "gpgm --print-md rmd160"] */
+- u32 x[16];
+- memcpy( x, data, 64 );
+- #endif
+- #endif
+-
+-
+-#define K0 0x00000000
+-#define K1 0x5A827999
+-#define K2 0x6ED9EBA1
+-#define K3 0x8F1BBCDC
+-#define K4 0xA953FD4E
+-#define KK0 0x50A28BE6
+-#define KK1 0x5C4DD124
+-#define KK2 0x6D703EF3
+-#define KK3 0x7A6D76E9
+-#define KK4 0x00000000
+-#define F0(x,y,z) ( (x) ^ (y) ^ (z) )
+-#define F1(x,y,z) ( ((x) & (y)) | (~(x) & (z)) )
+-#define F2(x,y,z) ( ((x) | ~(y)) ^ (z) )
+-#define F3(x,y,z) ( ((x) & (z)) | ((y) & ~(z)) )
+-#define F4(x,y,z) ( (x) ^ ((y) | ~(z)) )
+-#define R(a,b,c,d,e,f,k,r,s) do { t = a + f(b,c,d) + k + x[r]; \
+- a = rol(t,s) + e; \
+- c = rol(c,10); \
+- } while(0)
+-
+- /* left lane */
+- a = hd->h0;
+- b = hd->h1;
+- c = hd->h2;
+- d = hd->h3;
+- e = hd->h4;
+- R( a, b, c, d, e, F0, K0, 0, 11 );
+- R( e, a, b, c, d, F0, K0, 1, 14 );
+- R( d, e, a, b, c, F0, K0, 2, 15 );
+- R( c, d, e, a, b, F0, K0, 3, 12 );
+- R( b, c, d, e, a, F0, K0, 4, 5 );
+- R( a, b, c, d, e, F0, K0, 5, 8 );
+- R( e, a, b, c, d, F0, K0, 6, 7 );
+- R( d, e, a, b, c, F0, K0, 7, 9 );
+- R( c, d, e, a, b, F0, K0, 8, 11 );
+- R( b, c, d, e, a, F0, K0, 9, 13 );
+- R( a, b, c, d, e, F0, K0, 10, 14 );
+- R( e, a, b, c, d, F0, K0, 11, 15 );
+- R( d, e, a, b, c, F0, K0, 12, 6 );
+- R( c, d, e, a, b, F0, K0, 13, 7 );
+- R( b, c, d, e, a, F0, K0, 14, 9 );
+- R( a, b, c, d, e, F0, K0, 15, 8 );
+- R( e, a, b, c, d, F1, K1, 7, 7 );
+- R( d, e, a, b, c, F1, K1, 4, 6 );
+- R( c, d, e, a, b, F1, K1, 13, 8 );
+- R( b, c, d, e, a, F1, K1, 1, 13 );
+- R( a, b, c, d, e, F1, K1, 10, 11 );
+- R( e, a, b, c, d, F1, K1, 6, 9 );
+- R( d, e, a, b, c, F1, K1, 15, 7 );
+- R( c, d, e, a, b, F1, K1, 3, 15 );
+- R( b, c, d, e, a, F1, K1, 12, 7 );
+- R( a, b, c, d, e, F1, K1, 0, 12 );
+- R( e, a, b, c, d, F1, K1, 9, 15 );
+- R( d, e, a, b, c, F1, K1, 5, 9 );
+- R( c, d, e, a, b, F1, K1, 2, 11 );
+- R( b, c, d, e, a, F1, K1, 14, 7 );
+- R( a, b, c, d, e, F1, K1, 11, 13 );
+- R( e, a, b, c, d, F1, K1, 8, 12 );
+- R( d, e, a, b, c, F2, K2, 3, 11 );
+- R( c, d, e, a, b, F2, K2, 10, 13 );
+- R( b, c, d, e, a, F2, K2, 14, 6 );
+- R( a, b, c, d, e, F2, K2, 4, 7 );
+- R( e, a, b, c, d, F2, K2, 9, 14 );
+- R( d, e, a, b, c, F2, K2, 15, 9 );
+- R( c, d, e, a, b, F2, K2, 8, 13 );
+- R( b, c, d, e, a, F2, K2, 1, 15 );
+- R( a, b, c, d, e, F2, K2, 2, 14 );
+- R( e, a, b, c, d, F2, K2, 7, 8 );
+- R( d, e, a, b, c, F2, K2, 0, 13 );
+- R( c, d, e, a, b, F2, K2, 6, 6 );
+- R( b, c, d, e, a, F2, K2, 13, 5 );
+- R( a, b, c, d, e, F2, K2, 11, 12 );
+- R( e, a, b, c, d, F2, K2, 5, 7 );
+- R( d, e, a, b, c, F2, K2, 12, 5 );
+- R( c, d, e, a, b, F3, K3, 1, 11 );
+- R( b, c, d, e, a, F3, K3, 9, 12 );
+- R( a, b, c, d, e, F3, K3, 11, 14 );
+- R( e, a, b, c, d, F3, K3, 10, 15 );
+- R( d, e, a, b, c, F3, K3, 0, 14 );
+- R( c, d, e, a, b, F3, K3, 8, 15 );
+- R( b, c, d, e, a, F3, K3, 12, 9 );
+- R( a, b, c, d, e, F3, K3, 4, 8 );
+- R( e, a, b, c, d, F3, K3, 13, 9 );
+- R( d, e, a, b, c, F3, K3, 3, 14 );
+- R( c, d, e, a, b, F3, K3, 7, 5 );
+- R( b, c, d, e, a, F3, K3, 15, 6 );
+- R( a, b, c, d, e, F3, K3, 14, 8 );
+- R( e, a, b, c, d, F3, K3, 5, 6 );
+- R( d, e, a, b, c, F3, K3, 6, 5 );
+- R( c, d, e, a, b, F3, K3, 2, 12 );
+- R( b, c, d, e, a, F4, K4, 4, 9 );
+- R( a, b, c, d, e, F4, K4, 0, 15 );
+- R( e, a, b, c, d, F4, K4, 5, 5 );
+- R( d, e, a, b, c, F4, K4, 9, 11 );
+- R( c, d, e, a, b, F4, K4, 7, 6 );
+- R( b, c, d, e, a, F4, K4, 12, 8 );
+- R( a, b, c, d, e, F4, K4, 2, 13 );
+- R( e, a, b, c, d, F4, K4, 10, 12 );
+- R( d, e, a, b, c, F4, K4, 14, 5 );
+- R( c, d, e, a, b, F4, K4, 1, 12 );
+- R( b, c, d, e, a, F4, K4, 3, 13 );
+- R( a, b, c, d, e, F4, K4, 8, 14 );
+- R( e, a, b, c, d, F4, K4, 11, 11 );
+- R( d, e, a, b, c, F4, K4, 6, 8 );
+- R( c, d, e, a, b, F4, K4, 15, 5 );
+- R( b, c, d, e, a, F4, K4, 13, 6 );
+-
+- aa = a; bb = b; cc = c; dd = d; ee = e;
+-
+- /* right lane */
+- a = hd->h0;
+- b = hd->h1;
+- c = hd->h2;
+- d = hd->h3;
+- e = hd->h4;
+- R( a, b, c, d, e, F4, KK0, 5, 8);
+- R( e, a, b, c, d, F4, KK0, 14, 9);
+- R( d, e, a, b, c, F4, KK0, 7, 9);
+- R( c, d, e, a, b, F4, KK0, 0, 11);
+- R( b, c, d, e, a, F4, KK0, 9, 13);
+- R( a, b, c, d, e, F4, KK0, 2, 15);
+- R( e, a, b, c, d, F4, KK0, 11, 15);
+- R( d, e, a, b, c, F4, KK0, 4, 5);
+- R( c, d, e, a, b, F4, KK0, 13, 7);
+- R( b, c, d, e, a, F4, KK0, 6, 7);
+- R( a, b, c, d, e, F4, KK0, 15, 8);
+- R( e, a, b, c, d, F4, KK0, 8, 11);
+- R( d, e, a, b, c, F4, KK0, 1, 14);
+- R( c, d, e, a, b, F4, KK0, 10, 14);
+- R( b, c, d, e, a, F4, KK0, 3, 12);
+- R( a, b, c, d, e, F4, KK0, 12, 6);
+- R( e, a, b, c, d, F3, KK1, 6, 9);
+- R( d, e, a, b, c, F3, KK1, 11, 13);
+- R( c, d, e, a, b, F3, KK1, 3, 15);
+- R( b, c, d, e, a, F3, KK1, 7, 7);
+- R( a, b, c, d, e, F3, KK1, 0, 12);
+- R( e, a, b, c, d, F3, KK1, 13, 8);
+- R( d, e, a, b, c, F3, KK1, 5, 9);
+- R( c, d, e, a, b, F3, KK1, 10, 11);
+- R( b, c, d, e, a, F3, KK1, 14, 7);
+- R( a, b, c, d, e, F3, KK1, 15, 7);
+- R( e, a, b, c, d, F3, KK1, 8, 12);
+- R( d, e, a, b, c, F3, KK1, 12, 7);
+- R( c, d, e, a, b, F3, KK1, 4, 6);
+- R( b, c, d, e, a, F3, KK1, 9, 15);
+- R( a, b, c, d, e, F3, KK1, 1, 13);
+- R( e, a, b, c, d, F3, KK1, 2, 11);
+- R( d, e, a, b, c, F2, KK2, 15, 9);
+- R( c, d, e, a, b, F2, KK2, 5, 7);
+- R( b, c, d, e, a, F2, KK2, 1, 15);
+- R( a, b, c, d, e, F2, KK2, 3, 11);
+- R( e, a, b, c, d, F2, KK2, 7, 8);
+- R( d, e, a, b, c, F2, KK2, 14, 6);
+- R( c, d, e, a, b, F2, KK2, 6, 6);
+- R( b, c, d, e, a, F2, KK2, 9, 14);
+- R( a, b, c, d, e, F2, KK2, 11, 12);
+- R( e, a, b, c, d, F2, KK2, 8, 13);
+- R( d, e, a, b, c, F2, KK2, 12, 5);
+- R( c, d, e, a, b, F2, KK2, 2, 14);
+- R( b, c, d, e, a, F2, KK2, 10, 13);
+- R( a, b, c, d, e, F2, KK2, 0, 13);
+- R( e, a, b, c, d, F2, KK2, 4, 7);
+- R( d, e, a, b, c, F2, KK2, 13, 5);
+- R( c, d, e, a, b, F1, KK3, 8, 15);
+- R( b, c, d, e, a, F1, KK3, 6, 5);
+- R( a, b, c, d, e, F1, KK3, 4, 8);
+- R( e, a, b, c, d, F1, KK3, 1, 11);
+- R( d, e, a, b, c, F1, KK3, 3, 14);
+- R( c, d, e, a, b, F1, KK3, 11, 14);
+- R( b, c, d, e, a, F1, KK3, 15, 6);
+- R( a, b, c, d, e, F1, KK3, 0, 14);
+- R( e, a, b, c, d, F1, KK3, 5, 6);
+- R( d, e, a, b, c, F1, KK3, 12, 9);
+- R( c, d, e, a, b, F1, KK3, 2, 12);
+- R( b, c, d, e, a, F1, KK3, 13, 9);
+- R( a, b, c, d, e, F1, KK3, 9, 12);
+- R( e, a, b, c, d, F1, KK3, 7, 5);
+- R( d, e, a, b, c, F1, KK3, 10, 15);
+- R( c, d, e, a, b, F1, KK3, 14, 8);
+- R( b, c, d, e, a, F0, KK4, 12, 8);
+- R( a, b, c, d, e, F0, KK4, 15, 5);
+- R( e, a, b, c, d, F0, KK4, 10, 12);
+- R( d, e, a, b, c, F0, KK4, 4, 9);
+- R( c, d, e, a, b, F0, KK4, 1, 12);
+- R( b, c, d, e, a, F0, KK4, 5, 5);
+- R( a, b, c, d, e, F0, KK4, 8, 14);
+- R( e, a, b, c, d, F0, KK4, 7, 6);
+- R( d, e, a, b, c, F0, KK4, 6, 8);
+- R( c, d, e, a, b, F0, KK4, 2, 13);
+- R( b, c, d, e, a, F0, KK4, 13, 6);
+- R( a, b, c, d, e, F0, KK4, 14, 5);
+- R( e, a, b, c, d, F0, KK4, 0, 15);
+- R( d, e, a, b, c, F0, KK4, 3, 13);
+- R( c, d, e, a, b, F0, KK4, 9, 11);
+- R( b, c, d, e, a, F0, KK4, 11, 11);
+-
+-
+- t = hd->h1 + d + cc;
+- hd->h1 = hd->h2 + e + dd;
+- hd->h2 = hd->h3 + a + ee;
+- hd->h3 = hd->h4 + b + aa;
+- hd->h4 = hd->h0 + c + bb;
+- hd->h0 = t;
+-}
+-
+-
+-/* Update the message digest with the contents
+- * of INBUF with length INLEN.
+- */
+-static void
+-rmd160_write( RMD160_CONTEXT *hd, byte *inbuf, size_t inlen)
+-{
+- if( hd->count == 64 ) { /* flush the buffer */
+- transform( hd, hd->buf );
+- burn_stack (108+5*sizeof(void*));
+- hd->count = 0;
+- hd->nblocks++;
+- }
+- if( !inbuf )
+- return;
+- if( hd->count ) {
+- for( ; inlen && hd->count < 64; inlen-- )
+- hd->buf[hd->count++] = *inbuf++;
+- rmd160_write( hd, NULL, 0 );
+- if( !inlen )
+- return;
+- }
+-
+- while( inlen >= 64 ) {
+- transform( hd, inbuf );
+- hd->count = 0;
+- hd->nblocks++;
+- inlen -= 64;
+- inbuf += 64;
+- }
+- burn_stack (108+5*sizeof(void*));
+- for( ; inlen && hd->count < 64; inlen-- )
+- hd->buf[hd->count++] = *inbuf++;
+-}
+-
+-/****************
+- * Apply the rmd160 transform function on the buffer which must have
+- * a length 64 bytes. Do not use this function together with the
+- * other functions, use rmd160_init to initialize internal variables.
+- * Returns: 16 bytes in buffer with the mixed contentes of buffer.
+- */
+-void
+-rmd160_mixblock( RMD160_CONTEXT *hd, char *buffer )
+-{
+- char *p = buffer;
+- transform( hd, buffer );
+- #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+- X(0);
+- X(1);
+- X(2);
+- X(3);
+- X(4);
+- #undef X
+-}
+-
+-
+-/* The routine terminates the computation
+- */
+-
+-static void
+-rmd160_final( RMD160_CONTEXT *hd )
+-{
+- u32 t, msb, lsb;
+- byte *p;
+-
+- rmd160_write(hd, NULL, 0); /* flush */;
+-
+- t = hd->nblocks;
+- /* multiply by 64 to make a byte count */
+- lsb = t << 6;
+- msb = t >> 26;
+- /* add the count */
+- t = lsb;
+- if( (lsb += hd->count) < t )
+- msb++;
+- /* multiply by 8 to make a bit count */
+- t = lsb;
+- lsb <<= 3;
+- msb <<= 3;
+- msb |= t >> 29;
+-
+- if( hd->count < 56 ) { /* enough room */
+- hd->buf[hd->count++] = 0x80; /* pad */
+- while( hd->count < 56 )
+- hd->buf[hd->count++] = 0; /* pad */
+- }
+- else { /* need one extra block */
+- hd->buf[hd->count++] = 0x80; /* pad character */
+- while( hd->count < 64 )
+- hd->buf[hd->count++] = 0;
+- rmd160_write(hd, NULL, 0); /* flush */;
+- memset(hd->buf, 0, 56 ); /* fill next block with zeroes */
+- }
+- /* append the 64 bit count */
+- hd->buf[56] = lsb ;
+- hd->buf[57] = lsb >> 8;
+- hd->buf[58] = lsb >> 16;
+- hd->buf[59] = lsb >> 24;
+- hd->buf[60] = msb ;
+- hd->buf[61] = msb >> 8;
+- hd->buf[62] = msb >> 16;
+- hd->buf[63] = msb >> 24;
+- transform( hd, hd->buf );
+- burn_stack (108+5*sizeof(void*));
+-
+- p = hd->buf;
+- #ifdef BIG_ENDIAN_HOST
+- #define X(a) do { *p++ = hd->h##a ; *p++ = hd->h##a >> 8; \
+- *p++ = hd->h##a >> 16; *p++ = hd->h##a >> 24; } while(0)
+- #else /* little endian */
+- #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+- #endif
+- X(0);
+- X(1);
+- X(2);
+- X(3);
+- X(4);
+- #undef X
+-}
+-
+-static byte *
+-rmd160_read( RMD160_CONTEXT *hd )
+-{
+- return hd->buf;
+-}
+-
+-
+-
+-/****************
+- * Shortcut functions which puts the hash value of the supplied buffer
+- * into outbuf which must have a size of 20 bytes.
+- */
+-void
+-rmd160_hash_buffer( char *outbuf, const char *buffer, size_t length )
+-{
+- RMD160_CONTEXT hd;
+-
+- rmd160_init( &hd );
+- rmd160_write( &hd, (byte*)buffer, length );
+- rmd160_final( &hd );
+- memcpy( outbuf, hd.buf, 20 );
+-}
+-
+-
+-/****************
+- * Return some information about the algorithm. We need algo here to
+- * distinguish different flavors of the algorithm.
+- * Returns: A pointer to string describing the algorithm or NULL if
+- * the ALGO is invalid.
+- */
+-static const char *
+-rmd160_get_info( int algo, size_t *contextsize,
+- byte **r_asnoid, int *r_asnlen, int *r_mdlen,
+- void (**r_init)( void *c ),
+- void (**r_write)( void *c, byte *buf, size_t nbytes ),
+- void (**r_final)( void *c ),
+- byte *(**r_read)( void *c )
+- )
+-{
+- static byte asn[15] = /* Object ID is 1.3.36.3.2.1 */
+- { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
+- 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
+-
+- if( algo != 3 )
+- return NULL;
+-
+- *contextsize = sizeof(RMD160_CONTEXT);
+- *r_asnoid = asn;
+- *r_asnlen = DIM(asn);
+- *r_mdlen = 20;
+- *(void (**)(RMD160_CONTEXT *))r_init = rmd160_init;
+- *(void (**)(RMD160_CONTEXT *, byte*, size_t))r_write = rmd160_write;
+- *(void (**)(RMD160_CONTEXT *))r_final = rmd160_final;
+- *(byte *(**)(RMD160_CONTEXT *))r_read = rmd160_read;
+-
+- return "RIPEMD160";
+-}
+-
+-
+-#ifndef IS_MODULE
+-static
+-#endif
+-const char * const gnupgext_version = "RMD160 ($Revision: 1.17.2.4 $)";
+-
+-static struct {
+- int class;
+- int version;
+- int value;
+- void (*func)(void);
+-} func_table[] = {
+- { 10, 1, 0, (void(*)(void))rmd160_get_info },
+- { 11, 1, 3 },
+-};
+-
+-
+-#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;
+- switch( *class ) {
+- case 11:
+- case 21:
+- case 31:
+- ret = &func_table[i].value;
+- break;
+- default:
+- ret = func_table[i].func;
+- break;
+- }
+- i++;
+- } while( what && what != *class );
+-
+- *sequence = i;
+- return ret;
+-}
+-
+-
+-
+-#ifndef __HURD__
+-#ifndef IS_MODULE
+-void
+-rmd160_constructor(void)
+-{
+- register_internal_cipher_extension( gnupgext_version, gnupgext_enum_func );
+-}
+-#endif
+-#endif
+diff --git a/random/random.c b/random/random.c
+deleted file mode 100644
+index 8f76c5b..0000000
+--- a/random/random.c
++++ /dev/null
+@@ -1,650 +0,0 @@
+-/* random.c - A single-file translator providing random data
+- Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+-
+- This program is free software; you can redistribute it and/or
+- modify it under the terms of the GNU General Public License as
+- published by the Free Software Foundation; either version 2, or (at
+- your option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-
+- You should have received a copy of the GNU General Public License
+- along with this program; if not, write to the Free Software
+- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+-
+-#define _GNU_SOURCE 1
+-
+-#include <hurd/paths.h>
+-#include <hurd/trivfs.h>
+-#include <hurd/startup.h>
+-#include <stdio.h>
+-#include <stdlib.h>
+-#include <argp.h>
+-#include <argz.h>
+-#include <error.h>
+-#include <string.h>
+-#include <fcntl.h>
+-#include <sys/mman.h>
+-#include <pthread.h>
+-#include <assert.h>
+-
+-#include <version.h>
+-
+-#include "random.h"
+-#include "gnupg-random.h"
+-
+-/* Our control port. */
+-struct trivfs_control *fsys;
+-
+-int read_blocked; /* For read and select. */
+-pthread_cond_t wait; /* For read and select. */
+-pthread_cond_t select_alert; /* For read and select. */
+-
+-
+-/* The quality of randomness we provide.
+- 0: Very weak randomness based on time() and getrusage().
+- No external random data is used.
+- 1: Pseudo random numbers based on all available real random
+- numbers.
+- 2: Strong random numbers with a somewhat guaranteed entropy.
+-*/
+-#define DEFAULT_LEVEL 2
+-static int level = DEFAULT_LEVEL;
+-
+-/* Name of file to use as seed. */
+-static char *seed_file;
+-
+-/* The random bytes we collected. */
+-char gatherbuf[GATHERBUFSIZE];
+-
+-/* The current positions in gatherbuf[]. */
+-int gatherrpos;
+-int gatherwpos;
+-
+-/* XXX Yuk Yuk. */
+-#define POOLSIZE 600
+-
+-/* Take up to length bytes from gather_random if available. If
+- nothing is available, sleep until something becomes available.
+- Must be called with global_lock held. */
+-int
+-gather_random( void (*add)(const void*, size_t, int), int requester,
+- size_t length, int level )
+-{
+- int avail = (gatherwpos - gatherrpos + GATHERBUFSIZE) % GATHERBUFSIZE;
+- int first = GATHERBUFSIZE - gatherrpos;
+- int second = length - first;
+-
+- /* If level is zero, we should not block and not add anything
+- to the pool. */
+- if( !level )
+- return 0;
+-
+- /* io_read() should guarantee that there is always data available. */
+- if (level == 2)
+- assert (avail);
+-
+- if (length > avail)
+- length = avail;
+-
+- if (first > length)
+- first = length;
+- (*add) (&gatherbuf[gatherrpos], first, requester);
+- gatherrpos = (gatherrpos + first) % GATHERBUFSIZE;
+- if (second > 0)
+- {
+- (*add) (&gatherbuf[gatherrpos], second, requester);
+- gatherrpos += second;
+- }
+- return length;
+-}
+-
+-
+-const char *argp_program_version = STANDARD_HURD_VERSION (random);
+-
+-/* This lock protects the GnuPG code. */
+-static pthread_mutex_t global_lock;
+-
+-/* Trivfs hooks. */
+-int trivfs_fstype = FSTYPE_MISC;
+-int trivfs_fsid = 0;
+-
+-int trivfs_allow_open = O_READ | O_WRITE;
+-
+-int trivfs_support_read = 1;
+-int trivfs_support_write = 1;
+-int trivfs_support_exec = 0;
+-
+-void
+-trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
+-{
+- /* Mark the node as a read-only plain file. */
+- st->st_mode &= ~S_IFMT;
+- st->st_mode |= (S_IFCHR);
+- st->st_size = 0;
+-}
+-
+-error_t
+-trivfs_goaway (struct trivfs_control *cntl, int flags)
+-{
+- update_random_seed_file ();
+- exit (0);
+-}
+-
+-/* Read data from an IO object. If offset is -1, read from the object
+- maintained file pointer. If the object is not seekable, offset is
+- ignored. The amount desired to be read is in AMOUNT. */
+-error_t
+-trivfs_S_io_read (struct trivfs_protid *cred,
+- mach_port_t reply, mach_msg_type_name_t reply_type,
+- data_t *data, mach_msg_type_number_t *data_len,
+- loff_t offs, mach_msg_type_number_t amount)
+-{
+- error_t err;
+- mach_msg_type_number_t read_amount = 0;
+- void *buf = NULL;
+- size_t length;
+-
+- /* Deny access if they have bad credentials. */
+- if (! cred)
+- return EOPNOTSUPP;
+- else if (! (cred->po->openmodes & O_READ))
+- return EBADF;
+-
+- pthread_mutex_lock (&global_lock);
+-
+- while (amount > 0)
+- {
+- mach_msg_type_number_t new_amount;
+- /* XXX: It would be nice to fix readable_pool to work for sizes
+- greater than the POOLSIZE. Otherwise we risk detecting too
+- late that we run out of entropy and all that entropy is
+- wasted. */
+- while (readable_pool (amount, level) == 0)
+- {
+- if (cred->po->openmodes & O_NONBLOCK)
+- {
+- pthread_mutex_unlock (&global_lock);
+- err = EWOULDBLOCK;
+- goto errout;
+- }
+- read_blocked = 1;
+- if (pthread_hurd_cond_wait_np (&wait, &global_lock))
+- {
+- pthread_mutex_unlock (&global_lock);
+- err = EINTR;
+- goto errout;
+- }
+- /* See term/users.c for possible race? */
+- }
+-
+- /* Possibly allocate a new buffer. */
+- if (*data_len < amount)
+- {
+- *data = mmap (0, amount, PROT_READ|PROT_WRITE,
+- MAP_ANON, 0, 0);
+-
+- if (*data == MAP_FAILED)
+- {
+- pthread_mutex_unlock (&global_lock);
+- return errno;
+- }
+-
+- /* Keep track of our map in case of errors. */
+- buf = *data, length = amount;
+-
+- /* Update DATA_LEN to reflect the new buffers size. */
+- *data_len = amount;
+- }
+-
+- new_amount = read_pool (((byte *) *data) + read_amount, amount, level);
+- read_amount += new_amount;
+- amount -= new_amount;
+- }
+-
+- /* Set atime, see term/users.c */
+-
+- pthread_mutex_unlock (&global_lock);
+- *data_len = read_amount;
+- return 0;
+-
+- errout:
+- if (buf)
+- munmap (buf, length);
+- return err;
+-}
+-
+-/* Write data to an IO object. If offset is -1, write at the object
+- maintained file pointer. If the object is not seekable, offset is
+- ignored. The amount successfully written is returned in amount. A
+- given user should not have more than one outstanding io_write on an
+- object at a time; servers implement congestion control by delaying
+- responses to io_write. Servers may drop data (returning ENOBUFS)
+- if they receive more than one write when not prepared for it. */
+-error_t
+-trivfs_S_io_write (struct trivfs_protid *cred,
+- mach_port_t reply,
+- mach_msg_type_name_t replytype,
+- data_t data,
+- mach_msg_type_number_t datalen,
+- loff_t offset,
+- mach_msg_type_number_t *amount)
+-{
+- int i = 0;
+- /* Deny access if they have bad credentials. */
+- if (! cred)
+- return EOPNOTSUPP;
+- else if (! (cred->po->openmodes & O_WRITE))
+- return EBADF;
+-
+- pthread_mutex_lock (&global_lock);
+-
+- while (i < datalen)
+- {
+- gatherbuf[gatherwpos] = data[i++];
+- gatherwpos = (gatherwpos + 1) % GATHERBUFSIZE;
+- if (gatherrpos == gatherwpos)
+- /* Overrun. */
+- gatherrpos = (gatherrpos + 1) % GATHERBUFSIZE;
+- }
+- *amount = datalen;
+-
+- if (datalen > 0 && read_blocked)
+- {
+- read_blocked = 0;
+- pthread_cond_broadcast (&wait);
+- pthread_cond_broadcast (&select_alert);
+- }
+-
+- pthread_mutex_unlock (&global_lock);
+- return 0;
+-}
+-
+-/* Tell how much data can be read from the object without blocking for
+- a "long time" (this should be the same meaning of "long time" used
+- by the nonblocking flag. */
+-kern_return_t
+-trivfs_S_io_readable (struct trivfs_protid *cred,
+- mach_port_t reply, mach_msg_type_name_t replytype,
+- mach_msg_type_number_t *amount)
+-{
+- /* Deny access if they have bad credentials. */
+- if (! cred)
+- return EOPNOTSUPP;
+- else if (! (cred->po->openmodes & O_READ))
+- return EBADF;
+-
+- pthread_mutex_lock (&global_lock);
+-
+- /* XXX: Before initialization, the amount depends on the amount we
+- want to read. Assume some medium value. */
+- *amount = readable_pool (POOLSIZE/2, level);
+-
+- pthread_mutex_unlock (&global_lock);
+-
+- return 0;
+-}
+-
+-/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
+- Block until one of the indicated types of i/o can be done "quickly", and
+- return the types that are then available. ID_TAG is returned as passed; it
+- is just for the convenience of the user in matching up reply messages with
+- specific requests sent. */
+-error_t
+-trivfs_S_io_select (struct trivfs_protid *cred,
+- mach_port_t reply,
+- mach_msg_type_name_t reply_type,
+- int *type)
+-{
+- if (!cred)
+- return EOPNOTSUPP;
+-
+- /* We only deal with SELECT_READ and SELECT_WRITE here. */
+- if (*type & ~(SELECT_READ | SELECT_WRITE))
+- return EINVAL;
+-
+- if (*type == 0)
+- return 0;
+-
+- pthread_mutex_lock (&global_lock);
+-
+- while (1)
+- {
+- /* XXX Before initialization, readable_pool depends on length. */
+- int avail = readable_pool (POOLSIZE/2, level);
+-
+- if (avail != 0 || *type & SELECT_WRITE)
+- {
+- *type = (avail ? SELECT_READ : 0) | (*type & SELECT_WRITE);
+- pthread_mutex_unlock (&global_lock);
+- return 0;
+- }
+-
+- ports_interrupt_self_on_port_death (cred, reply);
+- read_blocked = 1;
+-
+- if (pthread_hurd_cond_wait_np (&select_alert, &global_lock))
+- {
+- *type = 0;
+- pthread_mutex_unlock (&global_lock);
+- return EINTR;
+- }
+- }
+-}
+-
+-
+-/* Change current read/write offset */
+-error_t
+-trivfs_S_io_seek (struct trivfs_protid *cred,
+- mach_port_t reply, mach_msg_type_name_t reply_type,
+- loff_t offs, int whence, loff_t *new_offs)
+-{
+- if (! cred)
+- return EOPNOTSUPP;
+-
+- /* Not seekable. */
+- return ESPIPE;
+-}
+-
+-/* Change the size of the file. If the size increases, new blocks are
+- zero-filled. After successful return, it is safe to reference mapped
+- areas of the file up to NEW_SIZE. */
+-error_t
+-trivfs_S_file_set_size (struct trivfs_protid *cred,
+- mach_port_t reply, mach_msg_type_name_t reply_type,
+- loff_t size)
+-{
+- if (!cred)
+- return EOPNOTSUPP;
+-
+- return size == 0 ? 0 : EINVAL;
+-}
+-
+-/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
+- O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
+- will tell you which of O_READ, O_WRITE, and O_EXEC the object can
+- be used for. The O_ASYNC bit affects icky async I/O; good async
+- I/O is done through io_async which is orthogonal to these calls. */
+-error_t
+-trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
+- mach_port_t reply,
+- mach_msg_type_name_t reply_type,
+- int mode)
+-{
+- if (!cred)
+- return EOPNOTSUPP;
+-
+- return 0;
+-}
+-
+-error_t
+-trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
+- mach_port_t reply,
+- mach_msg_type_name_t reply_type,
+- int bits)
+-{
+- if (!cred)
+- return EOPNOTSUPP;
+-
+- return 0;
+-}
+-
+-error_t
+-trivfs_S_io_get_owner (struct trivfs_protid *cred,
+- mach_port_t reply,
+- mach_msg_type_name_t reply_type,
+- pid_t *owner)
+-{
+- if (!cred)
+- return EOPNOTSUPP;
+-
+- *owner = 0;
+- return 0;
+-}
+-
+-error_t
+-trivfs_S_io_mod_owner (struct trivfs_protid *cred,
+- mach_port_t reply, mach_msg_type_name_t reply_type,
+- pid_t owner)
+-{
+- if (!cred)
+- return EOPNOTSUPP;
+-
+- return EINVAL;
+-}
+-
+-/* Return objects mapping the data underlying this memory object. If
+- the object can be read then memobjrd will be provided; if the
+- object can be written then memobjwr will be provided. For objects
+- where read data and write data are the same, these objects will be
+- equal, otherwise they will be disjoint. Servers are permitted to
+- implement io_map but not io_map_cntl. Some objects do not provide
+- mapping; they will set none of the ports and return an error. Such
+- objects can still be accessed by io_read and io_write. */
+-error_t
+-trivfs_S_io_map(struct trivfs_protid *cred,
+- mach_port_t reply, mach_msg_type_name_t reply_type,
+- mach_port_t *rdobj,
+- mach_msg_type_name_t *rdtype,
+- mach_port_t *wrobj,
+- mach_msg_type_name_t *wrtype)
+-{
+- if (!cred)
+- return EOPNOTSUPP;
+-
+- return EINVAL;
+-}
+-
+-
+-int
+-random_demuxer (mach_msg_header_t *inp,
+- mach_msg_header_t *outp)
+-{
+- extern int startup_notify_server (mach_msg_header_t *, mach_msg_header_t *);
+-
+- return (trivfs_demuxer (inp, outp)
+- || startup_notify_server (inp, outp));
+-}
+-
+-
+-/* Options processing. We accept the same options on the command line
+- and from fsys_set_options. */
+-
+-static const struct argp_option options[] =
+-{
+- {"weak", 'w', 0, 0, "Output weak pseudo random data"},
+- {"fast", 'f', 0, 0, "Output cheap random data fast"},
+- {"secure", 's', 0, 0, "Output cryptographically secure random"},
+- {"seed-file", 'S', "FILE", 0, "Use FILE to remember the seed"},
+- {0}
+-};
+-
+-static error_t
+-parse_opt (int opt, char *arg, struct argp_state *state)
+-{
+- switch (opt)
+- {
+- default:
+- return ARGP_ERR_UNKNOWN;
+- case ARGP_KEY_INIT:
+- case ARGP_KEY_SUCCESS:
+- case ARGP_KEY_ERROR:
+- break;
+-
+- case 'w':
+- {
+- level = 0;
+- break;
+- }
+- case 'f':
+- {
+- level = 1;
+- break;
+- }
+- case 's':
+- {
+- level = 2;
+- break;
+- }
+- case 'S':
+- {
+- seed_file = strdup (arg);
+- set_random_seed_file (arg);
+- }
+- }
+- return 0;
+-}
+-
+-/* This will be called from libtrivfs to help construct the answer
+- to an fsys_get_options RPC. */
+-error_t
+-trivfs_append_args (struct trivfs_control *fsys,
+- char **argz, size_t *argz_len)
+-{
+- error_t err = 0;
+- char *opt;
+-
+- pthread_mutex_lock (&global_lock);
+- switch (level)
+- {
+- case 0:
+- opt = "--weak";
+- break;
+-
+- case 1:
+- opt = "--fast";
+- break;
+-
+- default:
+- opt = "--secure";
+- }
+- if (level != DEFAULT_LEVEL)
+- err = argz_add (argz, argz_len, opt);
+-
+- if (!err && seed_file)
+- {
+- if (asprintf (&opt, "--seed-file=%s", seed_file) < 0)
+- err = ENOMEM;
+- else
+- {
+- err = argz_add (argz, argz_len, opt);
+- free (opt);
+- }
+- }
+- pthread_mutex_unlock (&global_lock);
+-
+- return err;
+-}
+-
+-static struct argp random_argp =
+-{ options, parse_opt, 0,
+- "A translator providing random output." };
+-
+-/* Setting this variable makes libtrivfs use our argp to
+- parse options passed in an fsys_set_options RPC. */
+-struct argp *trivfs_runtime_argp = &random_argp;
+-
+-struct port_class *shutdown_notify_class;
+-
+-/* The system is going down; destroy all the extant port rights. That
+- will cause net channels and such to close promptly. */
+-error_t
+-S_startup_dosync (mach_port_t handle)
+-{
+- struct port_info *inpi = ports_lookup_port (fsys->pi.bucket, handle,
+- shutdown_notify_class);
+-
+- if (!inpi)
+- return EOPNOTSUPP;
+-
+- update_random_seed_file ();
+- return 0;
+-}
+-
+-void
+-sigterm_handler (int signo)
+-{
+- update_random_seed_file ();
+- signal (SIGTERM, SIG_DFL);
+- raise (SIGTERM);
+-}
+-
+-static error_t
+-arrange_shutdown_notification ()
+-{
+- error_t err;
+- mach_port_t initport, notify;
+- struct port_info *pi;
+-
+- shutdown_notify_class = ports_create_class (0, 0);
+-
+- signal (SIGTERM, sigterm_handler);
+-
+- /* Arrange to get notified when the system goes down,
+- but if we fail for some reason, just silently give up. No big deal. */
+-
+- err = ports_create_port (shutdown_notify_class, fsys->pi.bucket,
+- sizeof (struct port_info), &pi);
+- if (err)
+- return err;
+-
+- initport = file_name_lookup (_SERVERS_STARTUP, 0, 0);
+- if (! MACH_PORT_VALID (initport))
+- return errno;
+-
+- notify = ports_get_send_right (pi);
+- ports_port_deref (pi);
+- err = startup_request_notification (initport, notify,
+- MACH_MSG_TYPE_MAKE_SEND,
+- program_invocation_short_name);
+-
+- mach_port_deallocate (mach_task_self (), notify);
+- mach_port_deallocate (mach_task_self (), initport);
+- return err;
+-}
+-
+-
+-int
+-main (int argc, char **argv)
+-{
+- error_t err;
+- mach_port_t bootstrap;
+-
+- /* Initialize the lock that will protect everything.
+- We must do this before argp_parse, because parse_opt (above) will
+- use the lock. */
+- pthread_mutex_init (&global_lock, NULL);
+-
+- /* The conditions are used to implement proper read/select
+- behaviour. */
+- pthread_cond_init (&wait, NULL);
+- pthread_cond_init (&select_alert, NULL);
+-
+- /* We use the same argp for options available at startup
+- as for options we'll accept in an fsys_set_options RPC. */
+- argp_parse (&random_argp, argc, argv, 0, 0, 0);
+-
+- task_get_bootstrap_port (mach_task_self (), &bootstrap);
+- if (bootstrap == MACH_PORT_NULL)
+- error (1, 0, "Must be started as a translator");
+-
+- /* Reply to our parent */
+- err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
+- mach_port_deallocate (mach_task_self (), bootstrap);
+- if (err)
+- error (3, err, "trivfs_startup");
+-
+- err = arrange_shutdown_notification ();
+- if (err)
+- error (0, err, "Cannot request shutdown notification");
+-
+- /* Launch. */
+- ports_manage_port_operations_multithread (fsys->pi.bucket, random_demuxer,
+- 10 * 1000, /* idle thread */
+- 10 * 60 * 1000, /* idle server */
+- 0);
+- return 0;
+-}
+diff --git a/random/random.h b/random/random.h
+deleted file mode 100644
+index a38a417..0000000
+--- a/random/random.h
++++ /dev/null
+@@ -1,32 +0,0 @@
+-/* random.c - A single-file translator providing random data
+- Copyright (C) 1998, 1999, 2001 Free Software Foundation, Inc.
+-
+- This program is free software; you can redistribute it and/or
+- modify it under the terms of the GNU General Public License as
+- published by the Free Software Foundation; either version 2, or (at
+- your option) any later version.
+-
+- This program is distributed in the hope that it will be useful, but
+- WITHOUT ANY WARRANTY; without even the implied warranty of
+- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- General Public License for more details.
+-
+- You should have received a copy of the GNU General Public License
+- along with this program; if not, write to the Free Software
+- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+-
+-#ifndef __RANDOM_H__
+-#define __RANDOM_H__
+-
+-/* How many random bytes to gather at most.
+- XXX: Should be at least POOLSIZE. */
+-#define GATHERBUFSIZE 32768
+-
+-/* The random bytes we collected. */
+-extern char gatherbuf[GATHERBUFSIZE];
+-
+-/* The current positions in gatherbuf[]. */
+-extern int gatherrpos;
+-extern int gatherwpos;
+-
+-#endif
+diff --git a/sutils/MAKEDEV.sh b/sutils/MAKEDEV.sh
+index 1baec15..9fd4b1d 100644
+--- a/sutils/MAKEDEV.sh
++++ b/sutils/MAKEDEV.sh
+@@ -100,7 +100,7 @@ mkdev() {
+ ;;
+
+ std)
+- mkdev console tty urandom null zero full fd time mem klog shm
++ mkdev console tty random urandom null zero full fd time mem klog shm
+ ;;
+ console|com[0-9])
+ st $I root 600 /hurd/term ${DEVDIR}/$I device $I;;
+@@ -111,8 +111,10 @@ mkdev() {
+ ${DEVDIR}/vcs/`echo $I | sed -e s/tty//`/console;;
+ lpr[0-9])
+ st $I root 660 /hurd/streamio "$I";;
++ random)
++ st $I root 644 /hurd/random --secure --seed-file /var/lib/random-seed;;
+ urandom)
+- st $I root 644 /hurd/random --fast --seed-file /var/lib/random-seed;;
++ st $I root 644 /hurd/random --fast --seed-file /var/lib/urandom-seed;;
+ null)
+ st $I root 666 /hurd/null;;
+ full)
+diff --git a/trans/Makefile b/trans/Makefile
+index ce1eae7..ec0586e 100644
+--- a/trans/Makefile
++++ b/trans/Makefile
+@@ -21,14 +21,14 @@ makemode := servers
+
+ targets = symlink firmlink ifsock magic null fifo new-fifo fwd crash \
+ password hello hello-mt streamio fakeroot proxy-defpager remap \
+- mtab
++ mtab random
+ SRCS = ifsock.c symlink.c magic.c null.c fifo.c new-fifo.c fwd.c \
+ crash.c firmlink.c password.c hello.c hello-mt.c streamio.c \
+ fakeroot.c proxy-defpager.c remap.c mtab.c
+ OBJS = $(SRCS:.c=.o) fsysServer.o ifsockServer.o passwordServer.o \
+ crashServer.o crash_replyUser.o msgServer.o \
+ default_pagerServer.o default_pagerUser.o \
+- device_replyServer.o elfcore.o
++ device_replyServer.o elfcore.o startup_notifyServer.o
+ HURDLIBS = ports netfs trivfs iohelp fshelp pipe ihash shouldbeinlibc
+ LDLIBS += -lpthread
+ password-LDLIBS = -lcrypt
+@@ -51,6 +51,8 @@ device_reply-MIGSFLAGS="-DMACH_PAYLOAD_TO_PORT=ports_payload_get_name"
+ # libports. Disable the default payload to port conversion.
+ fsys-MIGSFLAGS = "-DHURD_DEFAULT_PAYLOAD_TO_PORT=1"
+
++random-LDLIBS = -lgcrypt
++
+ include ../Makeconf
+
+ vpath elfcore.c $(top_srcdir)/exec
+@@ -71,6 +73,7 @@ hello: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a
+ fakeroot: ../libnetfs/libnetfs.a ../libfshelp/libfshelp.a ../libiohelp/libiohelp.a ../libports/libports.a ../libihash/libihash.a
+ remap: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a
+ mtab: ../libtrivfs/libtrivfs.a ../libfshelp/libfshelp.a ../libports/libports.a ../libihash/libihash.a fsUser.o
++random: ../libtrivfs/libtrivfs.a ../libports/libports.a ../libihash/libihash.a startup_notifyServer.o mach_debugUser.o
+ $(targets): ../libshouldbeinlibc/libshouldbeinlibc.a
+
+ $(targets): %: %.o
+diff --git a/trans/random.c b/trans/random.c
+new file mode 100644
+index 0000000..83f0579
+--- /dev/null
++++ b/trans/random.c
+@@ -0,0 +1,682 @@
++/* random.c - A single-file translator providing random data
++ Copyright (C) 1998, 1999, 2001, 2015 Free Software Foundation, Inc.
++
++ This program is free software; you can redistribute it and/or
++ modify it under the terms of the GNU General Public License as
++ published by the Free Software Foundation; either version 2, or (at
++ your option) any later version.
++
++ This program is distributed in the hope that it will be useful, but
++ WITHOUT ANY WARRANTY; without even the implied warranty of
++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ General Public License for more details.
++
++ You should have received a copy of the GNU General Public License
++ along with this program; if not, write to the Free Software
++ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
++
++#include <argp.h>
++#include <argz.h>
++#include <assert.h>
++#include <error.h>
++#include <fcntl.h>
++#include <gcrypt.h>
++#include <hurd/paths.h>
++#include <hurd/startup.h>
++#include <hurd/trivfs.h>
++#include <mach_debug/mach_debug_types.h>
++#include <pthread.h>
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <sys/mman.h>
++#include <sys/stat.h>
++#include <unistd.h>
++#include <version.h>
++
++#include "mach_debug_U.h"
++
++/* Our control port. */
++struct trivfs_control *fsys;
++
++int read_blocked; /* For read and select. */
++pthread_cond_t wait; /* For read and select. */
++pthread_cond_t select_alert; /* For read and select. */
++
++/* The quality of randomness we provide. If URANDOM is set, return
++ unlimited random data. */
++static int urandom;
++
++/* Name of file to use as seed. */
++static char *seed_file;
++
++/* Entropy management. */
++
++/* Estimate of available entropy measured in bytes. */
++static size_t entropy;
++
++/* Protected by this lock. */
++static pthread_mutex_t entropy_lock;
++
++static error_t
++entropy_add (const void *buf, size_t length, float factor)
++{
++ gcry_error_t cerr;
++ size_t new_entropy;
++ pthread_mutex_lock (&entropy_lock);
++
++ cerr = gcry_random_add_bytes (buf, length, -1);
++ if (cerr)
++ {
++ pthread_mutex_unlock (&entropy_lock);
++ error (0, 0, "Failed to add random bytes: %s",
++ gcry_strerror (cerr));
++ return EINVAL;
++ }
++ new_entropy = (size_t) ((float) length * factor);
++ entropy += new_entropy;
++
++ if (new_entropy > 0 && read_blocked)
++ {
++ read_blocked = 0;
++ pthread_cond_broadcast (&wait);
++ pthread_cond_broadcast (&select_alert);
++ }
++
++ pthread_mutex_unlock (&entropy_lock);
++ return 0;
++}
++
++static void
++update_random_seed_file (void)
++{
++ gcry_error_t cerr;
++ cerr = gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE, seed_file, 0);
++ if (cerr)
++ error (0, 0, "Updating random seed file %s failed: %s",
++ seed_file, gcry_strerror (cerr));
++}
++
++static void
++initialize_gcrypt (void)
++{
++ gcry_error_t cerr;
++ struct stat s;
++
++ if (! gcry_check_version (GCRYPT_VERSION))
++ error (1, 0, "libgcrypt version mismatch\n");
++
++ cerr = gcry_control (GCRYCTL_SET_PREFERRED_RNG_TYPE,
++ GCRY_RNG_TYPE_STANDARD, 0);
++ if (cerr)
++ error (1, 0, "Selecting preferred rng type failed: %s",
++ gcry_strerror (cerr));
++
++ cerr = gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, seed_file, 0);
++ if (cerr)
++ error (1, 0, "Setting seed file %s failed: %s",
++ seed_file, gcry_strerror (cerr));
++
++ cerr = gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
++ if (cerr)
++ error (1, 0, "Finalizing gcrypt failed: %s",
++ gcry_strerror (cerr));
++
++ if (stat (seed_file, &s) == 0)
++ /* Libgcrypt will read the seed file on demand. Set entropy
++ accordingly. */
++ entropy = s.st_size;
++}
++
++static void
++gather_slab_info (void)
++{
++ error_t err;
++ cache_info_array_t cache_info;
++ mach_msg_type_number_t cache_info_count, i;
++
++ cache_info = NULL;
++ cache_info_count = 0;
++
++ err = host_slab_info (mach_host_self(), &cache_info, &cache_info_count);
++ if (err)
++ {
++ error (0, err, "host_slab_info");
++ return;
++ }
++
++ for (i = 0; i < cache_info_count; i++)
++ if (cache_info[i].nr_bufs > 500)
++ entropy_add (&cache_info[i].nr_objs, sizeof cache_info[i].nr_objs,
++ 0.25);
++
++ vm_deallocate (mach_task_self (),
++ (vm_address_t) cache_info,
++ cache_info_count * sizeof *cache_info);
++}
++
++static void *
++gather_thread (void *args)
++{
++ while (1)
++ {
++ gather_slab_info ();
++ sleep (1); /* XXX vary sleep time */
++ }
++
++ assert (! "reached");
++}
++
++error_t
++start_gather_thread (void)
++{
++ error_t err;
++ pthread_t thread;
++
++ err = pthread_create (&thread, NULL, gather_thread, NULL);
++ if (err)
++ return err;
++
++ err = pthread_detach (thread);
++ return err;
++}
++
++const char *argp_program_version = STANDARD_HURD_VERSION (random);
++
++/* Trivfs hooks. */
++int trivfs_fstype = FSTYPE_MISC;
++int trivfs_fsid = 0;
++
++int trivfs_allow_open = O_READ | O_WRITE;
++
++int trivfs_support_read = 1;
++int trivfs_support_write = 1;
++int trivfs_support_exec = 0;
++
++void
++trivfs_modify_stat (struct trivfs_protid *cred, struct stat *st)
++{
++ /* Mark the node as a read-only plain file. */
++ st->st_mode &= ~((unsigned) S_IFMT);
++ st->st_mode |= (S_IFCHR);
++ st->st_size = 0;
++}
++
++error_t
++trivfs_goaway (struct trivfs_control *cntl, int flags)
++{
++ update_random_seed_file ();
++ exit (0);
++}
++
++/* Read data from an IO object. If offset is -1, read from the object
++ maintained file pointer. If the object is not seekable, offset is
++ ignored. The amount desired to be read is in AMOUNT. */
++error_t
++trivfs_S_io_read (struct trivfs_protid *cred,
++ mach_port_t reply, mach_msg_type_name_t reply_type,
++ data_t *data, mach_msg_type_number_t *data_len,
++ loff_t offs, mach_msg_type_number_t amount)
++{
++ error_t err;
++ void *buf = NULL;
++ size_t length = 0;
++
++ if (! cred)
++ return EOPNOTSUPP;
++ else if (! (cred->po->openmodes & O_READ))
++ return EBADF;
++
++ pthread_mutex_lock (&entropy_lock);
++
++ if (amount > 0)
++ {
++ while (! urandom && amount > entropy)
++ {
++ if (cred->po->openmodes & O_NONBLOCK)
++ {
++ err = EWOULDBLOCK;
++ goto errout;
++ }
++ read_blocked = 1;
++ if (pthread_hurd_cond_wait_np (&wait, &entropy_lock))
++ {
++ err = EINTR;
++ goto errout;
++ }
++ /* See term/users.c for possible race? */
++ }
++
++ /* Possibly allocate a new buffer. */
++ if (*data_len < amount)
++ {
++ *data = mmap (0, amount, PROT_READ|PROT_WRITE,
++ MAP_ANON, 0, 0);
++
++ if (*data == MAP_FAILED)
++ {
++ pthread_mutex_unlock (&entropy_lock);
++ return errno;
++ }
++
++ /* Keep track of our map in case of errors. */
++ buf = *data, length = amount;
++
++ /* Update DATA_LEN to reflect the new buffers size. */
++ *data_len = amount;
++ }
++
++ if (! urandom)
++ assert (entropy >= amount);
++ else if (entropy >= amount)
++ entropy -= amount;
++ else
++ entropy = 0;
++
++ gcry_randomize ((unsigned char *) *data, amount, GCRY_STRONG_RANDOM);
++ }
++
++ /* Set atime, see term/users.c */
++
++ pthread_mutex_unlock (&entropy_lock);
++ *data_len = amount;
++ return 0;
++
++ errout:
++ pthread_mutex_unlock (&entropy_lock);
++ if (buf)
++ munmap (buf, length);
++ return err;
++}
++
++/* Write data to an IO object. If offset is -1, write at the object
++ maintained file pointer. If the object is not seekable, offset is
++ ignored. The amount successfully written is returned in amount. A
++ given user should not have more than one outstanding io_write on an
++ object at a time; servers implement congestion control by delaying
++ responses to io_write. Servers may drop data (returning ENOBUFS)
++ if they receive more than one write when not prepared for it. */
++error_t
++trivfs_S_io_write (struct trivfs_protid *cred,
++ mach_port_t reply,
++ mach_msg_type_name_t replytype,
++ data_t data,
++ mach_msg_type_number_t datalen,
++ loff_t offset,
++ mach_msg_type_number_t *amount)
++{
++ error_t err;
++
++ /* Deny access if they have bad credentials. */
++ if (! cred)
++ return EOPNOTSUPP;
++ else if (! (cred->po->openmodes & O_WRITE))
++ return EBADF;
++
++ err = entropy_add (data, datalen, 0);
++ *amount = datalen;
++ return err;
++}
++
++/* Tell how much data can be read from the object without blocking for
++ a "long time" (this should be the same meaning of "long time" used
++ by the nonblocking flag. */
++kern_return_t
++trivfs_S_io_readable (struct trivfs_protid *cred,
++ mach_port_t reply, mach_msg_type_name_t replytype,
++ mach_msg_type_number_t *amount)
++{
++ /* Deny access if they have bad credentials. */
++ if (! cred)
++ return EOPNOTSUPP;
++ else if (! (cred->po->openmodes & O_READ))
++ return EBADF;
++
++ pthread_mutex_lock (&entropy_lock);
++
++ *amount = entropy;
++
++ pthread_mutex_unlock (&entropy_lock);
++
++ return 0;
++}
++
++/* SELECT_TYPE is the bitwise OR of SELECT_READ, SELECT_WRITE, and SELECT_URG.
++ Block until one of the indicated types of i/o can be done "quickly", and
++ return the types that are then available. ID_TAG is returned as passed; it
++ is just for the convenience of the user in matching up reply messages with
++ specific requests sent. */
++error_t
++trivfs_S_io_select (struct trivfs_protid *cred,
++ mach_port_t reply,
++ mach_msg_type_name_t reply_type,
++ int *type)
++{
++ if (!cred)
++ return EOPNOTSUPP;
++
++ /* We only deal with SELECT_READ and SELECT_WRITE here. */
++ if (*type & ~(SELECT_READ | SELECT_WRITE))
++ return EINVAL;
++
++ if (*type == 0)
++ return 0;
++
++ pthread_mutex_lock (&entropy_lock);
++
++ while (1)
++ {
++ if (entropy > 0 || *type & SELECT_WRITE)
++ {
++ *type = (entropy > 0 ? SELECT_READ : 0) | (*type & SELECT_WRITE);
++ pthread_mutex_unlock (&entropy_lock);
++ return 0;
++ }
++
++ ports_interrupt_self_on_port_death (cred, reply);
++ read_blocked = 1;
++
++ if (pthread_hurd_cond_wait_np (&select_alert, &entropy_lock))
++ {
++ *type = 0;
++ pthread_mutex_unlock (&entropy_lock);
++ return EINTR;
++ }
++ }
++}
++
++
++/* Change current read/write offset */
++error_t
++trivfs_S_io_seek (struct trivfs_protid *cred,
++ mach_port_t reply, mach_msg_type_name_t reply_type,
++ loff_t offs, int whence, loff_t *new_offs)
++{
++ if (! cred)
++ return EOPNOTSUPP;
++
++ /* Not seekable. */
++ return ESPIPE;
++}
++
++/* Change the size of the file. If the size increases, new blocks are
++ zero-filled. After successful return, it is safe to reference mapped
++ areas of the file up to NEW_SIZE. */
++error_t
++trivfs_S_file_set_size (struct trivfs_protid *cred,
++ mach_port_t reply, mach_msg_type_name_t reply_type,
++ loff_t size)
++{
++ if (!cred)
++ return EOPNOTSUPP;
++
++ return size == 0 ? 0 : EINVAL;
++}
++
++/* These four routines modify the O_APPEND, O_ASYNC, O_FSYNC, and
++ O_NONBLOCK bits for the IO object. In addition, io_get_openmodes
++ will tell you which of O_READ, O_WRITE, and O_EXEC the object can
++ be used for. The O_ASYNC bit affects icky async I/O; good async
++ I/O is done through io_async which is orthogonal to these calls. */
++error_t
++trivfs_S_io_set_all_openmodes(struct trivfs_protid *cred,
++ mach_port_t reply,
++ mach_msg_type_name_t reply_type,
++ int mode)
++{
++ if (!cred)
++ return EOPNOTSUPP;
++
++ return 0;
++}
++
++error_t
++trivfs_S_io_set_some_openmodes (struct trivfs_protid *cred,
++ mach_port_t reply,
++ mach_msg_type_name_t reply_type,
++ int bits)
++{
++ if (!cred)
++ return EOPNOTSUPP;
++
++ return 0;
++}
++
++error_t
++trivfs_S_io_get_owner (struct trivfs_protid *cred,
++ mach_port_t reply,
++ mach_msg_type_name_t reply_type,
++ pid_t *owner)
++{
++ if (!cred)
++ return EOPNOTSUPP;
++
++ *owner = 0;
++ return 0;
++}
++
++error_t
++trivfs_S_io_mod_owner (struct trivfs_protid *cred,
++ mach_port_t reply, mach_msg_type_name_t reply_type,
++ pid_t owner)
++{
++ if (!cred)
++ return EOPNOTSUPP;
++
++ return EINVAL;
++}
++
++/* Return objects mapping the data underlying this memory object. If
++ the object can be read then memobjrd will be provided; if the
++ object can be written then memobjwr will be provided. For objects
++ where read data and write data are the same, these objects will be
++ equal, otherwise they will be disjoint. Servers are permitted to
++ implement io_map but not io_map_cntl. Some objects do not provide
++ mapping; they will set none of the ports and return an error. Such
++ objects can still be accessed by io_read and io_write. */
++error_t
++trivfs_S_io_map(struct trivfs_protid *cred,
++ mach_port_t reply, mach_msg_type_name_t reply_type,
++ mach_port_t *rdobj,
++ mach_msg_type_name_t *rdtype,
++ mach_port_t *wrobj,
++ mach_msg_type_name_t *wrtype)
++{
++ if (!cred)
++ return EOPNOTSUPP;
++
++ return EINVAL;
++}
++
++
++int
++random_demuxer (mach_msg_header_t *inp,
++ mach_msg_header_t *outp)
++{
++ extern int startup_notify_server (mach_msg_header_t *, mach_msg_header_t *);
++
++ return (trivfs_demuxer (inp, outp)
++ || startup_notify_server (inp, outp));
++}
++
++
++/* Options processing. We accept the same options on the command line
++ and from fsys_set_options. */
++
++static const struct argp_option options[] =
++{
++ {"fast", 'f', 0, 0, "Output cheap random data fast"},
++ {"secure", 's', 0, 0,
++ "Output cryptographically secure random (the default)"},
++ {"seed-file", 'S', "FILE", 0, "Use FILE to remember the seed"},
++ {0}
++};
++
++static error_t
++parse_opt (int opt, char *arg, struct argp_state *state)
++{
++ switch (opt)
++ {
++ default:
++ return ARGP_ERR_UNKNOWN;
++ case ARGP_KEY_INIT:
++ case ARGP_KEY_SUCCESS:
++ case ARGP_KEY_ERROR:
++ break;
++
++ case 'f':
++ urandom = 1;
++ break;
++
++ case 's':
++ urandom = 0;
++ break;
++
++ case 'S':
++ seed_file = strdup (arg);
++ break;
++ }
++ return 0;
++}
++
++/* This will be called from libtrivfs to help construct the answer
++ to an fsys_get_options RPC. */
++error_t
++trivfs_append_args (struct trivfs_control *fsys,
++ char **argz, size_t *argz_len)
++{
++ error_t err = 0;
++ char *opt;
++
++ err = argz_add (argz, argz_len, urandom ? "--fast" : "--secure");
++ if (err)
++ return err;
++
++ if (seed_file)
++ {
++ if (asprintf (&opt, "--seed-file=%s", seed_file) < 0)
++ err = ENOMEM;
++ else
++ {
++ err = argz_add (argz, argz_len, opt);
++ free (opt);
++ }
++ }
++
++ return err;
++}
++
++static struct argp random_argp =
++{ options, parse_opt, 0,
++ "A translator providing random output." };
++
++/* Setting this variable makes libtrivfs use our argp to
++ parse options passed in an fsys_set_options RPC. */
++struct argp *trivfs_runtime_argp = &random_argp;
++
++struct port_class *shutdown_notify_class;
++
++/* The system is going down; destroy all the extant port rights. That
++ will cause net channels and such to close promptly. */
++error_t
++S_startup_dosync (mach_port_t handle)
++{
++ struct port_info *inpi = ports_lookup_port (fsys->pi.bucket, handle,
++ shutdown_notify_class);
++
++ if (!inpi)
++ return EOPNOTSUPP;
++
++ update_random_seed_file ();
++ return 0;
++}
++
++void
++sigterm_handler (int signo)
++{
++ update_random_seed_file ();
++ signal (SIGTERM, SIG_DFL);
++ raise (SIGTERM);
++}
++
++static error_t
++arrange_shutdown_notification ()
++{
++ error_t err;
++ mach_port_t initport, notify;
++ struct port_info *pi;
++
++ shutdown_notify_class = ports_create_class (0, 0);
++
++ signal (SIGTERM, sigterm_handler);
++
++ /* Arrange to get notified when the system goes down,
++ but if we fail for some reason, just silently give up. No big deal. */
++
++ err = ports_create_port (shutdown_notify_class, fsys->pi.bucket,
++ sizeof (struct port_info), &pi);
++ if (err)
++ return err;
++
++ initport = file_name_lookup (_SERVERS_STARTUP, 0, 0);
++ if (! MACH_PORT_VALID (initport))
++ return errno;
++
++ notify = ports_get_send_right (pi);
++ ports_port_deref (pi);
++ err = startup_request_notification (initport, notify,
++ MACH_MSG_TYPE_MAKE_SEND,
++ program_invocation_short_name);
++
++ mach_port_deallocate (mach_task_self (), notify);
++ mach_port_deallocate (mach_task_self (), initport);
++ return err;
++}
++
++int
++main (int argc, char **argv)
++{
++ error_t err;
++ mach_port_t bootstrap;
++
++ /* Initialize the lock that will protect everything.
++ We must do this before argp_parse, because parse_opt (above) will
++ use the lock. */
++ pthread_mutex_init (&entropy_lock, NULL);
++
++ /* The conditions are used to implement proper read/select
++ behaviour. */
++ pthread_cond_init (&wait, NULL);
++ pthread_cond_init (&select_alert, NULL);
++
++ /* We use the same argp for options available at startup
++ as for options we'll accept in an fsys_set_options RPC. */
++ argp_parse (&random_argp, argc, argv, 0, 0, 0);
++
++ initialize_gcrypt ();
++
++ task_get_bootstrap_port (mach_task_self (), &bootstrap);
++ if (bootstrap == MACH_PORT_NULL)
++ error (1, 0, "Must be started as a translator");
++
++ /* Reply to our parent */
++ err = trivfs_startup (bootstrap, 0, 0, 0, 0, 0, &fsys);
++ mach_port_deallocate (mach_task_self (), bootstrap);
++ if (err)
++ error (3, err, "trivfs_startup");
++
++ err = arrange_shutdown_notification ();
++ if (err)
++ error (0, err, "Cannot request shutdown notification");
++
++ err = start_gather_thread ();
++ if (err)
++ error (0, err, "Starting gatherer thread failed");
++
++ /* Launch. */
++ ports_manage_port_operations_multithread (fsys->pi.bucket, random_demuxer,
++ 10 * 1000, /* idle thread */
++ 10 * 60 * 1000, /* idle server */
++ 0);
++ return 0;
++}
+--
+2.1.4
+
diff --git a/debian/patches/series b/debian/patches/series
index d429eedf..0b645778 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -67,3 +67,4 @@ translators-list0001-libfshelp-acquire-references-to-control-ports.patch
translators-list0002-fu.patch
translators-list0003-libfshelp-improve-translator-list.patch
translators-list0004-add-iteration.patch
+random0001-xxx-standalone-random-translator.patch