]> andersk Git - openssh.git/blob - entropy.c
- Irix portability fixes - don't include netinet headers more than once
[openssh.git] / entropy.c
1 /*
2  * Copyright (c) 2000 Damien Miller.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. All advertising materials mentioning features or use of this software
13  *    must display the following acknowledgement:
14  *      This product includes software developed by Markus Friedl.
15  * 4. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "includes.h"
31
32 #include "ssh.h"
33 #include "xmalloc.h"
34
35 #include <openssl/rand.h>
36 #include <openssl/sha.h>
37
38 RCSID("$Id$");
39
40 #ifdef EGD_SOCKET
41 #ifndef offsetof
42 # define offsetof(type, member) ((size_t) &((type *)0)->member)
43 #endif
44 /* Collect entropy from EGD */
45 void get_random_bytes(unsigned char *buf, int len)
46 {
47         static int egd_socket = -1;
48         int c;
49         char egd_message[2] = { 0x02, 0x00 };
50         struct sockaddr_un addr;
51         int addr_len;
52
53         memset(&addr, '\0', sizeof(addr));
54         addr.sun_family = AF_UNIX;
55         
56         /* FIXME: compile time check? */
57         if (sizeof(EGD_SOCKET) > sizeof(addr.sun_path))
58                 fatal("Random pool path is too long");
59         
60         strcpy(addr.sun_path, EGD_SOCKET);
61         
62         addr_len = offsetof(struct sockaddr_un, sun_path) + sizeof(EGD_SOCKET);
63         
64         if (egd_socket == -1) {
65                 egd_socket = socket(AF_UNIX, SOCK_STREAM, 0);
66                 if (egd_socket == -1)
67                         fatal("Couldn't create AF_UNIX socket: %s", strerror(errno));
68                 if (connect(egd_socket, (struct sockaddr*)&addr, addr_len) == -1)
69                         fatal("Couldn't connect to EGD socket \"%s\": %s", addr.sun_path, strerror(errno));
70         }       
71
72         if (len > 255)
73                 fatal("Too many bytes to read from EGD");
74         
75         /* Send blocking read request to EGD */
76         egd_message[1] = len;
77
78         c = atomicio(write, egd_socket, egd_message, sizeof(egd_message));
79         if (c == -1)
80                 fatal("Couldn't write to EGD socket \"%s\": %s", EGD_SOCKET, strerror(errno));
81
82         c = atomicio(read, egd_socket, buf, len);
83         if (c <= 0)
84                 fatal("Couldn't read from EGD socket \"%s\": %s", EGD_SOCKET, strerror(errno));
85         
86         close(EGD_SOCKET);
87 }
88 #else /* !EGD_SOCKET */
89 #ifdef RANDOM_POOL
90 /* Collect entropy from /dev/urandom or pipe */
91 void get_random_bytes(unsigned char *buf, int len)
92 {
93         static int random_pool = -1;
94         int c;
95
96         if (random_pool == -1) {
97                 random_pool = open(RANDOM_POOL, O_RDONLY);
98                 if (random_pool == -1)
99                         fatal("Couldn't open random pool \"%s\": %s", RANDOM_POOL, strerror(errno));
100         }
101         
102         c = atomicio(read, random_pool, buf, len);
103         if (c <= 0)
104                 fatal("Couldn't read from random pool \"%s\": %s", RANDOM_POOL, strerror(errno));
105 }
106 #endif /* RANDOM_POOL */
107 #endif /* EGD_SOCKET */
108
109 #if !defined(EGD_SOCKET) && !defined(RANDOM_POOL)
110 /* 
111  * FIXME: proper entropy estimations. All current values are guesses
112  * FIXME: (ATL) do estimates at compile time?
113  * FIXME: More entropy sources
114  * FIXME: (ATL) bring in entropy sources from file
115  * FIXME: (ATL) add heuristic to increase the timeout if needed
116  */
117
118 /* slow command timeouts (all in milliseconds) */
119 /* static int entropy_timeout_default = ENTROPY_TIMEOUT_MSEC; */
120 static int entropy_timeout_current = ENTROPY_TIMEOUT_MSEC;
121
122 static int prng_seed_loaded = 0;
123 static int prng_seed_saved = 0;         
124
125 typedef struct
126 {
127         /* Proportion of data that is entropy */
128         double rate;
129         /* Counter goes positive if this command times out */
130         unsigned int badness;
131         /* Increases by factor of two each timeout */
132         unsigned int sticky_badness;
133         /* Path to executable */
134         const char *path;
135         /* argv to pass to executable */
136         const char *args[5];
137 } entropy_source_t;
138
139 double stir_from_system(void);
140 double stir_from_programs(void);
141 double stir_gettimeofday(double entropy_estimate);
142 double stir_clock(double entropy_estimate);
143 double stir_rusage(int who, double entropy_estimate);
144 double hash_output_from_command(entropy_source_t *src, char *hash);
145
146 entropy_source_t entropy_sources[] = {
147 #ifdef PROG_LS
148         { 0.002, 0, 1, PROG_LS,       { "ls", "-alni", "/var/log", NULL } },
149         { 0.002, 0, 1, PROG_LS,       { "ls", "-alni", "/var/adm", NULL } },
150         { 0.002, 0, 1, PROG_LS,       { "ls", "-alni", "/var/mail", NULL } },
151         { 0.002, 0, 1, PROG_LS,       { "ls", "-alni", "/var/spool/mail", NULL } },
152         { 0.002, 0, 1, PROG_LS,       { "ls", "-alni", "/proc", NULL } },
153         { 0.002, 0, 1, PROG_LS,       { "ls", "-alni", "/tmp", NULL } },
154 #endif
155 #ifdef PROG_NETSTAT
156         { 0.005, 0, 1, PROG_NETSTAT,  { "netstat","-an", NULL, NULL } },
157         { 0.010, 0, 1, PROG_NETSTAT,  { "netstat","-in", NULL, NULL } },
158         { 0.002, 0, 1, PROG_NETSTAT,  { "netstat","-rn", NULL, NULL } },
159         { 0.002, 0, 1, PROG_NETSTAT,  { "netstat","-s", NULL, NULL } },
160 #endif
161 #ifdef PROG_ARP
162         { 0.002, 0, 1, PROG_ARP,      { "arp","-a","-n", NULL } },
163 #endif
164 #ifdef PROG_IFCONFIG
165         { 0.002, 0, 1, PROG_IFCONFIG, { "ifconfig", "-a", NULL, NULL } },
166 #endif
167 #ifdef PROG_PS
168         { 0.003, 0, 1, PROG_PS,       { "ps", "laxww", NULL, NULL } },
169         { 0.003, 0, 1, PROG_PS,       { "ps", "-al", NULL, NULL } },
170         { 0.003, 0, 1, PROG_PS,       { "ps", "-efl", NULL, NULL } },
171 #endif
172 #ifdef PROG_W
173         { 0.005, 0, 1, PROG_W,        { "w", NULL, NULL, NULL } },
174 #endif
175 #ifdef PROG_WHO
176         { 0.001, 0, 1, PROG_WHO,      { "who","-i", NULL, NULL } },
177 #endif
178 #ifdef PROG_LAST
179         { 0.001, 0, 1, PROG_LAST,     { "last", NULL, NULL, NULL } },
180 #endif
181 #ifdef PROG_LASTLOG
182         { 0.001, 0, 1, PROG_LASTLOG,  { "lastlog", NULL, NULL, NULL } },
183 #endif
184 #ifdef PROG_DF
185         { 0.010, 0, 1, PROG_DF,       { "df", NULL, NULL, NULL } },
186         { 0.010, 0, 1, PROG_DF,       { "df", "-i", NULL, NULL } },
187 #endif
188 #ifdef PROG_VMSTAT
189         { 0.010, 0, 1, PROG_VMSTAT,   { "vmstat", NULL, NULL, NULL } },
190 #endif
191 #ifdef PROG_UPTIME
192         { 0.001, 0, 1, PROG_UPTIME,   { "uptime", NULL, NULL, NULL } },
193 #endif
194 #ifdef PROG_IPCS
195         { 0.001, 0, 1, PROG_IPCS,     { "-a", NULL, NULL, NULL } },
196 #endif
197 #ifdef PROG_TAIL
198         { 0.001, 0, 1, PROG_TAIL,     { "tail", "-200", "/var/log/messages", NULL, NULL } },
199         { 0.001, 0, 1, PROG_TAIL,     { "tail", "-200", "/var/log/syslog", NULL, NULL } },
200         { 0.001, 0, 1, PROG_TAIL,     { "tail", "-200", "/var/adm/messages", NULL, NULL } },
201         { 0.001, 0, 1, PROG_TAIL,     { "tail", "-200", "/var/adm/syslog", NULL, NULL } },
202         { 0.001, 0, 1, PROG_TAIL,     { "tail", "-200", "/var/log/maillog", NULL, NULL } },
203         { 0.001, 0, 1, PROG_TAIL,     { "tail", "-200", "/var/adm/maillog", NULL, NULL } },
204 #endif
205         { 0.000, 0, 0, NULL,          { NULL, NULL, NULL, NULL, NULL } },
206 };
207
208 double 
209 stir_from_system(void)
210 {
211         double total_entropy_estimate;
212         long int i;
213         
214         total_entropy_estimate = 0;
215         
216         i = getpid();
217         RAND_add(&i, sizeof(i), 0.1);
218         total_entropy_estimate += 0.1;
219         
220         i = getppid();
221         RAND_add(&i, sizeof(i), 0.1);
222         total_entropy_estimate += 0.1;
223
224         i = getuid();
225         RAND_add(&i, sizeof(i), 0.0);
226         i = getgid();
227         RAND_add(&i, sizeof(i), 0.0);
228
229         total_entropy_estimate += stir_gettimeofday(1.0);
230         total_entropy_estimate += stir_clock(0.2);
231         total_entropy_estimate += stir_rusage(RUSAGE_SELF, 2.0);
232
233         return(total_entropy_estimate);
234 }
235
236 double 
237 stir_from_programs(void)
238 {
239         int i;
240         int c;
241         double entropy_estimate;
242         double total_entropy_estimate;
243         char hash[SHA_DIGEST_LENGTH];
244
245         /*
246          * Run through list of programs twice to catch differences
247          */
248         total_entropy_estimate = 0;
249         for(i = 0; i < 2; i++) {
250                 c = 0;
251                 while (entropy_sources[c].path != NULL) {
252
253                         if (!entropy_sources[c].badness) {
254                                 /* Hash output from command */
255                                 entropy_estimate = hash_output_from_command(&entropy_sources[c], hash);
256
257                                 /* Scale back entropy estimate according to command's rate */
258                                 entropy_estimate *= entropy_sources[c].rate;
259  
260                                 /* Upper bound of entropy estimate is SHA_DIGEST_LENGTH */
261                                 if (entropy_estimate > SHA_DIGEST_LENGTH)
262                                         entropy_estimate = SHA_DIGEST_LENGTH;
263
264                         /* * Scale back estimates for subsequent passes through list */
265                                 entropy_estimate /= 10.0 * (i + 1.0);
266                         
267                                 /* Stir it in */
268                                 RAND_add(hash, sizeof(hash), entropy_estimate);
269
270 /* FIXME: turn this off later */
271 #if 1
272                                 debug("Got %0.2f bytes of entropy from %s", entropy_estimate, 
273                                         entropy_sources[c].path);
274 #endif
275
276                                 total_entropy_estimate += entropy_estimate;
277
278                         /* Execution times should be a little unpredictable */
279                                 total_entropy_estimate += stir_gettimeofday(0.05);
280                                 total_entropy_estimate += stir_clock(0.05);
281                                 total_entropy_estimate += stir_rusage(RUSAGE_SELF, 0.1);
282                                 total_entropy_estimate += stir_rusage(RUSAGE_CHILDREN, 0.1);
283                         } else {
284 /* FIXME: turn this off later */
285 #if 1
286                                 debug("Command '%s %s %s' disabled (badness %d)",
287                                         entropy_sources[c].path, entropy_sources[c].args[1],
288                                         entropy_sources[c].args[2], entropy_sources[c].badness);
289 #endif
290
291                                 if (entropy_sources[c].badness > 0)
292                                         entropy_sources[c].badness--;
293                         }
294
295                         c++;
296                 }
297         }
298         
299         return(total_entropy_estimate);
300 }
301
302 double
303 stir_gettimeofday(double entropy_estimate)
304 {
305         struct timeval tv;
306         
307         if (gettimeofday(&tv, NULL) == -1)
308                 fatal("Couldn't gettimeofday: %s", strerror(errno));
309
310         RAND_add(&tv, sizeof(tv), entropy_estimate);
311         
312         return(entropy_estimate);
313 }
314
315 double
316 stir_clock(double entropy_estimate)
317 {
318 #ifdef HAVE_CLOCK
319         clock_t c;
320         
321         c = clock();
322         RAND_add(&c, sizeof(c), entropy_estimate);
323         
324         return(entropy_estimate);
325 #else /* _HAVE_CLOCK */
326         return(0);
327 #endif /* _HAVE_CLOCK */
328 }
329
330 double
331 stir_rusage(int who, double entropy_estimate)
332 {
333 #ifdef HAVE_GETRUSAGE
334         struct rusage ru;
335         
336         if (getrusage(who, &ru) == -1)
337                 fatal("Couldn't getrusage: %s", strerror(errno));
338
339         RAND_add(&ru, sizeof(ru), 0.1);
340
341         return(entropy_estimate);
342 #else /* _HAVE_GETRUSAGE */
343         return(0);
344 #endif /* _HAVE_GETRUSAGE */
345 }
346
347 double
348 hash_output_from_command(entropy_source_t *src, char *hash)
349 {
350         static int devnull = -1;
351         int p[2];
352         fd_set rdset;
353         int cmd_eof = 0, error_abort = 0;
354         pid_t pid;
355         int status;
356         char buf[2048];
357         int bytes_read;
358         int total_bytes_read;
359         SHA_CTX sha;
360         
361         if (devnull == -1) {
362                 devnull = open("/dev/null", O_RDWR);
363                 if (devnull == -1)
364                         fatal("Couldn't open /dev/null: %s", strerror(errno));
365         }
366         
367         if (pipe(p) == -1)
368                 fatal("Couldn't open pipe: %s", strerror(errno));
369
370         switch (pid = fork()) {
371                 case -1: /* Error */
372                         close(p[0]);
373                         close(p[1]);
374                         fatal("Couldn't fork: %s", strerror(errno));
375                         /* NOTREACHED */
376                 case 0: /* Child */
377                         dup2(devnull, STDIN_FILENO);
378                         dup2(p[1], STDOUT_FILENO);
379                         dup2(p[1], STDERR_FILENO);
380                         close(p[0]);
381                         close(p[1]);
382                         close(devnull);
383
384                         execv(src->path, (char**)(src->args));
385                         debug("(child) Couldn't exec '%s %s %s': %s", src->path,
386                                 src->args[1], src->args[2], strerror(errno));
387                         src->badness = src->sticky_badness = 128;
388                         _exit(-1);
389                 default: /* Parent */
390                         break;
391         }
392
393         RAND_add(&pid, sizeof(&pid), 0.0);
394
395         close(p[1]);
396
397         /* Hash output from child */
398         SHA1_Init(&sha);
399         total_bytes_read = 0;
400
401         while (!error_abort && !cmd_eof) {
402                 int ret;
403                 struct timeval tv;
404
405                 FD_ZERO(&rdset);
406                 FD_SET(p[0], &rdset);
407                 tv.tv_sec = entropy_timeout_current / 1000;
408                 tv.tv_usec = (entropy_timeout_current % 1000) * 1000;
409
410                 ret = select(p[0]+1, &rdset, NULL, NULL, &tv);
411                 switch (ret) {
412                 case 0:
413                         /* timer expired */
414                         error_abort = 1;
415                         break;
416                         
417                 case 1:
418                         /* command input */
419                         bytes_read = read(p[0], buf, sizeof(buf));
420                         if (bytes_read == -1) {
421                                 error_abort = 1;
422                                 break;
423                         }
424                         SHA1_Update(&sha, buf, bytes_read);
425                         total_bytes_read += bytes_read;
426                         RAND_add(&bytes_read, sizeof(&bytes_read), 0.0);
427                         cmd_eof = bytes_read ? 0 : 1;
428
429                         break;
430
431                 case -1:
432                 default:
433                         error("Command '%s %s': select() failed: %s", src->path, src->args[1],
434                                 strerror(errno));
435                         error_abort = 1;
436                         break;
437                 } /* switch ret */
438
439                 RAND_add(&tv, sizeof(&tv), 0.0);
440         } /* while !error_abort && !cmd_eof */
441
442         SHA1_Final(hash, &sha);
443
444         close(p[0]);
445         
446         if (waitpid(pid, &status, 0) == -1) {
447                 error("Couldn't wait for child '%s %s' completion: %s", src->path,
448                         src->args[1], strerror(errno));
449                 /* return(-1); */ /* FIXME: (ATL) this doesn't feel right */
450                 return(0.0);
451         }
452
453         RAND_add(&status, sizeof(&status), 0.0);
454
455         if (error_abort) {
456                 /* closing p[0] on timeout causes the entropy command to
457                  * SIGPIPE. Take whatever output we got, and mark this command
458                  * as slow */
459                 debug("Command %s %s timed out", src->path, src->args[1]);
460                 src->sticky_badness *= 2;
461                 src->badness = src->sticky_badness;
462                 return(total_bytes_read);
463         }
464
465         if (WIFEXITED(status)) {
466                 if (WEXITSTATUS(status)==0) {
467                         return(total_bytes_read);
468                 } else {
469                         debug("Exit status was %d", WEXITSTATUS(status));
470                         src->badness = src->sticky_badness = 128;
471                         return (0.0);
472                 }
473         } else if (WIFSIGNALED(status)) {
474                 debug("Returned on uncaught signal %d !", status);
475                 src->badness = src->sticky_badness = 128;
476                 return(0.0);
477         } else
478                 return(0.0);
479 }
480
481 /*
482  * prng seedfile functions
483  */
484 int
485 prng_check_seedfile(char *filename) {
486
487         struct stat st;
488
489         /* FIXME raceable: eg replace seed between this stat and subsequent open */
490         /* Not such a problem because we don't trust the seed file anyway */
491         if (lstat(filename, &st) == -1) {
492                 /* Fail on hard errors */
493                 if (errno != ENOENT)
494                         fatal("Couldn't stat random seed file \"%s\": %s", filename,
495                                 strerror(errno));
496
497                 return(0);
498         }
499
500         /* regular file? */
501         if (!S_ISREG(st.st_mode))
502                 fatal("PRNG seedfile %.100s is not a regular file", filename);
503
504         /* mode 0600, owned by root or the current user? */
505         if (((st.st_mode & 0177) != 0) || !(st.st_uid == geteuid()))
506                 fatal("PRNG seedfile %.100s must be mode 0600, owned by uid %d",
507                          filename, getuid());
508
509         return(1);
510 }
511
512 void
513 prng_write_seedfile(void) {
514         int fd;
515         char seed[1024];
516         char filename[1024];
517         struct passwd *pw;
518
519         /* Don't bother if we have already saved a seed */
520         if (prng_seed_saved)
521                 return;
522         
523         prng_seed_saved = 1;
524         
525         pw = getpwuid(getuid());
526         if (pw == NULL)
527                 fatal("Couldn't get password entry for current user (%i): %s", 
528                         getuid(), strerror(errno));
529                                 
530         /* Try to ensure that the parent directory is there */
531         snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir, 
532                 SSH_USER_DIR);
533         mkdir(filename, 0700);
534
535         snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir, 
536                 SSH_PRNG_SEED_FILE);
537
538         debug("writing PRNG seed to file %.100s", filename);
539
540         RAND_bytes(seed, sizeof(seed));
541
542         /* Don't care if the seed doesn't exist */
543         prng_check_seedfile(filename);
544         
545         if ((fd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, 0600)) == -1)
546                 fatal("couldn't access PRNG seedfile %.100s (%.100s)", filename, 
547                         strerror(errno));
548         
549         if (atomicio(write, fd, &seed, sizeof(seed)) != sizeof(seed))
550                 fatal("problem writing PRNG seedfile %.100s (%.100s)", filename, 
551                          strerror(errno));
552
553         close(fd);
554 }
555
556 void
557 prng_read_seedfile(void) {
558         int fd;
559         char seed[1024];
560         char filename[1024];
561         struct passwd *pw;
562         
563         pw = getpwuid(getuid());
564         if (pw == NULL)
565                 fatal("Couldn't get password entry for current user (%i): %s", 
566                         getuid(), strerror(errno));
567                         
568         snprintf(filename, sizeof(filename), "%.512s/%s", pw->pw_dir, 
569                 SSH_PRNG_SEED_FILE);
570
571         debug("loading PRNG seed from file %.100s", filename);
572
573         if (!prng_check_seedfile(filename)) {
574                 verbose("Random seed file not found, creating new");
575                 prng_write_seedfile();
576                 
577                 /* Reseed immediatly */
578                 (void)stir_from_system();
579                 (void)stir_from_programs();
580                 return;
581         }
582
583         /* open the file and read in the seed */
584         fd = open(filename, O_RDONLY);
585         if (fd == -1)
586                 fatal("could not open PRNG seedfile %.100s (%.100s)", filename, 
587                         strerror(errno));
588
589         if (atomicio(read, fd, &seed, sizeof(seed)) != sizeof(seed)) {
590                 verbose("invalid or short read from PRNG seedfile %.100s - ignoring",
591                         filename);
592                 memset(seed, '\0', sizeof(seed));
593         }
594         close(fd);
595
596         /* stir in the seed, with estimated entropy zero */
597         RAND_add(&seed, sizeof(seed), 0.0);
598 }
599
600 #endif /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */
601
602 #if defined(EGD_SOCKET) || defined(RANDOM_POOL)
603
604 /*
605  * Seed OpenSSL's random number pool from Kernel random number generator
606  * or EGD
607  */
608 void
609 seed_rng(void)
610 {
611         char buf[32];
612         
613         debug("Seeding random number generator");
614         get_random_bytes(buf, sizeof(buf));
615         RAND_add(buf, sizeof(buf), sizeof(buf));
616         memset(buf, '\0', sizeof(buf));
617 }
618
619 #else /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */
620
621 /*
622  * Write a keyfile at exit
623  */ 
624 void
625 prng_seed_cleanup(void *junk)
626 {
627         prng_write_seedfile();
628 }
629
630 /*
631  * Conditionally Seed OpenSSL's random number pool from
632  * syscalls and program output
633  */
634 void
635 seed_rng(void)
636 {
637         debug("Seeding random number generator.");
638         debug("OpenSSL random status is now %i\n", RAND_status());
639         debug("%i bytes from system calls", (int)stir_from_system());
640         debug("%i bytes from programs", (int)stir_from_programs());
641         debug("OpenSSL random status is now %i\n", RAND_status());
642
643         if (!prng_seed_loaded)
644         {
645                 prng_seed_loaded = 1;
646                 prng_seed_saved = 0;            
647                 prng_read_seedfile();
648                 fatal_add_cleanup(prng_seed_cleanup, NULL);
649                 atexit(prng_write_seedfile);
650         }
651 }
652 #endif /* defined(EGD_SOCKET) || defined(RANDOM_POOL) */
This page took 0.086697 seconds and 5 git commands to generate.