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