comparison nss/lib/freebl/unix_rand.c @ 0:1e5118fa0cb1

This is NSS with a Cmake Buildsyste To compile a static NSS library for Windows we've used the Chromium-NSS fork and added a Cmake buildsystem to compile it statically for Windows. See README.chromium for chromium changes and README.trustbridge for our modifications.
author Andre Heinecke <andre.heinecke@intevation.de>
date Mon, 28 Jul 2014 10:47:06 +0200
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:1e5118fa0cb1
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5 #include <stdio.h>
6 #include <string.h>
7 #include <signal.h>
8 #include <unistd.h>
9 #include <limits.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 #include <sys/time.h>
13 #include <sys/wait.h>
14 #include <sys/stat.h>
15 #include "secrng.h"
16 #include "secerr.h"
17 #include "prerror.h"
18 #include "prthread.h"
19 #include "prprf.h"
20
21 size_t RNG_FileUpdate(const char *fileName, size_t limit);
22
23 /*
24 * When copying data to the buffer we want the least signicant bytes
25 * from the input since those bits are changing the fastest. The address
26 * of least significant byte depends upon whether we are running on
27 * a big-endian or little-endian machine.
28 *
29 * Does this mean the least signicant bytes are the most significant
30 * to us? :-)
31 */
32
33 static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
34 {
35 union endianness {
36 PRInt32 i;
37 char c[4];
38 } u;
39
40 if (srclen <= dstlen) {
41 memcpy(dst, src, srclen);
42 return srclen;
43 }
44 u.i = 0x01020304;
45 if (u.c[0] == 0x01) {
46 /* big-endian case */
47 memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
48 } else {
49 /* little-endian case */
50 memcpy(dst, src, dstlen);
51 }
52 return dstlen;
53 }
54
55 #ifdef SOLARIS
56
57 #include <kstat.h>
58
59 static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */
60
61 /* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time.
62 * Returns error if RNG_RandomUpdate fails. Also increments *total_fed
63 * by the number of bytes successfully buffered.
64 */
65 static SECStatus BufferEntropy(char* inbuf, PRUint32 inlen,
66 char* entropy_buf, PRUint32* entropy_buffered,
67 PRUint32* total_fed)
68 {
69 PRUint32 tocopy = 0;
70 PRUint32 avail = 0;
71 SECStatus rv = SECSuccess;
72
73 while (inlen) {
74 avail = entropy_buf_len - *entropy_buffered;
75 if (!avail) {
76 /* Buffer is full, time to feed it to the RNG. */
77 rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len);
78 if (SECSuccess != rv) {
79 break;
80 }
81 *entropy_buffered = 0;
82 avail = entropy_buf_len;
83 }
84 tocopy = PR_MIN(avail, inlen);
85 memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy);
86 *entropy_buffered += tocopy;
87 inlen -= tocopy;
88 inbuf += tocopy;
89 *total_fed += tocopy;
90 }
91 return rv;
92 }
93
94 /* Feed kernel statistics structures and ks_data field to the RNG.
95 * Returns status as well as the number of bytes successfully fed to the RNG.
96 */
97 static SECStatus RNG_kstat(PRUint32* fed)
98 {
99 kstat_ctl_t* kc = NULL;
100 kstat_t* ksp = NULL;
101 PRUint32 entropy_buffered = 0;
102 char* entropy_buf = NULL;
103 SECStatus rv = SECSuccess;
104
105 PORT_Assert(fed);
106 if (!fed) {
107 return SECFailure;
108 }
109 *fed = 0;
110
111 kc = kstat_open();
112 PORT_Assert(kc);
113 if (!kc) {
114 return SECFailure;
115 }
116 entropy_buf = (char*) PORT_Alloc(entropy_buf_len);
117 PORT_Assert(entropy_buf);
118 if (entropy_buf) {
119 for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
120 if (-1 == kstat_read(kc, ksp, NULL)) {
121 /* missing data from a single kstat shouldn't be fatal */
122 continue;
123 }
124 rv = BufferEntropy((char*)ksp, sizeof(kstat_t),
125 entropy_buf, &entropy_buffered,
126 fed);
127 if (SECSuccess != rv) {
128 break;
129 }
130
131 if (ksp->ks_data && ksp->ks_data_size>0 && ksp->ks_ndata>0) {
132 rv = BufferEntropy((char*)ksp->ks_data, ksp->ks_data_size,
133 entropy_buf, &entropy_buffered,
134 fed);
135 if (SECSuccess != rv) {
136 break;
137 }
138 }
139 }
140 if (SECSuccess == rv && entropy_buffered) {
141 /* Buffer is not empty, time to feed it to the RNG */
142 rv = RNG_RandomUpdate(entropy_buf, entropy_buffered);
143 }
144 PORT_Free(entropy_buf);
145 } else {
146 rv = SECFailure;
147 }
148 if (kstat_close(kc)) {
149 PORT_Assert(0);
150 rv = SECFailure;
151 }
152 return rv;
153 }
154
155 #endif
156
157 #if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \
158 || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) \
159 || defined(NTO) || defined(__riscos__)
160 #include <sys/times.h>
161
162 #define getdtablesize() sysconf(_SC_OPEN_MAX)
163
164 static size_t
165 GetHighResClock(void *buf, size_t maxbytes)
166 {
167 int ticks;
168 struct tms buffer;
169
170 ticks=times(&buffer);
171 return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
172 }
173
174 static void
175 GiveSystemInfo(void)
176 {
177 long si;
178
179 /*
180 * Is this really necessary? Why not use rand48 or something?
181 */
182 si = sysconf(_SC_CHILD_MAX);
183 RNG_RandomUpdate(&si, sizeof(si));
184
185 si = sysconf(_SC_STREAM_MAX);
186 RNG_RandomUpdate(&si, sizeof(si));
187
188 si = sysconf(_SC_OPEN_MAX);
189 RNG_RandomUpdate(&si, sizeof(si));
190 }
191 #endif
192
193 #if defined(__sun)
194 #if defined(__svr4) || defined(SVR4)
195 #include <sys/systeminfo.h>
196
197 #define getdtablesize() sysconf(_SC_OPEN_MAX)
198
199 static void
200 GiveSystemInfo(void)
201 {
202 int rv;
203 char buf[2000];
204
205 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
206 if (rv > 0) {
207 RNG_RandomUpdate(buf, rv);
208 }
209 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
210 if (rv > 0) {
211 RNG_RandomUpdate(buf, rv);
212 }
213 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
214 if (rv > 0) {
215 RNG_RandomUpdate(buf, rv);
216 }
217 }
218
219 static size_t
220 GetHighResClock(void *buf, size_t maxbytes)
221 {
222 hrtime_t t;
223 t = gethrtime();
224 if (t) {
225 return CopyLowBits(buf, maxbytes, &t, sizeof(t));
226 }
227 return 0;
228 }
229 #else /* SunOS (Sun, but not SVR4) */
230
231 extern long sysconf(int name);
232
233 static size_t
234 GetHighResClock(void *buf, size_t maxbytes)
235 {
236 return 0;
237 }
238
239 static void
240 GiveSystemInfo(void)
241 {
242 long si;
243
244 /* This is not very good */
245 si = sysconf(_SC_CHILD_MAX);
246 RNG_RandomUpdate(&si, sizeof(si));
247 }
248 #endif
249 #endif /* Sun */
250
251 #if defined(__hpux)
252 #include <sys/unistd.h>
253
254 #define getdtablesize() sysconf(_SC_OPEN_MAX)
255
256 #if defined(__ia64)
257 #include <ia64/sys/inline.h>
258
259 static size_t
260 GetHighResClock(void *buf, size_t maxbytes)
261 {
262 PRUint64 t;
263
264 t = _Asm_mov_from_ar(_AREG44);
265 return CopyLowBits(buf, maxbytes, &t, sizeof(t));
266 }
267 #else
268 static size_t
269 GetHighResClock(void *buf, size_t maxbytes)
270 {
271 extern int ret_cr16();
272 int cr16val;
273
274 cr16val = ret_cr16();
275 return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val));
276 }
277 #endif
278
279 static void
280 GiveSystemInfo(void)
281 {
282 long si;
283
284 /* This is not very good */
285 si = sysconf(_AES_OS_VERSION);
286 RNG_RandomUpdate(&si, sizeof(si));
287 si = sysconf(_SC_CPU_VERSION);
288 RNG_RandomUpdate(&si, sizeof(si));
289 }
290 #endif /* HPUX */
291
292 #if defined(OSF1)
293 #include <sys/types.h>
294 #include <sys/sysinfo.h>
295 #include <sys/systeminfo.h>
296 #include <c_asm.h>
297
298 static void
299 GiveSystemInfo(void)
300 {
301 char buf[BUFSIZ];
302 int rv;
303 int off = 0;
304
305 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
306 if (rv > 0) {
307 RNG_RandomUpdate(buf, rv);
308 }
309 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
310 if (rv > 0) {
311 RNG_RandomUpdate(buf, rv);
312 }
313 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
314 if (rv > 0) {
315 RNG_RandomUpdate(buf, rv);
316 }
317 }
318
319 /*
320 * Use the "get the cycle counter" instruction on the alpha.
321 * The low 32 bits completely turn over in less than a minute.
322 * The high 32 bits are some non-counter gunk that changes sometimes.
323 */
324 static size_t
325 GetHighResClock(void *buf, size_t maxbytes)
326 {
327 unsigned long t;
328
329 t = asm("rpcc %v0");
330 return CopyLowBits(buf, maxbytes, &t, sizeof(t));
331 }
332
333 #endif /* Alpha */
334
335 #if defined(_IBMR2)
336 static size_t
337 GetHighResClock(void *buf, size_t maxbytes)
338 {
339 return 0;
340 }
341
342 static void
343 GiveSystemInfo(void)
344 {
345 /* XXX haven't found any yet! */
346 }
347 #endif /* IBM R2 */
348
349 #if defined(LINUX)
350 #include <sys/sysinfo.h>
351
352 static size_t
353 GetHighResClock(void *buf, size_t maxbytes)
354 {
355 return 0;
356 }
357
358 static void
359 GiveSystemInfo(void)
360 {
361 #ifndef NO_SYSINFO
362 struct sysinfo si;
363 if (sysinfo(&si) == 0) {
364 RNG_RandomUpdate(&si, sizeof(si));
365 }
366 #endif
367 }
368 #endif /* LINUX */
369
370 #if defined(NCR)
371
372 #include <sys/utsname.h>
373 #include <sys/systeminfo.h>
374
375 #define getdtablesize() sysconf(_SC_OPEN_MAX)
376
377 static size_t
378 GetHighResClock(void *buf, size_t maxbytes)
379 {
380 return 0;
381 }
382
383 static void
384 GiveSystemInfo(void)
385 {
386 int rv;
387 char buf[2000];
388
389 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
390 if (rv > 0) {
391 RNG_RandomUpdate(buf, rv);
392 }
393 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
394 if (rv > 0) {
395 RNG_RandomUpdate(buf, rv);
396 }
397 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
398 if (rv > 0) {
399 RNG_RandomUpdate(buf, rv);
400 }
401 }
402
403 #endif /* NCR */
404
405 #if defined(sgi)
406 #include <fcntl.h>
407 #undef PRIVATE
408 #include <sys/mman.h>
409 #include <sys/syssgi.h>
410 #include <sys/immu.h>
411 #include <sys/systeminfo.h>
412 #include <sys/utsname.h>
413 #include <wait.h>
414
415 static void
416 GiveSystemInfo(void)
417 {
418 int rv;
419 char buf[4096];
420
421 rv = syssgi(SGI_SYSID, &buf[0]);
422 if (rv > 0) {
423 RNG_RandomUpdate(buf, MAXSYSIDSIZE);
424 }
425 #ifdef SGI_RDUBLK
426 rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf));
427 if (rv > 0) {
428 RNG_RandomUpdate(buf, sizeof(buf));
429 }
430 #endif /* SGI_RDUBLK */
431 rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf));
432 if (rv > 0) {
433 RNG_RandomUpdate(buf, sizeof(buf));
434 }
435 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
436 if (rv > 0) {
437 RNG_RandomUpdate(buf, rv);
438 }
439 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
440 if (rv > 0) {
441 RNG_RandomUpdate(buf, rv);
442 }
443 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
444 if (rv > 0) {
445 RNG_RandomUpdate(buf, rv);
446 }
447 }
448
449 static size_t GetHighResClock(void *buf, size_t maxbuf)
450 {
451 unsigned phys_addr, raddr, cycleval;
452 static volatile unsigned *iotimer_addr = NULL;
453 static int tries = 0;
454 static int cntr_size;
455 int mfd;
456 long s0[2];
457 struct timeval tv;
458
459 #ifndef SGI_CYCLECNTR_SIZE
460 #define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */
461 #endif
462
463 if (iotimer_addr == NULL) {
464 if (tries++ > 1) {
465 /* Don't keep trying if it didn't work */
466 return 0;
467 }
468
469 /*
470 ** For SGI machines we can use the cycle counter, if it has one,
471 ** to generate some truly random numbers
472 */
473 phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
474 if (phys_addr) {
475 int pgsz = getpagesize();
476 int pgoffmask = pgsz - 1;
477
478 raddr = phys_addr & ~pgoffmask;
479 mfd = open("/dev/mmem", O_RDONLY);
480 if (mfd < 0) {
481 return 0;
482 }
483 iotimer_addr = (unsigned *)
484 mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
485 if (iotimer_addr == (void*)-1) {
486 close(mfd);
487 iotimer_addr = NULL;
488 return 0;
489 }
490 iotimer_addr = (unsigned*)
491 ((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
492 /*
493 * The file 'mfd' is purposefully not closed.
494 */
495 cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
496 if (cntr_size < 0) {
497 struct utsname utsinfo;
498
499 /*
500 * We must be executing on a 6.0 or earlier system, since the
501 * SGI_CYCLECNTR_SIZE call is not supported.
502 *
503 * The only pre-6.1 platforms with 64-bit counters are
504 * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
505 */
506 uname(&utsinfo);
507 if (!strncmp(utsinfo.machine, "IP19", 4) ||
508 !strncmp(utsinfo.machine, "IP21", 4))
509 cntr_size = 64;
510 else
511 cntr_size = 32;
512 }
513 cntr_size /= 8; /* Convert from bits to bytes */
514 }
515 }
516
517 s0[0] = *iotimer_addr;
518 if (cntr_size > 4)
519 s0[1] = *(iotimer_addr + 1);
520 memcpy(buf, (char *)&s0[0], cntr_size);
521 return CopyLowBits(buf, maxbuf, &s0, cntr_size);
522 }
523 #endif
524
525 #if defined(sony)
526 #include <sys/systeminfo.h>
527
528 #define getdtablesize() sysconf(_SC_OPEN_MAX)
529
530 static size_t
531 GetHighResClock(void *buf, size_t maxbytes)
532 {
533 return 0;
534 }
535
536 static void
537 GiveSystemInfo(void)
538 {
539 int rv;
540 char buf[2000];
541
542 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
543 if (rv > 0) {
544 RNG_RandomUpdate(buf, rv);
545 }
546 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
547 if (rv > 0) {
548 RNG_RandomUpdate(buf, rv);
549 }
550 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
551 if (rv > 0) {
552 RNG_RandomUpdate(buf, rv);
553 }
554 }
555 #endif /* sony */
556
557 #if defined(sinix)
558 #include <sys/systeminfo.h>
559 #include <sys/times.h>
560
561 int gettimeofday(struct timeval *, struct timezone *);
562 int gethostname(char *, int);
563
564 #define getdtablesize() sysconf(_SC_OPEN_MAX)
565
566 static size_t
567 GetHighResClock(void *buf, size_t maxbytes)
568 {
569 int ticks;
570 struct tms buffer;
571
572 ticks=times(&buffer);
573 return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
574 }
575
576 static void
577 GiveSystemInfo(void)
578 {
579 int rv;
580 char buf[2000];
581
582 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
583 if (rv > 0) {
584 RNG_RandomUpdate(buf, rv);
585 }
586 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
587 if (rv > 0) {
588 RNG_RandomUpdate(buf, rv);
589 }
590 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
591 if (rv > 0) {
592 RNG_RandomUpdate(buf, rv);
593 }
594 }
595 #endif /* sinix */
596
597
598 #ifdef BEOS
599 #include <be/kernel/OS.h>
600
601 static size_t
602 GetHighResClock(void *buf, size_t maxbytes)
603 {
604 bigtime_t bigtime; /* Actually a int64 */
605
606 bigtime = real_time_clock_usecs();
607 return CopyLowBits(buf, maxbytes, &bigtime, sizeof(bigtime));
608 }
609
610 static void
611 GiveSystemInfo(void)
612 {
613 system_info *info = NULL;
614 PRInt32 val;
615 get_system_info(info);
616 if (info) {
617 val = info->boot_time;
618 RNG_RandomUpdate(&val, sizeof(val));
619 val = info->used_pages;
620 RNG_RandomUpdate(&val, sizeof(val));
621 val = info->used_ports;
622 RNG_RandomUpdate(&val, sizeof(val));
623 val = info->used_threads;
624 RNG_RandomUpdate(&val, sizeof(val));
625 val = info->used_teams;
626 RNG_RandomUpdate(&val, sizeof(val));
627 }
628 }
629 #endif /* BEOS */
630
631 #if defined(nec_ews)
632 #include <sys/systeminfo.h>
633
634 #define getdtablesize() sysconf(_SC_OPEN_MAX)
635
636 static size_t
637 GetHighResClock(void *buf, size_t maxbytes)
638 {
639 return 0;
640 }
641
642 static void
643 GiveSystemInfo(void)
644 {
645 int rv;
646 char buf[2000];
647
648 rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
649 if (rv > 0) {
650 RNG_RandomUpdate(buf, rv);
651 }
652 rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
653 if (rv > 0) {
654 RNG_RandomUpdate(buf, rv);
655 }
656 rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
657 if (rv > 0) {
658 RNG_RandomUpdate(buf, rv);
659 }
660 }
661 #endif /* nec_ews */
662
663 size_t RNG_GetNoise(void *buf, size_t maxbytes)
664 {
665 struct timeval tv;
666 int n = 0;
667 int c;
668
669 n = GetHighResClock(buf, maxbytes);
670 maxbytes -= n;
671
672 (void)gettimeofday(&tv, 0);
673 c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
674 n += c;
675 maxbytes -= c;
676 c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
677 n += c;
678 return n;
679 }
680
681 #define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */
682
683 /*
684 * safe_popen is static to this module and we know what arguments it is
685 * called with. Note that this version only supports a single open child
686 * process at any time.
687 */
688 static pid_t safe_popen_pid;
689 static struct sigaction oldact;
690
691 static FILE *
692 safe_popen(char *cmd)
693 {
694 int p[2], fd, argc;
695 pid_t pid;
696 char *argv[SAFE_POPEN_MAXARGS + 1];
697 FILE *fp;
698 static char blank[] = " \t";
699 static struct sigaction newact;
700
701 if (pipe(p) < 0)
702 return 0;
703
704 fp = fdopen(p[0], "r");
705 if (fp == 0) {
706 close(p[0]);
707 close(p[1]);
708 return 0;
709 }
710
711 /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
712 newact.sa_handler = SIG_DFL;
713 newact.sa_flags = 0;
714 sigfillset(&newact.sa_mask);
715 sigaction (SIGCHLD, &newact, &oldact);
716
717 pid = fork();
718 switch (pid) {
719 int ndesc;
720
721 case -1:
722 fclose(fp); /* this closes p[0], the fd associated with fp */
723 close(p[1]);
724 sigaction (SIGCHLD, &oldact, NULL);
725 return 0;
726
727 case 0:
728 /* dup write-side of pipe to stderr and stdout */
729 if (p[1] != 1) dup2(p[1], 1);
730 if (p[1] != 2) dup2(p[1], 2);
731
732 /*
733 * close the other file descriptors, except stdin which we
734 * try reassociating with /dev/null, first (bug 174993)
735 */
736 if (!freopen("/dev/null", "r", stdin))
737 close(0);
738 ndesc = getdtablesize();
739 for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd));
740
741 /* clean up environment in the child process */
742 putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
743 putenv("SHELL=/bin/sh");
744 putenv("IFS= \t");
745
746 /*
747 * The caller may have passed us a string that is in text
748 * space. It may be illegal to modify the string
749 */
750 cmd = strdup(cmd);
751 /* format argv */
752 argv[0] = strtok(cmd, blank);
753 argc = 1;
754 while ((argv[argc] = strtok(0, blank)) != 0) {
755 if (++argc == SAFE_POPEN_MAXARGS) {
756 argv[argc] = 0;
757 break;
758 }
759 }
760
761 /* and away we go */
762 execvp(argv[0], argv);
763 exit(127);
764 break;
765
766 default:
767 close(p[1]);
768 break;
769 }
770
771 /* non-zero means there's a cmd running */
772 safe_popen_pid = pid;
773 return fp;
774 }
775
776 static int
777 safe_pclose(FILE *fp)
778 {
779 pid_t pid;
780 int status = -1, rv;
781
782 if ((pid = safe_popen_pid) == 0)
783 return -1;
784 safe_popen_pid = 0;
785
786 fclose(fp);
787
788 /* yield the processor so the child gets some time to exit normally */
789 PR_Sleep(PR_INTERVAL_NO_WAIT);
790
791 /* if the child hasn't exited, kill it -- we're done with its output */
792 while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR)
793 ;
794 if (rv == 0) {
795 kill(pid, SIGKILL);
796 while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
797 ;
798 }
799
800 /* Reset SIGCHLD signal hander before returning */
801 sigaction(SIGCHLD, &oldact, NULL);
802
803 return status;
804 }
805
806 #ifdef DARWIN
807 #include <TargetConditionals.h>
808 #if !TARGET_OS_IPHONE
809 #include <crt_externs.h>
810 #endif
811 #endif
812
813 /* Fork netstat to collect its output by default. Do not unset this unless
814 * another source of entropy is available
815 */
816 #define DO_NETSTAT 1
817
818 void RNG_SystemInfoForRNG(void)
819 {
820 FILE *fp;
821 char buf[BUFSIZ];
822 size_t bytes;
823 const char * const *cp;
824 char *randfile;
825 #ifdef DARWIN
826 #if TARGET_OS_IPHONE
827 /* iOS does not expose a way to access environ. */
828 char **environ = NULL;
829 #else
830 char **environ = *_NSGetEnviron();
831 #endif
832 #else
833 extern char **environ;
834 #endif
835 #ifdef BEOS
836 static const char * const files[] = {
837 "/boot/var/swap",
838 "/boot/var/log/syslog",
839 "/boot/var/tmp",
840 "/boot/home/config/settings",
841 "/boot/home",
842 0
843 };
844 #else
845 static const char * const files[] = {
846 "/etc/passwd",
847 "/etc/utmp",
848 "/tmp",
849 "/var/tmp",
850 "/usr/tmp",
851 0
852 };
853 #endif
854
855 #if defined(BSDI)
856 static char netstat_ni_cmd[] = "netstat -nis";
857 #else
858 static char netstat_ni_cmd[] = "netstat -ni";
859 #endif
860
861 GiveSystemInfo();
862
863 bytes = RNG_GetNoise(buf, sizeof(buf));
864 RNG_RandomUpdate(buf, bytes);
865
866 /*
867 * Pass the C environment and the addresses of the pointers to the
868 * hash function. This makes the random number function depend on the
869 * execution environment of the user and on the platform the program
870 * is running on.
871 */
872 if (environ != NULL) {
873 cp = (const char * const *) environ;
874 while (*cp) {
875 RNG_RandomUpdate(*cp, strlen(*cp));
876 cp++;
877 }
878 RNG_RandomUpdate(environ, (char*)cp - (char*)environ);
879 }
880
881 /* Give in system information */
882 if (gethostname(buf, sizeof(buf)) == 0) {
883 RNG_RandomUpdate(buf, strlen(buf));
884 }
885 GiveSystemInfo();
886
887 /* grab some data from system's PRNG before any other files. */
888 bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);
889
890 /* If the user points us to a random file, pass it through the rng */
891 randfile = getenv("NSRANDFILE");
892 if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) {
893 char *randCountString = getenv("NSRANDCOUNT");
894 int randCount = randCountString ? atoi(randCountString) : 0;
895 if (randCount != 0) {
896 RNG_FileUpdate(randfile, randCount);
897 } else {
898 RNG_FileForRNG(randfile);
899 }
900 }
901
902 /* pass other files through */
903 for (cp = files; *cp; cp++)
904 RNG_FileForRNG(*cp);
905
906 /*
907 * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen
908 * in a pthreads environment. Therefore, we call safe_popen last and on
909 * BSD/OS we do not call safe_popen when we succeeded in getting data
910 * from /dev/urandom.
911 *
912 * Bug 174993: On platforms providing /dev/urandom, don't fork netstat
913 * either, if data has been gathered successfully.
914 */
915
916 #if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \
917 || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) \
918 || defined(HPUX)
919 if (bytes == SYSTEM_RNG_SEED_COUNT)
920 return;
921
922 /*
923 * Modified to abort the process if it failed to read from /dev/urandom.
924 *
925 * See crbug.com/244661 for details.
926 */
927 fprintf(stderr, "[ERROR:%s(%d)] NSS read %zu bytes (expected %d bytes) "
928 "from /dev/urandom. Abort process.\n", __FILE__, __LINE__,
929 bytes, SYSTEM_RNG_SEED_COUNT);
930 fflush(stderr);
931 abort();
932 #endif
933
934 #ifdef SOLARIS
935
936 /*
937 * On Solaris, NSS may be initialized automatically from libldap in
938 * applications that are unaware of the use of NSS. safe_popen forks, and
939 * sometimes creates issues with some applications' pthread_atfork handlers.
940 * We always have /dev/urandom on Solaris 9 and above as an entropy source,
941 * and for Solaris 8 we have the libkstat interface, so we don't need to
942 * fork netstat.
943 */
944
945 #undef DO_NETSTAT
946 if (!bytes) {
947 /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
948 PRUint32 kstat_bytes = 0;
949 if (SECSuccess != RNG_kstat(&kstat_bytes)) {
950 PORT_Assert(0);
951 }
952 bytes += kstat_bytes;
953 PORT_Assert(bytes);
954 }
955 #endif
956
957 #ifdef DO_NETSTAT
958 fp = safe_popen(netstat_ni_cmd);
959 if (fp != NULL) {
960 while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
961 RNG_RandomUpdate(buf, bytes);
962 safe_pclose(fp);
963 }
964 #endif
965
966 }
967
968 #define TOTAL_FILE_LIMIT 1000000 /* one million */
969
970 size_t RNG_FileUpdate(const char *fileName, size_t limit)
971 {
972 FILE * file;
973 int fd;
974 int bytes;
975 size_t fileBytes = 0;
976 struct stat stat_buf;
977 unsigned char buffer[BUFSIZ];
978 static size_t totalFileBytes = 0;
979
980 /* suppress valgrind warnings due to holes in struct stat */
981 memset(&stat_buf, 0, sizeof(stat_buf));
982
983 if (stat((char *)fileName, &stat_buf) < 0)
984 return fileBytes;
985 RNG_RandomUpdate(&stat_buf, sizeof(stat_buf));
986
987 file = fopen(fileName, "r");
988 if (file != NULL) {
989 /* Read from the underlying file descriptor directly to bypass stdio
990 * buffering and avoid reading more bytes than we need from
991 * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because
992 * fread may return EOF in unbuffered I/O mode on Android.
993 *
994 * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O
995 * has no performance advantage. */
996 fd = fileno(file);
997 /* 'file' was just opened, so this should not fail. */
998 PORT_Assert(fd != -1);
999 while (limit > fileBytes) {
1000 bytes = PR_MIN(sizeof buffer, limit - fileBytes);
1001 bytes = read(fd, buffer, bytes);
1002 if (bytes <= 0)
1003 break;
1004 RNG_RandomUpdate(buffer, bytes);
1005 fileBytes += bytes;
1006 totalFileBytes += bytes;
1007 /* after TOTAL_FILE_LIMIT has been reached, only read in first
1008 ** buffer of data from each subsequent file.
1009 */
1010 if (totalFileBytes > TOTAL_FILE_LIMIT)
1011 break;
1012 }
1013 fclose(file);
1014 }
1015 /*
1016 * Pass yet another snapshot of our highest resolution clock into
1017 * the hash function.
1018 */
1019 bytes = RNG_GetNoise(buffer, sizeof(buffer));
1020 RNG_RandomUpdate(buffer, bytes);
1021 return fileBytes;
1022 }
1023
1024 void RNG_FileForRNG(const char *fileName)
1025 {
1026 RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT);
1027 }
1028
1029 void ReadSingleFile(const char *fileName)
1030 {
1031 FILE * file;
1032 unsigned char buffer[BUFSIZ];
1033
1034 file = fopen(fileName, "rb");
1035 if (file != NULL) {
1036 while (fread(buffer, 1, sizeof(buffer), file) > 0)
1037 ;
1038 fclose(file);
1039 }
1040 }
1041
1042 #define _POSIX_PTHREAD_SEMANTICS
1043 #include <dirent.h>
1044
1045 PRBool
1046 ReadFileOK(char *dir, char *file)
1047 {
1048 struct stat stat_buf;
1049 char filename[PATH_MAX];
1050 int count = snprintf(filename, sizeof filename, "%s/%s",dir, file);
1051
1052 if (count <= 0) {
1053 return PR_FALSE; /* name too long, can't read it anyway */
1054 }
1055
1056 if (stat(filename, &stat_buf) < 0)
1057 return PR_FALSE; /* can't stat, probably can't read it then as well */
1058 return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE;
1059 }
1060
1061 /*
1062 * read one file out of either /etc or the user's home directory.
1063 * fileToRead tells which file to read.
1064 *
1065 * return 1 if it's time to reset the fileToRead (no more files to read).
1066 */
1067 int ReadOneFile(int fileToRead)
1068 {
1069 char *dir = "/etc";
1070 DIR *fd = opendir(dir);
1071 int resetCount = 0;
1072 #ifdef SOLARIS
1073 /* grumble, Solaris does not define struct dirent to be the full length */
1074 typedef union {
1075 unsigned char space[sizeof(struct dirent) + MAXNAMELEN];
1076 struct dirent dir;
1077 } dirent_hack;
1078 dirent_hack entry, firstEntry;
1079
1080 #define entry_dir entry.dir
1081 #else
1082 struct dirent entry, firstEntry;
1083 #define entry_dir entry
1084 #endif
1085
1086 int i, error = -1;
1087
1088 if (fd == NULL) {
1089 dir = getenv("HOME");
1090 if (dir) {
1091 fd = opendir(dir);
1092 }
1093 }
1094 if (fd == NULL) {
1095 return 1;
1096 }
1097
1098 for (i=0; i <= fileToRead; i++) {
1099 struct dirent *result = NULL;
1100 do {
1101 error = readdir_r(fd, &entry_dir, &result);
1102 } while (error == 0 && result != NULL &&
1103 !ReadFileOK(dir,&result->d_name[0]));
1104 if (error != 0 || result == NULL) {
1105 resetCount = 1; /* read to the end, start again at the beginning */
1106 if (i != 0) {
1107 /* ran out of entries in the directory, use the first one */
1108 entry = firstEntry;
1109 error = 0;
1110 break;
1111 }
1112 /* if i== 0, there were no readable entries in the directory */
1113 break;
1114 }
1115 if (i==0) {
1116 /* save the first entry in case we run out of entries */
1117 firstEntry = entry;
1118 }
1119 }
1120
1121 if (error == 0) {
1122 char filename[PATH_MAX];
1123 int count = snprintf(filename, sizeof filename,
1124 "%s/%s",dir, &entry_dir.d_name[0]);
1125 if (count >= 1) {
1126 ReadSingleFile(filename);
1127 }
1128 }
1129
1130 closedir(fd);
1131 return resetCount;
1132 }
1133
1134 /*
1135 * do something to try to introduce more noise into the 'GetNoise' call
1136 */
1137 static void rng_systemJitter(void)
1138 {
1139 static int fileToRead = 1;
1140
1141 if (ReadOneFile(fileToRead)) {
1142 fileToRead = 1;
1143 } else {
1144 fileToRead++;
1145 }
1146 }
1147
1148 /*
1149 * Modified to abort the process if it failed to read from /dev/urandom.
1150 *
1151 * See crbug.com/244661 for details.
1152 */
1153 size_t RNG_SystemRNG(void *dest, size_t maxLen)
1154 {
1155 FILE *file;
1156 int fd;
1157 int bytes;
1158 size_t fileBytes = 0;
1159 unsigned char *buffer = dest;
1160
1161 file = fopen("/dev/urandom", "r");
1162 if (file == NULL) {
1163 fprintf(stderr, "[ERROR:%s(%d)] NSS failed to read from /dev/urandom. "
1164 "Abort process.\n", __FILE__, __LINE__);
1165 fflush(stderr);
1166 abort();
1167 }
1168 /* Read from the underlying file descriptor directly to bypass stdio
1169 * buffering and avoid reading more bytes than we need from /dev/urandom.
1170 * NOTE: we can't use fread with unbuffered I/O because fread may return
1171 * EOF in unbuffered I/O mode on Android.
1172 */
1173 fd = fileno(file);
1174 /* 'file' was just opened, so this should not fail. */
1175 PORT_Assert(fd != -1);
1176 while (maxLen > fileBytes) {
1177 bytes = maxLen - fileBytes;
1178 bytes = read(fd, buffer, bytes);
1179 if (bytes <= 0)
1180 break;
1181 fileBytes += bytes;
1182 buffer += bytes;
1183 }
1184 fclose(file);
1185 if (fileBytes != maxLen) {
1186 fprintf(stderr, "[ERROR:%s(%d)] NSS failed to read from /dev/urandom. "
1187 "Abort process.\n", __FILE__, __LINE__);
1188 fflush(stderr);
1189 abort();
1190 }
1191 return fileBytes;
1192 }
This site is hosted by Intevation GmbH (Datenschutzerklärung und Impressum | Privacy Policy and Imprint)