See ChangeLog: Wed Feb 10 17:15:39 CET 1999 Werner Koch
[gnupg.git] / cipher / rndunix.c
1 /****************************************************************************
2  *                                                                          *
3  *   BeOS Randomness-Gathering Code                                         *
4  *   Copyright Peter Gutmann, Paul Kendall, and Chris Wedgwood 1996-1998    *
5  *   Copyright (C) 1998, 1999  Werner Koch
6  *                                                                          *
7  ****************************************************************************/
8
9 /* General includes */
10
11 #include <config.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 #include <assert.h>
16
17 /* OS-specific includes */
18
19 #ifdef __osf__
20   /* Somewhere in the morass of system-specific cruft which OSF/1 pulls in
21    * via the following includes are various endianness defines, so we
22    * undefine the cryptlib ones, which aren't really needed for this module
23    * anyway */
24 #undef BIG_ENDIAN
25 #undef LITTLE_ENDIAN
26 #endif                          /* __osf__ */
27
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <pwd.h>
31 #ifndef __QNX__
32 #include <sys/errno.h>
33 #include <sys/ipc.h>
34 #endif                          /* __QNX__ */
35 #include <sys/time.h>           /* SCO and SunOS need this before resource.h */
36 #ifndef __QNX__
37 #include <sys/resource.h>
38 #endif                          /* __QNX__ */
39 #ifdef _AIX
40 #include <sys/select.h>
41 #endif                          /* _AIX */
42 #ifndef __QNX__
43 #include <sys/shm.h>
44 #include <sys/signal.h>
45 #endif                          /* __QNX__ */
46 #include <sys/stat.h>
47 #include <sys/types.h>          /* Verschiedene komische Typen */
48 #if defined( __hpux ) && ( OS_VERSION == 9 )
49 #include <vfork.h>
50 #endif                          /* __hpux 9.x, after that it's in unistd.h */
51 #include <sys/wait.h>
52 /* #include <kitchensink.h> */
53 #include <errno.h>
54
55 #include "types.h"  /* for byte and u32 typedefs */
56 #include "g10lib.h"
57 #ifndef IS_MODULE
58 #include "dynload.h"
59 #endif
60
61 #ifndef EAGAIN
62   #define EAGAIN  EWOULDBLOCK
63 #endif
64
65 #define GATHER_BUFSIZE          49152   /* Usually about 25K are filled */
66
67 /* The structure containing information on random-data sources.  Each
68  * record contains the source and a relative estimate of its usefulness
69  * (weighting) which is used to scale the number of kB of output from the
70  * source (total = data_bytes / usefulness).  Usually the weighting is in the
71  * range 1-3 (or 0 for especially useless sources), resulting in a usefulness
72  * rating of 1...3 for each kB of source output (or 0 for the useless
73  * sources).
74  *
75  * If the source is constantly changing (certain types of network statistics
76  * have this characteristic) but the amount of output is small, the weighting
77  * is given as a negative value to indicate that the output should be treated
78  * as if a minimum of 1K of output had been obtained.  If the source produces
79  * a lot of output then the scale factor is fractional, resulting in a
80  * usefulness rating of < 1 for each kB of source output.
81  *
82  * In order to provide enough randomness to satisfy the requirements for a
83  * slow poll, we need to accumulate at least 20 points of usefulness (a
84  * typical system should get about 30 points).
85  *
86  * Some potential options are missed out because of special considerations.
87  * pstat -i and pstat -f can produce amazing amounts of output (the record
88  * is 600K on an Oracle server) which floods the buffer and doesn't yield
89  * anything useful (apart from perhaps increasing the entropy of the vmstat
90  * output a bit), so we don't bother with this.  pstat in general produces
91  * quite a bit of output, but it doesn't change much over time, so it gets
92  * very low weightings.  netstat -s produces constantly-changing output but
93  * also produces quite a bit of it, so it only gets a weighting of 2 rather
94  * than 3.  The same holds for netstat -in, which gets 1 rather than 2.
95  *
96  * Some binaries are stored in different locations on different systems so
97  * alternative paths are given for them.  The code sorts out which one to
98  * run by itself, once it finds an exectable somewhere it moves on to the
99  * next source.  The sources are arranged roughly in their order of
100  * usefulness, occasionally sources which provide a tiny amount of
101  * relatively useless data are placed ahead of ones which provide a large
102  * amount of possibly useful data because another 100 bytes can't hurt, and
103  * it means the buffer won't be swamped by one or two high-output sources.
104  * All the high-output sources are clustered towards the end of the list
105  * for this reason.  Some binaries are checked for in a certain order, for
106  * example under Slowaris /usr/ucb/ps understands aux as an arg, but the
107  * others don't.  Some systems have conditional defines enabling alternatives
108  * to commands which don't understand the usual options but will provide
109  * enough output (in the form of error messages) to look like they're the
110  * real thing, causing alternative options to be skipped (we can't check the
111  * return either because some commands return peculiar, non-zero status even
112  * when they're working correctly).
113  *
114  * In order to maximise use of the buffer, the code performs a form of run-
115  * length compression on its input where a repeated sequence of bytes is
116  * replaced by the occurrence count mod 256.  Some commands output an awful
117  * lot of whitespace, this measure greatly increases the amount of data we
118  * can fit in the buffer.
119  *
120  * When we scale the weighting using the SC() macro, some preprocessors may
121  * give a division by zero warning for the most obvious expression
122  * 'weight ? 1024 / weight : 0' (and gcc 2.7.2.2 dies with a division by zero
123  * trap), so we define a value SC_0 which evaluates to zero when fed to
124  * '1024 / SC_0' */
125
126 #define SC( weight )    ( 1024 / weight )       /* Scale factor */
127 #define SC_0                    16384   /* SC( SC_0 ) evalutes to 0 */
128
129 static struct RI {
130     const char *path;           /* Path to check for existence of source */
131     const char *arg;            /* Args for source */
132     const int usefulness;       /* Usefulness of source */
133     FILE *pipe;                 /* Pipe to source as FILE * */
134     int pipeFD;                 /* Pipe to source as FD */
135     pid_t pid;                  /* pid of child for waitpid() */
136     int length;                 /* Quantity of output produced */
137     const int hasAlternative;       /* Whether source has alt.location */
138 } dataSources[] = {
139
140     {   "/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 1    },
141     {   "/usr/bin/vmstat", "-s", SC(-3), NULL, 0, 0, 0, 0},
142     {   "/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 1     },
143     {   "/usr/bin/vmstat", "-c", SC(-3), NULL, 0, 0, 0, 0},
144     {   "/usr/bin/pfstat", NULL, SC(-2), NULL, 0, 0, 0, 0},
145     {   "/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 1     },
146     {   "/usr/bin/vmstat", "-i", SC(-2), NULL, 0, 0, 0, 0},
147     {   "/usr/ucb/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 },
148     {   "/usr/bin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1 },
149     {   "/usr/sbin/netstat", "-s", SC(2), NULL, 0, 0, 0, 1},
150     {   "/usr/etc/netstat", "-s", SC(2), NULL, 0, 0, 0, 0},
151     {   "/usr/bin/nfsstat", NULL, SC(2), NULL, 0, 0, 0, 0},
152     {   "/usr/ucb/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1  },
153     {   "/usr/bin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1  },
154     {   "/usr/sbin/netstat", "-m", SC(-1), NULL, 0, 0, 0, 1 },
155     {   "/usr/etc/netstat", "-m", SC(-1), NULL, 0, 0, 0, 0 },
156     {   "/bin/netstat",     "-in", SC(-1), NULL, 0, 0, 0, 1 },
157     {   "/usr/ucb/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 },
158     {   "/usr/bin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1 },
159     {   "/usr/sbin/netstat", "-in", SC(-1), NULL, 0, 0, 0, 1},
160     {   "/usr/etc/netstat", "-in", SC(-1), NULL, 0, 0, 0, 0},
161     {   "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.1.0",
162                                     SC(-1), NULL, 0, 0, 0, 0 }, /* UDP in */
163     {   "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.7.4.0",
164                                     SC(-1), NULL, 0, 0, 0, 0 },  /* UDP out */
165     {   "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.4.3.0",
166                                     SC(-1), NULL, 0, 0, 0, 0 }, /* IP ? */
167     {   "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.10.0",
168                                     SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */
169     {   "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.11.0",
170                                     SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */
171     {   "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.6.13.0",
172                                     SC(-1), NULL, 0, 0, 0, 0 }, /* TCP ? */
173     {   "/usr/bin/mpstat", NULL, SC(1), NULL, 0, 0, 0, 0     },
174     {   "/usr/bin/w", NULL, SC(1), NULL, 0, 0, 0, 1           },
175     {   "/usr/bsd/w", NULL, SC(1), NULL, 0, 0, 0, 0          },
176     {   "/usr/bin/df", NULL, SC(1), NULL, 0, 0, 0, 1          },
177     {   "/bin/df", NULL, SC(1), NULL, 0, 0, 0, 0             },
178     {   "/usr/sbin/portstat", NULL, SC(1), NULL, 0, 0, 0, 0  },
179     {   "/usr/bin/iostat", NULL, SC(SC_0), NULL, 0, 0, 0, 0  },
180     {   "/usr/bin/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 1   },
181     {   "/usr/bsd/uptime", NULL, SC(SC_0), NULL, 0, 0, 0, 0  },
182     {   "/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 1       },
183     {   "/usr/bin/vmstat", "-f", SC(SC_0), NULL, 0, 0, 0, 0  },
184     {   "/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 1       },
185     {   "/usr/bin/vmstat", NULL, SC(SC_0), NULL, 0, 0, 0, 0  },
186     {   "/usr/ucb/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1   },
187     {   "/usr/bin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1   },
188     {   "/usr/sbin/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 1  },
189     {   "/usr/etc/netstat", "-n", SC(0.5), NULL, 0, 0, 0, 0  },
190 #if defined( __sgi ) || defined( __hpux )
191     {   "/bin/ps", "-el", SC(0.3), NULL, 0, 0, 0, 1           },
192 #endif                          /* __sgi || __hpux */
193     {   "/usr/ucb/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1       },
194     {   "/usr/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 1       },
195     {   "/bin/ps", "aux", SC(0.3), NULL, 0, 0, 0, 0          },
196     {   "/usr/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 1      },
197     {   "/bin/ipcs", "-a", SC(0.5), NULL, 0, 0, 0, 0         },
198     /* Unreliable source, depends on system usage */
199     {   "/etc/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 1         },
200     {   "/bin/pstat", "-p", SC(0.5), NULL, 0, 0, 0, 0        },
201     {   "/etc/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 1         },
202     {   "/bin/pstat", "-S", SC(0.2), NULL, 0, 0, 0, 0        },
203     {   "/etc/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 1         },
204     {   "/bin/pstat", "-v", SC(0.2), NULL, 0, 0, 0, 0        },
205     {   "/etc/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 1         },
206     {   "/bin/pstat", "-x", SC(0.2), NULL, 0, 0, 0, 0        },
207     {   "/etc/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 1         },
208     {   "/bin/pstat", "-t", SC(0.1), NULL, 0, 0, 0, 0        },
209     /* pstat is your friend */
210     {   "/usr/bin/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 1   },
211 #ifdef __sgi
212     {   "/usr/bsd/last", "-50", SC(0.3), NULL, 0, 0, 0, 0    },
213 #endif                          /* __sgi */
214 #ifdef __hpux
215     {   "/etc/last", "-50", SC(0.3), NULL, 0, 0, 0, 0        },
216 #endif                          /* __hpux */
217     {   "/usr/bsd/last", "-n 50", SC(0.3), NULL, 0, 0, 0, 0  },
218     {   "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.1.0",
219                                 SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */
220     {   "/usr/sbin/snmp_request", "localhost public get 1.3.6.1.2.1.5.3.0",
221                                 SC(0.1), NULL, 0, 0, 0, 0 }, /* ICMP ? */
222     {   "/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1  },
223     {   "/usr/etc/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1  },
224     {   "/usr/bin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 1  },
225     {   "/usr/sbin/arp", "-a", SC(0.1), NULL, 0, 0, 0, 0 },
226     {   "/usr/sbin/ripquery", "-nw 1 127.0.0.1",
227                                 SC(0.1), NULL, 0, 0, 0, 0 },
228     {   "/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1     },
229     {   "/usr/bin/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 1 },
230     {   "/usr/ucb/lpstat", "-t", SC(0.1), NULL, 0, 0, 0, 0 },
231     {   "/usr/bin/tcpdump", "-c 5 -efvvx", SC(1), NULL, 0, 0, 0, 0 },
232     /* This is very environment-dependant.  If network traffic is low, it'll
233      * probably time out before delivering 5 packets, which is OK because
234      * it'll probably be fixed stuff like ARP anyway */
235     {   "/usr/sbin/advfsstat", "-b usr_domain",
236                                 SC(SC_0), NULL, 0, 0, 0, 0},
237     {   "/usr/sbin/advfsstat", "-l 2 usr_domain",
238                                 SC(0.5), NULL, 0, 0, 0, 0},
239     {   "/usr/sbin/advfsstat", "-p usr_domain",
240                                 SC(SC_0), NULL, 0, 0, 0, 0},
241     /* This is a complex and screwball program.  Some systems have things
242      * like rX_dmn, x = integer, for RAID systems, but the statistics are
243      * pretty dodgy */
244 #if 0
245     /* The following aren't enabled since they're somewhat slow and not very
246      * unpredictable, however they give an indication of the sort of sources
247      * you can use (for example the finger might be more useful on a
248      * firewalled internal network) */
249     {   "/usr/bin/finger", "@ml.media.mit.edu", SC(0.9), NULL, 0, 0, 0, 0 },
250     {   "/usr/local/bin/wget", "-O - http://lavarand.sgi.com/block.html",
251                                 SC(0.9), NULL, 0, 0, 0, 0 },
252     {   "/bin/cat", "/usr/spool/mqueue/syslog", SC(0.9), NULL, 0, 0, 0, 0 },
253 #endif                          /* 0 */
254     {   NULL, NULL, 0, NULL, 0, 0, 0, 0 }
255 };
256
257 static byte *gather_buffer;         /* buffer for gathering random noise */
258 static int gather_buffer_size;      /* size of the memory buffer */
259 static uid_t gatherer_uid;
260
261 /* The message structure used to communicate with the parent */
262 typedef struct {
263     int  usefulness;    /* usefulness of data */
264     int  ndata;         /* valid bytes in data */
265     char data[500];     /* gathered data */
266 } GATHER_MSG;
267
268 /* Under SunOS popen() doesn't record the pid of the child process.  When
269  * pclose() is called, instead of calling waitpid() for the correct child, it
270  * calls wait() repeatedly until the right child is reaped.  The problem is
271  * that this reaps any other children that happen to have died at that
272  * moment, and when their pclose() comes along, the process hangs forever.
273  * The fix is to use a wrapper for popen()/pclose() which saves the pid in
274  * the dataSources structure (code adapted from GNU-libc's popen() call).
275  *
276  * Aut viam inveniam aut faciam */
277
278 static FILE *
279 my_popen(struct RI *entry)
280 {
281
282     int pipedes[2];
283     FILE *stream;
284
285     /* Create the pipe */
286     if (pipe(pipedes) < 0)
287         return (NULL);
288
289     /* Fork off the child ("vfork() is like an OS orgasm.  All OS's want to
290      * do it, but most just end up faking it" - Chris Wedgwood).  If your OS
291      * supports it, you should try to use vfork() here because it's somewhat
292      * more efficient */
293 #if defined( sun ) || defined( __ultrix__ ) || defined( __osf__ ) || \
294         defined(__hpux)
295     entry->pid = vfork();
296 #else                           /*  */
297     entry->pid = fork();
298 #endif                          /* Unixen which have vfork() */
299     if (entry->pid == (pid_t) - 1) {
300         /* The fork failed */
301         close(pipedes[0]);
302         close(pipedes[1]);
303         return (NULL);
304     }
305
306     if (entry->pid == (pid_t) 0) {
307         struct passwd *passwd;
308
309         /* We are the child.  Make the read side of the pipe be stdout */
310         if (dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO) < 0)
311             exit(127);
312
313         /* Now that everything is set up, give up our permissions to make
314          * sure we don't read anything sensitive.  If the getpwnam() fails,
315          * we default to -1, which is usually nobody */
316         if (gatherer_uid == (uid_t)-1 && \
317             (passwd = getpwnam("nobody")) != NULL)
318             gatherer_uid = passwd->pw_uid;
319
320         setuid(gatherer_uid);
321
322         /* Close the pipe descriptors */
323         close(pipedes[STDIN_FILENO]);
324         close(pipedes[STDOUT_FILENO]);
325
326         /* Try and exec the program */
327         execl(entry->path, entry->path, entry->arg, NULL);
328
329         /* Die if the exec failed */
330         exit(127);
331     }
332
333     /* We are the parent.  Close the irrelevant side of the pipe and open
334      * the relevant side as a new stream.  Mark our side of the pipe to
335      * close on exec, so new children won't see it */
336     close(pipedes[STDOUT_FILENO]);
337
338     fcntl(pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
339
340     stream = fdopen(pipedes[STDIN_FILENO], "r");
341
342     if (stream == NULL) {
343         int savedErrno = errno;
344
345         /* The stream couldn't be opened or the child structure couldn't be
346          * allocated.  Kill the child and close the other side of the pipe */
347         kill(entry->pid, SIGKILL);
348         if (stream == NULL)
349             close(pipedes[STDOUT_FILENO]);
350         else
351             fclose(stream);
352
353         waitpid(entry->pid, NULL, 0);
354
355         entry->pid = 0;
356         errno = savedErrno;
357         return (NULL);
358     }
359
360     return (stream);
361 }
362
363 static int
364 my_pclose(struct RI *entry)
365 {
366     int status = 0;
367
368     if (fclose(entry->pipe))
369         return (-1);
370
371     /* We ignore the return value from the process because some programs
372      * return funny values which would result in the input being discarded
373      * even if they executed successfully.  This isn't a problem because the
374      * result data size threshold will filter out any programs which exit
375      * with a usage message without producing useful output */
376     if (waitpid(entry->pid, NULL, 0) != entry->pid)
377         status = -1;
378
379     entry->pipe = NULL;
380     entry->pid = 0;
381     return (status);
382 }
383
384
385 /* Unix slow poll (without special support for Linux)
386  *
387  * If a few of the randomness sources create a large amount of output then
388  * the slowPoll() stops once the buffer has been filled (but before all the
389  * randomness sources have been sucked dry) so that the 'usefulness' factor
390  * remains below the threshold.  For this reason the gatherer buffer has to
391  * be fairly sizeable on moderately loaded systems.  This is something of a
392  * bug since the usefulness should be influenced by the amount of output as
393  * well as the source type */
394
395
396 static int
397 slow_poll(FILE *dbgfp, int dbgall, size_t *nbytes )
398 {
399     int moreSources;
400     struct timeval tv;
401     fd_set fds;
402   #if defined( __hpux )
403     size_t maxFD = 0;
404     int pageSize = 4096;        /* PHUX doesn't have getpagesize() */
405   #elif defined( _M_XENIX ) || defined( __aux )
406     int maxFD = 0, pageSize = 4096;/* Nor do others, but they get fd right */
407   #else
408     int maxFD = 0, pageSize = getpagesize();
409   #endif /* OS-specific brokenness */
410     int bufPos, i, usefulness = 0;
411
412
413     /* Fire up each randomness source */
414     FD_ZERO(&fds);
415     for (i = 0; dataSources[i].path != NULL; i++) {
416         /* Since popen() is a fairly heavy function, we check to see whether
417          * the executable exists before we try to run it */
418         if (access(dataSources[i].path, X_OK)) {
419             if( dbgfp && dbgall )
420                 fprintf(dbgfp, "%s not present%s\n", dataSources[i].path,
421                                dataSources[i].hasAlternative ?
422                                         ", has alternatives" : "");
423             dataSources[i].pipe = NULL;
424         }
425         else
426             dataSources[i].pipe = my_popen(&dataSources[i]);
427
428         if (dataSources[i].pipe != NULL) {
429             dataSources[i].pipeFD = fileno(dataSources[i].pipe);
430             if (dataSources[i].pipeFD > maxFD)
431                 maxFD = dataSources[i].pipeFD;
432           #ifdef O_NONBLOCK /* Ohhh what a hack (used for Atari) */
433             fcntl(dataSources[i].pipeFD, F_SETFL, O_NONBLOCK);
434           #else
435             #warning O_NONBLOCK is missing
436           #endif
437             FD_SET(dataSources[i].pipeFD, &fds);
438             dataSources[i].length = 0;
439
440             /* If there are alternatives for this command, don't try and
441              * execute them */
442             while (dataSources[i].hasAlternative) {
443                 if( dbgfp && dbgall )
444                     fprintf(dbgfp, "Skipping %s\n", dataSources[i + 1].path);
445                 i++;
446             }
447         }
448     }
449
450
451     /* Suck all the data we can get from each of the sources */
452     bufPos = 0;
453     moreSources = 1;
454     while (moreSources && bufPos <= gather_buffer_size) {
455         /* Wait for data to become available from any of the sources, with a
456          * timeout of 10 seconds.  This adds even more randomness since data
457          * becomes available in a nondeterministic fashion.  Kudos to HP's QA
458          * department for managing to ship a select() which breaks its own
459          * prototype */
460         tv.tv_sec = 10;
461         tv.tv_usec = 0;
462
463       #if defined( __hpux ) && ( OS_VERSION == 9 )
464         if (select(maxFD + 1, (int *)&fds, NULL, NULL, &tv) == -1)
465       #else  /*  */
466         if (select(maxFD + 1, &fds, NULL, NULL, &tv) == -1)
467       #endif /* __hpux */
468             break;
469
470         /* One of the sources has data available, read it into the buffer */
471         for (i = 0; dataSources[i].path != NULL; i++) {
472             if( dataSources[i].pipe && FD_ISSET(dataSources[i].pipeFD, &fds)) {
473                 size_t noBytes;
474
475                 if ((noBytes = fread(gather_buffer + bufPos, 1,
476                                      gather_buffer_size - bufPos,
477                                      dataSources[i].pipe)) == 0) {
478                     if (my_pclose(&dataSources[i]) == 0) {
479                         int total = 0;
480
481                         /* Try and estimate how much entropy we're getting
482                          * from a data source */
483                         if (dataSources[i].usefulness)
484                             if (dataSources[i].usefulness < 0)
485                                 total = (dataSources[i].length + 999)
486                                         / -dataSources[i].usefulness;
487                             else
488                                 total = dataSources[i].length
489                                         / dataSources[i].usefulness;
490                         if( dbgfp )
491                             fprintf(dbgfp,
492                                "%s %s contributed %d bytes, "
493                                "usefulness = %d\n", dataSources[i].path,
494                                (dataSources[i].arg != NULL) ?
495                                        dataSources[i].arg : "",
496                                       dataSources[i].length, total);
497                         if( dataSources[i].length )
498                             usefulness += total;
499                     }
500                     dataSources[i].pipe = NULL;
501                 }
502                 else {
503                     int currPos = bufPos;
504                     int endPos = bufPos + noBytes;
505
506                     /* Run-length compress the input byte sequence */
507                     while (currPos < endPos) {
508                         int ch = gather_buffer[currPos];
509
510                         /* If it's a single byte, just copy it over */
511                         if (ch != gather_buffer[currPos + 1]) {
512                             gather_buffer[bufPos++] = ch;
513                             currPos++;
514                         }
515                         else {
516                             int count = 0;
517
518                             /* It's a run of repeated bytes, replace them
519                              * with the byte count mod 256 */
520                             while ((ch == gather_buffer[currPos])
521                                     && currPos < endPos) {
522                                 count++;
523                                 currPos++;
524                             }
525                             gather_buffer[bufPos++] = count;
526                             noBytes -= count - 1;
527                         }
528                     }
529
530                     /* Remember the number of (compressed) bytes of input we
531                      * obtained */
532                     dataSources[i].length += noBytes;
533                 }
534             }
535         }
536
537         /* Check if there is more input available on any of the sources */
538         moreSources = 0;
539         FD_ZERO(&fds);
540         for (i = 0; dataSources[i].path != NULL; i++) {
541             if (dataSources[i].pipe != NULL) {
542                 FD_SET(dataSources[i].pipeFD, &fds);
543                 moreSources = 1;
544             }
545         }
546     }
547
548     if( dbgfp ) {
549         fprintf(dbgfp, "Got %d bytes, usefulness = %d\n", bufPos, usefulness);
550         fflush(dbgfp);
551     }
552     *nbytes = bufPos;
553     return usefulness;
554 }
555
556 /****************
557  * Start the gatherer process which writes messages of
558  * type GATHERER_MSG to pipedes
559  */
560 static void
561 start_gatherer( int pipefd )
562 {
563     FILE *dbgfp = NULL;
564     int dbgall;
565
566     {
567         const char *s = getenv("GNUPG_RNDUNIX_DBG");
568         if( s ) {
569             dbgfp = (*s=='-' && !s[1])? stdout : fopen(s, "a");
570             if( !dbgfp )
571                 g10_log_info("can't open debug file `%s': %s\n",
572                              s, strerror(errno) );
573             else
574                 fprintf(dbgfp,"\nSTART RNDUNIX DEBUG pid=%d\n", (int)getpid());
575         }
576         dbgall = !!getenv("GNUPG_RNDUNIX_DBGALL");
577     }
578     /* close all files but the ones we need */
579     {   int nmax, n1, n2, i;
580         if( (nmax=sysconf( _SC_OPEN_MAX )) < 0 ) {
581           #ifdef _POSIX_OPEN_MAX
582             nmax = _POSIX_OPEN_MAX;
583           #else
584             nmax = 20; /* assume a reasonable value */
585           #endif
586         }
587         n1 = fileno( stderr );
588         n2 = dbgfp? fileno( dbgfp ) : -1;
589         for(i=0; i < nmax; i++ ) {
590             if( i != n1 && i != n2 && i != pipefd )
591                 close(i);
592         }
593         errno = 0;
594     }
595
596
597
598     /* Set up the buffer */
599     gather_buffer_size = GATHER_BUFSIZE;
600     gather_buffer = malloc( gather_buffer_size );
601     if( !gather_buffer ) {
602         g10_log_error("out of core while allocating the gatherer buffer\n");
603         exit(2);
604     }
605
606     /* Reset the SIGC(H)LD handler to the system default.  This is necessary
607      * because if the program which cryptlib is a part of installs its own
608      * SIGC(H)LD handler, it will end up reaping the cryptlib children before
609      * cryptlib can.  As a result, my_pclose() will call waitpid() on a
610      * process which has already been reaped by the installed handler and
611      * return an error, so the read data won't be added to the randomness
612      * pool.  There are two types of SIGC(H)LD naming, the SysV SIGCLD and
613      * the BSD/Posix SIGCHLD, so we need to handle either possibility */
614   #ifdef SIGCLD
615     signal(SIGCLD, SIG_DFL);
616   #else
617     signal(SIGCHLD, SIG_DFL);
618   #endif
619
620     fclose(stderr);             /* Arrghh!!  It's Stuart code!! */
621
622     for(;;) {
623         GATHER_MSG msg;
624         size_t nbytes;
625         const char *p;
626
627         msg.usefulness = slow_poll( dbgfp, dbgall, &nbytes );
628         p = gather_buffer;
629         while( nbytes ) {
630             msg.ndata = nbytes > sizeof(msg.data)? sizeof(msg.data) : nbytes;
631             memcpy( msg.data, p, msg.ndata );
632             nbytes -= msg.ndata;
633             p += msg.ndata;
634
635             while( write( pipefd, &msg, sizeof(msg) ) != sizeof(msg) ) {
636                 if( errno == EINTR )
637                     continue;
638                 if( errno == EAGAIN ) {
639                     struct timeval tv;
640                     tv.tv_sec = 0;
641                     tv.tv_usec = 50000;
642                     select(0, NULL, NULL, NULL, &tv);
643                     continue;
644                 }
645                 if( errno == EPIPE ) /* parent has exited, so give up */
646                    exit(0);
647
648                 /* we can't do very much here because stderr is closed */
649                 if( dbgfp )
650                     fprintf(dbgfp, "gatherer can't write to pipe: %s\n",
651                                     strerror(errno) );
652                 /* we start a new poll to give the system some time */
653                 nbytes = 0;
654                 break;
655             }
656         }
657     }
658     /* we are killed when the parent dies */
659 }
660
661
662 static int
663 read_a_msg( int fd, GATHER_MSG *msg )
664 {
665     char *buffer = (char*)msg;
666     size_t length = sizeof( *msg );
667     int n;
668
669     do {
670         do {
671             n = read(fd, buffer, length );
672         } while( n == -1 && errno == EINTR );
673         if( n == -1 )
674             return -1;
675         buffer += n;
676         length -= n;
677     } while( length );
678     return 0;
679 }
680
681
682 static int
683 gather_random( void (*add)(const void*, size_t, int), int requester,
684                size_t length, int level )
685 {
686     static pid_t gatherer_pid = 0;
687     static int pipedes[2];
688     GATHER_MSG msg;
689     size_t n;
690
691     if( !gatherer_pid ) {
692         /* make sure we are not setuid */
693         if( getuid() != geteuid() )
694             BUG();
695         /* time to start the gatherer process */
696         if( pipe( pipedes ) ) {
697             g10_log_error("pipe() failed: %s\n", strerror(errno));
698             return -1;
699         }
700         gatherer_pid = fork();
701         if( gatherer_pid == -1 ) {
702             g10_log_error("can't for gatherer process: %s\n", strerror(errno));
703             return -1;
704         }
705         if( !gatherer_pid ) {
706             start_gatherer( pipedes[1] );
707             /* oops, can't happen */
708             return -1;
709         }
710     }
711
712     /* now read from the gatherer */
713     while( length ) {
714         int goodness;
715         ulong subtract;
716
717         if( read_a_msg( pipedes[0], &msg ) ) {
718             g10_log_error("reading from gatherer pipe failed: %s\n",
719                                                             strerror(errno));
720             return -1;
721         }
722
723
724         if( level > 1 ) {
725             if( msg.usefulness > 30 )
726                 goodness = 100;
727             else if ( msg.usefulness )
728                 goodness = msg.usefulness * 100 / 30;
729             else
730                 goodness = 0;
731         }
732         else if( level ) {
733             if( msg.usefulness > 15 )
734                 goodness = 100;
735             else if ( msg.usefulness )
736                 goodness = msg.usefulness * 100 / 15;
737             else
738                 goodness = 0;
739         }
740         else
741             goodness = 100; /* goodness of level 0 is always 100 % */
742
743         n = msg.ndata;
744         if( n > length )
745             n = length;
746         (*add)( msg.data, n, requester );
747
748         /* this is the trick how e cope with the goodness */
749         subtract = (ulong)n * goodness / 100;
750         /* subtract at least 1 byte to avoid infinite loops */
751         length -= subtract ? subtract : 1;
752     }
753
754     return 0;
755 }
756
757
758
759 #ifndef IS_MODULE
760 static
761 #endif
762 const char * const gnupgext_version = "RNDUNIX ($Revision$)";
763
764
765 static struct {
766     int class;
767     int version;
768     void *func;
769 } func_table[] = {
770     { 40, 1, gather_random },
771 };
772
773 /****************
774  * Enumerate the names of the functions together with informations about
775  * this function. Set sequence to an integer with a initial value of 0 and
776  * do not change it.
777  * If what is 0 all kind of functions are returned.
778  * Return values: class := class of function:
779  *                         10 = message digest algorithm info function
780  *                         11 = integer with available md algorithms
781  *                         20 = cipher algorithm info function
782  *                         21 = integer with available cipher algorithms
783  *                         30 = public key algorithm info function
784  *                         31 = integer with available pubkey algorithms
785  *                         40 = get read_random_source() function
786  *                         41 = get fast_random_poll function
787  *                version = interface version of the function/pointer
788  *                          (currently this is 1 for all functions)
789  */
790
791 #ifndef IS_MODULE
792 static
793 #endif
794 void *
795 gnupgext_enum_func( int what, int *sequence, int *class, int *vers )
796 {
797     void *ret;
798     int i = *sequence;
799
800     do {
801         if ( i >= DIM(func_table) || i < 0 ) {
802             return NULL;
803         }
804         *class = func_table[i].class;
805         *vers  = func_table[i].version;
806         ret = func_table[i].func;
807         i++;
808     } while ( what && what != *class );
809
810     *sequence = i;
811     return ret;
812 }
813
814 #ifndef IS_MODULE
815 void
816 rndunix_constructor(void)
817 {
818     register_internal_cipher_extension( gnupgext_version,
819                                         gnupgext_enum_func );
820 }
821 #endif
822
823