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