about to release 1.4.3rc1
[gnupg.git] / cipher / random.c
1 /* random.c  -  random number generator
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3  *               2003, 2006 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20  * USA.
21  */
22
23
24 /****************
25  * This random number generator is modelled after the one described
26  * in Peter Gutmann's Paper: "Software Generation of Practically
27  * Strong Random Numbers".
28  */
29
30
31 #include <config.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <assert.h>
35 #include <errno.h>
36 #include <string.h>
37 #include <time.h>
38 #ifndef _WIN32
39 #include <sys/time.h>
40 #endif
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <unistd.h>
44 #include <fcntl.h>
45 #ifdef HAVE_GETHRTIME
46 #include <sys/times.h>
47 #endif
48 #ifdef HAVE_GETTIMEOFDAY
49 #include <sys/times.h>
50 #endif
51 #ifdef HAVE_TIMES
52 #include <sys/times.h>
53 #endif
54 #ifdef HAVE_GETRUSAGE
55 #include <sys/resource.h>
56 #endif
57 #ifdef _WIN32
58 #include <process.h>
59 #endif
60 #include "util.h"
61 #include "rmd.h"
62 #include "ttyio.h"
63 #include "i18n.h"
64 #include "random.h"
65 #include "rand-internal.h"
66 #include "algorithms.h"
67
68 #ifndef RAND_MAX   /* for SunOS */
69 #define RAND_MAX 32767
70 #endif
71
72
73 /* Check whether we can lock the seed file read write. */
74 #if defined(HAVE_FCNTL) && defined(HAVE_FTRUNCATE) && !defined(HAVE_W32_SYSTEM)
75 #define LOCK_SEED_FILE 1
76 #else
77 #define LOCK_SEED_FILE 0
78 #endif
79
80
81 #if SIZEOF_UNSIGNED_LONG == 8
82 #define ADD_VALUE 0xa5a5a5a5a5a5a5a5
83 #elif SIZEOF_UNSIGNED_LONG == 4
84 #define ADD_VALUE 0xa5a5a5a5
85 #else
86 #error weird size for an unsigned long
87 #endif
88
89 #define BLOCKLEN  64   /* hash this amount of bytes */
90 #define DIGESTLEN 20   /* into a digest of this length (rmd160) */
91 /* poolblocks is the number of digests which make up the pool
92  * and poolsize must be a multiple of the digest length
93  * to make the AND operations faster, the size should also be
94  * a multiple of ulong
95  */
96 #define POOLBLOCKS 30
97 #define POOLSIZE (POOLBLOCKS*DIGESTLEN)
98 #if (POOLSIZE % SIZEOF_UNSIGNED_LONG)
99 #error Please make sure that poolsize is a multiple of ulong
100 #endif
101 #define POOLWORDS (POOLSIZE / SIZEOF_UNSIGNED_LONG)
102
103
104 static int is_initialized;
105 #define MASK_LEVEL(a) do {if( a > 2 ) a = 2; else if( a < 0 ) a = 0; } while(0)
106 static char *rndpool;   /* allocated size is POOLSIZE+BLOCKLEN */
107 static char *keypool;   /* allocated size is POOLSIZE+BLOCKLEN */
108 static size_t pool_readpos;
109 static size_t pool_writepos;
110 static int pool_filled;
111 static int pool_balance;
112 static int just_mixed;
113 static int did_initial_extra_seeding;
114 static char *seed_file_name;
115 static int allow_seed_file_update;
116 static int no_seed_file_locking;
117
118 static int secure_alloc;
119 static int quick_test;
120 static int faked_rng;
121
122
123 static void read_pool( byte *buffer, size_t length, int level );
124 static void add_randomness( const void *buffer, size_t length, int source );
125 static void random_poll(void);
126 static void read_random_source( int requester, size_t length, int level);
127 static int gather_faked( void (*add)(const void*, size_t, int), int requester,
128                                                     size_t length, int level );
129
130 static struct {
131     ulong mixrnd;
132     ulong mixkey;
133     ulong slowpolls;
134     ulong fastpolls;
135     ulong getbytes1;
136     ulong ngetbytes1;
137     ulong getbytes2;
138     ulong ngetbytes2;
139     ulong addbytes;
140     ulong naddbytes;
141 } rndstats;
142
143
144 static int (*
145 getfnc_gather_random (void))(void (*)(const void*, size_t, int), int,
146                         size_t, int)
147 {
148 #ifdef USE_ALL_RANDOM_MODULES
149   static int (*fnc)(void (*)(const void*, size_t, int), int, size_t, int);
150   
151   if (fnc)
152     return fnc;
153 # ifdef USE_RNDLINUX
154   if ( !access (NAME_OF_DEV_RANDOM, R_OK)
155        && !access (NAME_OF_DEV_URANDOM, R_OK))
156     {
157       fnc = rndlinux_gather_random;
158       return fnc;
159     }
160 # endif
161 # ifdef USE_RNDEGD
162   if ( rndegd_connect_socket (1) != -1 )
163     {
164       fnc = rndegd_gather_random;
165       return fnc;
166     }
167 # endif
168 # ifdef USE_RNDUNIX
169   fnc = rndunix_gather_random;
170   return fnc;
171 # endif
172
173   log_fatal (_("no entropy gathering module detected\n"));
174
175 #else
176 # ifdef USE_RNDLINUX
177   return rndlinux_gather_random;
178 # endif
179 # ifdef USE_RNDUNIX
180   return rndunix_gather_random;
181 # endif
182 # ifdef USE_RNDEGD
183   return rndegd_gather_random;
184 # endif
185 # ifdef USE_RNDW32
186   return rndw32_gather_random;
187 # endif
188 # ifdef USE_RNDRISCOS
189   return rndriscos_gather_random;
190 # endif
191 #endif
192   return NULL;
193 }
194
195 static int (*
196 getfnc_fast_random_poll (void))( void (*)(const void*, size_t, int), int)
197 {
198 #ifdef USE_RNDW32
199   return rndw32_gather_random_fast;
200 #endif
201   return NULL;
202 }
203
204
205
206 static void
207 initialize(void)
208 {
209     /* The data buffer is allocated somewhat larger, so that
210      * we can use this extra space (which is allocated in secure memory)
211      * as a temporary hash buffer */
212     rndpool = secure_alloc ? xmalloc_secure_clear(POOLSIZE+BLOCKLEN)
213                            : xmalloc_clear(POOLSIZE+BLOCKLEN);
214     keypool = secure_alloc ? xmalloc_secure_clear(POOLSIZE+BLOCKLEN)
215                            : xmalloc_clear(POOLSIZE+BLOCKLEN);
216     is_initialized = 1;
217 }
218
219 static void
220 burn_stack (int bytes)
221 {
222     char buf[128];
223     
224     wipememory(buf,sizeof buf);
225     bytes -= sizeof buf;
226     if (bytes > 0)
227         burn_stack (bytes);
228 }
229
230 void
231 random_dump_stats()
232 {
233     fprintf(stderr,
234             "random usage: poolsize=%d mixed=%lu polls=%lu/%lu added=%lu/%lu\n"
235             "              outmix=%lu getlvl1=%lu/%lu getlvl2=%lu/%lu\n",
236         POOLSIZE, rndstats.mixrnd, rndstats.slowpolls, rndstats.fastpolls,
237                   rndstats.naddbytes, rndstats.addbytes,
238         rndstats.mixkey, rndstats.ngetbytes1, rndstats.getbytes1,
239                     rndstats.ngetbytes2, rndstats.getbytes2 );
240 }
241
242 void
243 secure_randoxmalloc()
244 {
245     secure_alloc = 1;
246 }
247
248
249 int
250 quick_random_gen( int onoff )
251 {
252     int last;
253
254     read_random_source(0,0,0); /* init */
255     last = quick_test;
256     if( onoff != -1 )
257         quick_test = onoff;
258     return faked_rng? 1 : last;
259 }
260
261
262 /****************
263  * Fill the buffer with LENGTH bytes of cryptographically strong
264  * random bytes. level 0 is not very strong, 1 is strong enough
265  * for most usage, 2 is good for key generation stuff but may be very slow.
266  */
267 void
268 randomize_buffer( byte *buffer, size_t length, int level )
269 {
270     char *p = get_random_bits( length*8, level, 1 );
271     memcpy( buffer, p, length );
272     xfree(p);
273 }
274
275
276 int
277 random_is_faked()
278 {
279     if( !is_initialized )
280         initialize();
281     return faked_rng || quick_test;
282 }
283
284 /* Disable locking of seed files. */
285 void 
286 random_disable_locking ()
287 {
288   no_seed_file_locking = 1;
289 }
290
291 /****************
292  * Return a pointer to a randomized buffer of level 0 and LENGTH bits
293  * caller must free the buffer.
294  * Note: The returned value is rounded up to bytes.
295  */
296 byte *
297 get_random_bits( size_t nbits, int level, int secure )
298 {
299     byte *buf, *p;
300     size_t nbytes = (nbits+7)/8;
301
302     if( quick_test && level > 1 )
303         level = 1;
304     MASK_LEVEL(level);
305     if( level == 1 ) {
306         rndstats.getbytes1 += nbytes;
307         rndstats.ngetbytes1++;
308     }
309     else if( level >= 2 ) {
310         rndstats.getbytes2 += nbytes;
311         rndstats.ngetbytes2++;
312     }
313
314     buf = secure && secure_alloc ? xmalloc_secure( nbytes ) : xmalloc( nbytes );
315     for( p = buf; nbytes > 0; ) {
316         size_t n = nbytes > POOLSIZE? POOLSIZE : nbytes;
317         read_pool( p, n, level );
318         nbytes -= n;
319         p += n;
320     }
321     return buf;
322 }
323
324
325 /****************
326  * Mix the pool
327  */
328 static void
329 mix_pool(byte *pool)
330 {
331     char *hashbuf = pool + POOLSIZE;
332     char *p, *pend;
333     int i, n;
334     RMD160_CONTEXT md;
335
336     rmd160_init( &md );
337 #if DIGESTLEN != 20
338 #error must have a digest length of 20 for ripe-md-160
339 #endif
340     /* loop over the pool */
341     pend = pool + POOLSIZE;
342     memcpy(hashbuf, pend - DIGESTLEN, DIGESTLEN );
343     memcpy(hashbuf+DIGESTLEN, pool, BLOCKLEN-DIGESTLEN);
344     rmd160_mixblock( &md, hashbuf);
345     memcpy(pool, hashbuf, 20 );
346
347     p = pool;
348     for( n=1; n < POOLBLOCKS; n++ ) {
349         memcpy(hashbuf, p, DIGESTLEN );
350
351         p += DIGESTLEN;
352         if( p+DIGESTLEN+BLOCKLEN < pend )
353             memcpy(hashbuf+DIGESTLEN, p+DIGESTLEN, BLOCKLEN-DIGESTLEN);
354         else {
355             char *pp = p+DIGESTLEN;
356             for(i=DIGESTLEN; i < BLOCKLEN; i++ ) {
357                 if( pp >= pend )
358                     pp = pool;
359                 hashbuf[i] = *pp++;
360             }
361         }
362
363         rmd160_mixblock( &md, hashbuf);
364         memcpy(p, hashbuf, 20 );
365     }
366     burn_stack (384); /* for the rmd160_mixblock() */
367 }
368
369
370 void
371 set_random_seed_file( const char *name )
372 {
373     if( seed_file_name )
374         BUG();
375     seed_file_name = xstrdup( name );
376 }
377
378
379 /* Lock an open file identified by file descriptor FD and wait a
380    reasonable time to succeed.  With FOR_WRITE set to true a Rite lock
381    will be taken.  FNAME is used only for diagnostics. Returns 0 on
382    success or -1 on error. */
383 static int
384 lock_seed_file (int fd, const char *fname, int for_write)
385 {
386 #if LOCK_SEED_FILE
387   struct flock lck;
388   struct timeval tv;
389   int backoff=0;
390
391   if (no_seed_file_locking)
392     return 0;
393   
394   /* We take a lock on the entire file. */
395   memset (&lck, 0, sizeof lck);
396   lck.l_type = for_write? F_WRLCK : F_RDLCK;
397   lck.l_whence = SEEK_SET;
398
399   while (fcntl (fd, F_SETLK, &lck) == -1)
400     {
401       if (errno != EAGAIN && errno != EACCES)
402         {
403           log_info (_("can't lock `%s': %s\n"), fname, strerror (errno));
404           return -1;
405         }
406
407       if (backoff > 2) /* Show the first message after ~2.25 seconds. */
408         log_info( _("waiting for lock on `%s'...\n"), fname);
409       
410       tv.tv_sec = backoff;
411       tv.tv_usec = 250000;
412       select (0, NULL, NULL, NULL, &tv);
413       if (backoff < 10)
414         backoff++ ;
415     }
416 #endif /*LOCK_SEED_FILE*/
417   return 0;
418 }
419
420
421
422 /****************
423  * Read in a seed form the random_seed file
424  * and return true if this was successful
425  */
426 static int
427 read_seed_file(void)
428 {
429     int fd;
430     struct stat sb;
431     unsigned char buffer[POOLSIZE];
432     int n;
433
434     if( !seed_file_name )
435         return 0;
436
437 #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
438     fd = open( seed_file_name, O_RDONLY | O_BINARY );
439 #else
440     fd = open( seed_file_name, O_RDONLY );
441 #endif
442     if( fd == -1 && errno == ENOENT) {
443         allow_seed_file_update = 1;
444         return 0;
445     }
446
447     if( fd == -1 ) {
448         log_info(_("can't open `%s': %s\n"), seed_file_name, strerror(errno) );
449         return 0;
450     }
451     if (lock_seed_file (fd, seed_file_name, 0))
452       {
453         close (fd);
454         return 0;
455       }
456
457     if( fstat( fd, &sb ) ) {
458         log_info(_("can't stat `%s': %s\n"), seed_file_name, strerror(errno) );
459         close(fd);
460         return 0;
461     }
462     if( !S_ISREG(sb.st_mode) ) {
463         log_info(_("`%s' is not a regular file - ignored\n"), seed_file_name );
464         close(fd);
465         return 0;
466     }
467     if( !sb.st_size ) {
468         log_info(_("note: random_seed file is empty\n") );
469         close(fd);
470         allow_seed_file_update = 1;
471         return 0;
472     }
473     if( sb.st_size != POOLSIZE ) {
474         log_info(_("WARNING: invalid size of random_seed file - not used\n") );
475         close(fd);
476         return 0;
477     }
478     do {
479         n = read( fd, buffer, POOLSIZE );
480     } while( n == -1 && errno == EINTR );
481     if( n != POOLSIZE ) {
482         log_fatal(_("can't read `%s': %s\n"), seed_file_name,strerror(errno) );
483         close(fd);
484         return 0;
485     }
486
487     close(fd);
488
489     add_randomness( buffer, POOLSIZE, 0 );
490     /* add some minor entropy to the pool now (this will also force a mixing) */
491     {   pid_t x = getpid();
492         add_randomness( &x, sizeof(x), 0 );
493     }
494     {   time_t x = time(NULL);
495         add_randomness( &x, sizeof(x), 0 );
496     }
497     {   clock_t x = clock();
498         add_randomness( &x, sizeof(x), 0 );
499     }
500     /* And read a few bytes from our entropy source.  By using
501      * a level of 0 this will not block and might not return anything
502      * with some entropy drivers, however the rndlinux driver will use
503      * /dev/urandom and return some stuff - Do not read to much as we
504      * want to be friendly to the scare system entropy resource. */
505     read_random_source( 0, 16, 0 );
506
507     allow_seed_file_update = 1;
508     return 1;
509 }
510
511 void
512 update_random_seed_file()
513 {
514     ulong *sp, *dp;
515     int fd, i;
516
517     if( !seed_file_name || !is_initialized || !pool_filled )
518         return;
519     if( !allow_seed_file_update ) {
520         log_info(_("note: random_seed file not updated\n"));
521         return;
522     }
523
524
525     /* copy the entropy pool to a scratch pool and mix both of them */
526     for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
527                                     i < POOLWORDS; i++, dp++, sp++ ) {
528         *dp = *sp + ADD_VALUE;
529     }
530     mix_pool(rndpool); rndstats.mixrnd++;
531     mix_pool(keypool); rndstats.mixkey++;
532
533 #if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
534     fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY,
535                                                         S_IRUSR|S_IWUSR );
536 #else
537 # if LOCK_SEED_FILE
538     fd = open( seed_file_name, O_WRONLY|O_CREAT, S_IRUSR|S_IWUSR );
539 # else
540     fd = open( seed_file_name, O_WRONLY|O_CREAT|O_TRUNC, S_IRUSR|S_IWUSR );
541 # endif
542 #endif
543     if( fd == -1 ) {
544         log_info(_("can't create `%s': %s\n"), seed_file_name, strerror(errno) );
545         return;
546     }
547
548     if (lock_seed_file (fd, seed_file_name, 1))
549       {
550         close (fd);
551         return;
552       }
553 #if LOCK_SEED_FILE
554     if (ftruncate (fd, 0))
555       {
556         log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno));
557         close (fd);
558         return;
559       }
560 #endif /*LOCK_SEED_FILE*/
561
562     do {
563         i = write( fd, keypool, POOLSIZE );
564     } while( i == -1 && errno == EINTR );
565     if( i != POOLSIZE ) {
566         log_info(_("can't write `%s': %s\n"), seed_file_name, strerror(errno) );
567     }
568     if( close(fd) )
569         log_info(_("can't close `%s': %s\n"), seed_file_name, strerror(errno) );
570 }
571
572
573 static void
574 read_pool( byte *buffer, size_t length, int level )
575 {
576     int i;
577     ulong *sp, *dp;
578
579     if( length > POOLSIZE ) {
580         log_bug("too many random bits requested\n");
581     }
582
583     if( !pool_filled ) {
584         if( read_seed_file() )
585             pool_filled = 1;
586     }
587
588     /* For level 2 quality (key generation) we alwas make
589      * sure that the pool has been seeded enough initially */
590     if( level == 2 && !did_initial_extra_seeding ) {
591         size_t needed;
592
593         pool_balance = 0;
594         needed = length - pool_balance;
595         if( needed < POOLSIZE/2 )
596             needed = POOLSIZE/2;
597         else if( needed > POOLSIZE )
598             BUG();
599         read_random_source( 3, needed, 2 );
600         pool_balance += needed;
601         did_initial_extra_seeding=1;
602     }
603
604     /* for level 2 make sure that there is enough random in the pool */
605     if( level == 2 && pool_balance < length ) {
606         size_t needed;
607
608         if( pool_balance < 0 )
609             pool_balance = 0;
610         needed = length - pool_balance;
611         if( needed > POOLSIZE )
612             BUG();
613         read_random_source( 3, needed, 2 );
614         pool_balance += needed;
615     }
616
617     /* make sure the pool is filled */
618     while( !pool_filled )
619         random_poll();
620
621     /* do always a fast random poll */
622     fast_random_poll();
623
624     if( !level ) { /* no need for cryptographic strong random */
625         /* create a new pool */
626         for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
627                                     i < POOLWORDS; i++, dp++, sp++ )
628             *dp = *sp + ADD_VALUE;
629         /* must mix both pools */
630         mix_pool(rndpool); rndstats.mixrnd++;
631         mix_pool(keypool); rndstats.mixkey++;
632         memcpy( buffer, keypool, length );
633     }
634     else {
635         /* mix the pool (if add_randomness() didn't it) */
636         if( !just_mixed ) {
637             mix_pool(rndpool);
638             rndstats.mixrnd++;
639         }
640         /* create a new pool */
641         for(i=0,dp=(ulong*)keypool, sp=(ulong*)rndpool;
642                                     i < POOLWORDS; i++, dp++, sp++ )
643             *dp = *sp + ADD_VALUE;
644         /* and mix both pools */
645         mix_pool(rndpool); rndstats.mixrnd++;
646         mix_pool(keypool); rndstats.mixkey++;
647         /* read the required data
648          * we use a readpoiter to read from a different postion each
649          * time */
650         while( length-- ) {
651             *buffer++ = keypool[pool_readpos++];
652             if( pool_readpos >= POOLSIZE )
653                 pool_readpos = 0;
654             pool_balance--;
655         }
656         if( pool_balance < 0 )
657             pool_balance = 0;
658         /* and clear the keypool */
659         wipememory(keypool, POOLSIZE);
660     }
661 }
662
663
664 /****************
665  * Add LENGTH bytes of randomness from buffer to the pool.
666  * source may be used to specify the randomness source.
667  * Source is:
668  *      0 - used ony for initialization
669  *      1 - fast random poll function
670  *      2 - normal poll function
671  *      3 - used when level 2 random quality has been requested
672  *          to do an extra pool seed.
673  */
674 static void
675 add_randomness( const void *buffer, size_t length, int source )
676 {
677     const byte *p = buffer;
678
679     if( !is_initialized )
680         initialize();
681     rndstats.addbytes += length;
682     rndstats.naddbytes++;
683     while( length-- ) {
684         rndpool[pool_writepos++] ^= *p++;
685         if( pool_writepos >= POOLSIZE ) {
686             if( source > 1 )
687                 pool_filled = 1;
688             pool_writepos = 0;
689             mix_pool(rndpool); rndstats.mixrnd++;
690             just_mixed = !length;
691         }
692     }
693 }
694
695
696
697 static void
698 random_poll()
699 {
700     rndstats.slowpolls++;
701     read_random_source( 2, POOLSIZE/5, 1 );
702 }
703
704
705 void
706 fast_random_poll()
707 {
708     static int (*fnc)( void (*)(const void*, size_t, int), int) = NULL;
709     static int initialized = 0;
710
711     rndstats.fastpolls++;
712     if( !initialized ) {
713         if( !is_initialized )
714             initialize();
715         initialized = 1;
716         fnc = getfnc_fast_random_poll();
717     }
718     if( fnc ) {
719         (*fnc)( add_randomness, 1 );
720         return;
721     }
722
723     /* fall back to the generic function */
724 #if defined(HAVE_GETHRTIME) && !defined(HAVE_BROKEN_GETHRTIME)
725     {   hrtime_t tv;
726         /* On some Solaris and HPUX system gethrtime raises an SIGILL, but we 
727          * checked this with configure */
728         tv = gethrtime();
729         add_randomness( &tv, sizeof(tv), 1 );
730     }
731 #elif defined (HAVE_GETTIMEOFDAY)
732     {   struct timeval tv;
733         if( gettimeofday( &tv, NULL ) )
734             BUG();
735         add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
736         add_randomness( &tv.tv_usec, sizeof(tv.tv_usec), 1 );
737     }
738 #elif defined (HAVE_CLOCK_GETTIME)
739     {   struct timespec tv;
740         if( clock_gettime( CLOCK_REALTIME, &tv ) == -1 )
741             BUG();
742         add_randomness( &tv.tv_sec, sizeof(tv.tv_sec), 1 );
743         add_randomness( &tv.tv_nsec, sizeof(tv.tv_nsec), 1 );
744     }
745 #elif defined (HAVE_TIMES)
746     {   struct tms buf;
747         if( times( &buf ) == -1 )
748             BUG();
749         add_randomness( &buf, sizeof buf, 1 );
750     }
751 #endif
752 #ifdef HAVE_GETRUSAGE
753 #ifndef RUSAGE_SELF
754 #ifdef __GCC__
755 #warning There is no RUSAGE_SELF on this system
756 #endif
757 #else
758     {   struct rusage buf;
759         /* QNX/Neutrino does return ENOSYS - so we just ignore it and
760          * add whatever is in buf.  In a chroot environment it might not
761          * work at all (i.e. because /proc/ is not accessible), so we better 
762          * ignore all error codes and hope for the best
763          */
764         getrusage( RUSAGE_SELF, &buf );
765         
766         add_randomness( &buf, sizeof buf, 1 );
767         wipememory( &buf, sizeof buf );
768     }
769 #endif
770 #endif
771     /* time and clock are available on all systems - so
772      * we better do it just in case one of the above functions
773      * didn't work */
774     {   time_t x = time(NULL);
775         add_randomness( &x, sizeof(x), 1 );
776     }
777     {   clock_t x = clock();
778         add_randomness( &x, sizeof(x), 1 );
779     }
780 }
781
782
783
784 static void
785 read_random_source( int requester, size_t length, int level )
786 {
787     static int (*fnc)(void (*)(const void*, size_t, int), int,
788                                                     size_t, int) = NULL;
789     if( !fnc ) {
790         if( !is_initialized )
791             initialize();
792         fnc = getfnc_gather_random();
793         if( !fnc ) {
794             faked_rng = 1;
795             fnc = gather_faked;
796         }
797         if( !requester && !length && !level )
798             return; /* init only */
799     }
800     if( (*fnc)( add_randomness, requester, length, level ) < 0 )
801         log_fatal("No way to gather entropy for the RNG\n");
802 }
803
804
805 static int
806 gather_faked( void (*add)(const void*, size_t, int), int requester,
807               size_t length, int level )
808 {
809     static int initialized=0;
810     size_t n;
811     char *buffer, *p;
812
813     if( !initialized ) {
814         log_info(_("WARNING: using insecure random number generator!!\n"));
815         tty_printf(_("The random number generator is only a kludge to let\n"
816                    "it run - it is in no way a strong RNG!\n\n"
817                    "DON'T USE ANY DATA GENERATED BY THIS PROGRAM!!\n\n"));
818         initialized=1;
819 #ifdef HAVE_RAND
820         srand(make_timestamp()*getpid());
821 #else
822         srandom(make_timestamp()*getpid());
823 #endif
824     }
825
826     p = buffer = xmalloc( length );
827     n = length;
828 #ifdef HAVE_RAND
829     while( n-- )
830         *p++ = ((unsigned)(1 + (int) (256.0*rand()/(RAND_MAX+1.0)))-1);
831 #else
832     while( n-- )
833         *p++ = ((unsigned)(1 + (int) (256.0*random()/(RAND_MAX+1.0)))-1);
834 #endif
835     add_randomness( buffer, length, requester );
836     xfree(buffer);
837     return 0; /* okay */
838 }