From c12e4a9db255f2d7eaf86abae4f8dea0d4bb76ab 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 | 722 +++++++++++++++++++++++++++++++++++++++++++ 14 files changed, 731 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 -#include - -#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 -#else -#include "gnupg-glue.h" -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_GETHRTIME - #include -#endif -#ifdef HAVE_GETTIMEOFDAY - #include -#endif -#ifdef HAVE_GETRUSAGE - #include -#endif -#ifdef __MINGW32__ - #include -#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 -#endif -#include -#include -#include -#include -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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..0419912 --- /dev/null +++ b/trans/random.c @@ -0,0 +1,722 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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. */ + +/* Libgcrypts pool size limits the amount of entropy. */ +static const size_t entropy_limit = 600; + +/* 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 (entropy > entropy_limit) + entropy = entropy_limit; + + 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) +{ + unsigned int seed; + gcry_error_t cerr; + + 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)); + + if (seed_file) + { + struct stat s; + + /* Hack! XXX use relative path */ + if (seed_file[0] == '/') + { + chdir ("/"); + seed_file += 1; + } + + 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)); + + if (stat (seed_file, &s) == 0) + /* Libgcrypt will read the seed file on demand. Set entropy + accordingly. */ + entropy = s.st_size; + } + + cerr = gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + if (cerr) + error (1, 0, "Finalizing gcrypt failed: %s", + gcry_strerror (cerr)); + + /* Hack! Trick libgcrypt into assuming /dev/urandom is not + available by diddling with the root directory. */ + { + file_t root, var; + root = getcrdir (); + var = file_name_lookup ("/var", 0, 0); + setcrdir (var); + + /* Randomize SEED. Forces the random subsystem to be + initialized. */ + gcry_randomize (&seed, sizeof seed, GCRY_STRONG_RANDOM); + + setcrdir (root); + mach_port_deallocate (mach_task_self (), var); + } + + /* Initialize the libcs RNG. */ + srandom (seed); +} + +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 (); + usleep ( + (useconds_t) (1000000. * (1. + + (float) random () / (float) RAND_MAX))); + } + + 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); + + 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