Index: mozilla/security/nss/lib/freebl/unix_rand.c |
=================================================================== |
--- mozilla/security/nss/lib/freebl/unix_rand.c (revision 191424) |
+++ mozilla/security/nss/lib/freebl/unix_rand.c (working copy) |
@@ -1,1151 +0,0 @@ |
-/* This Source Code Form is subject to the terms of the Mozilla Public |
- * License, v. 2.0. If a copy of the MPL was not distributed with this |
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
- |
-#include <stdio.h> |
-#include <string.h> |
-#include <signal.h> |
-#include <unistd.h> |
-#include <limits.h> |
-#include <errno.h> |
-#include <stdlib.h> |
-#include <sys/time.h> |
-#include <sys/wait.h> |
-#include <sys/stat.h> |
-#include "secrng.h" |
-#include "secerr.h" |
-#include "prerror.h" |
-#include "prthread.h" |
-#include "prprf.h" |
- |
-size_t RNG_FileUpdate(const char *fileName, size_t limit); |
- |
-/* |
- * When copying data to the buffer we want the least signicant bytes |
- * from the input since those bits are changing the fastest. The address |
- * of least significant byte depends upon whether we are running on |
- * a big-endian or little-endian machine. |
- * |
- * Does this mean the least signicant bytes are the most significant |
- * to us? :-) |
- */ |
- |
-static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen) |
-{ |
- union endianness { |
- int32 i; |
- char c[4]; |
- } u; |
- |
- if (srclen <= dstlen) { |
- memcpy(dst, src, srclen); |
- return srclen; |
- } |
- u.i = 0x01020304; |
- if (u.c[0] == 0x01) { |
- /* big-endian case */ |
- memcpy(dst, (char*)src + (srclen - dstlen), dstlen); |
- } else { |
- /* little-endian case */ |
- memcpy(dst, src, dstlen); |
- } |
- return dstlen; |
-} |
- |
-#ifdef SOLARIS |
- |
-#include <kstat.h> |
- |
-static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */ |
- |
-/* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time. |
- * Returns error if RNG_RandomUpdate fails. Also increments *total_fed |
- * by the number of bytes successfully buffered. |
- */ |
-static SECStatus BufferEntropy(char* inbuf, PRUint32 inlen, |
- char* entropy_buf, PRUint32* entropy_buffered, |
- PRUint32* total_fed) |
-{ |
- PRUint32 tocopy = 0; |
- PRUint32 avail = 0; |
- SECStatus rv = SECSuccess; |
- |
- while (inlen) { |
- avail = entropy_buf_len - *entropy_buffered; |
- if (!avail) { |
- /* Buffer is full, time to feed it to the RNG. */ |
- rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len); |
- if (SECSuccess != rv) { |
- break; |
- } |
- *entropy_buffered = 0; |
- avail = entropy_buf_len; |
- } |
- tocopy = PR_MIN(avail, inlen); |
- memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy); |
- *entropy_buffered += tocopy; |
- inlen -= tocopy; |
- inbuf += tocopy; |
- *total_fed += tocopy; |
- } |
- return rv; |
-} |
- |
-/* Feed kernel statistics structures and ks_data field to the RNG. |
- * Returns status as well as the number of bytes successfully fed to the RNG. |
- */ |
-static SECStatus RNG_kstat(PRUint32* fed) |
-{ |
- kstat_ctl_t* kc = NULL; |
- kstat_t* ksp = NULL; |
- PRUint32 entropy_buffered = 0; |
- char* entropy_buf = NULL; |
- SECStatus rv = SECSuccess; |
- |
- PORT_Assert(fed); |
- if (!fed) { |
- return SECFailure; |
- } |
- *fed = 0; |
- |
- kc = kstat_open(); |
- PORT_Assert(kc); |
- if (!kc) { |
- return SECFailure; |
- } |
- entropy_buf = (char*) PORT_Alloc(entropy_buf_len); |
- PORT_Assert(entropy_buf); |
- if (entropy_buf) { |
- for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) { |
- if (-1 == kstat_read(kc, ksp, NULL)) { |
- /* missing data from a single kstat shouldn't be fatal */ |
- continue; |
- } |
- rv = BufferEntropy((char*)ksp, sizeof(kstat_t), |
- entropy_buf, &entropy_buffered, |
- fed); |
- if (SECSuccess != rv) { |
- break; |
- } |
- |
- if (ksp->ks_data && ksp->ks_data_size>0 && ksp->ks_ndata>0) { |
- rv = BufferEntropy((char*)ksp->ks_data, ksp->ks_data_size, |
- entropy_buf, &entropy_buffered, |
- fed); |
- if (SECSuccess != rv) { |
- break; |
- } |
- } |
- } |
- if (SECSuccess == rv && entropy_buffered) { |
- /* Buffer is not empty, time to feed it to the RNG */ |
- rv = RNG_RandomUpdate(entropy_buf, entropy_buffered); |
- } |
- PORT_Free(entropy_buf); |
- } else { |
- rv = SECFailure; |
- } |
- if (kstat_close(kc)) { |
- PORT_Assert(0); |
- rv = SECFailure; |
- } |
- return rv; |
-} |
- |
-#endif |
- |
-#if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \ |
- || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) \ |
- || defined(NTO) || defined(__riscos__) |
-#include <sys/times.h> |
- |
-#define getdtablesize() sysconf(_SC_OPEN_MAX) |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- int ticks; |
- struct tms buffer; |
- |
- ticks=times(&buffer); |
- return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); |
-} |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- long si; |
- |
- /* |
- * Is this really necessary? Why not use rand48 or something? |
- */ |
- si = sysconf(_SC_CHILD_MAX); |
- RNG_RandomUpdate(&si, sizeof(si)); |
- |
- si = sysconf(_SC_STREAM_MAX); |
- RNG_RandomUpdate(&si, sizeof(si)); |
- |
- si = sysconf(_SC_OPEN_MAX); |
- RNG_RandomUpdate(&si, sizeof(si)); |
-} |
-#endif |
- |
-#if defined(__sun) |
-#if defined(__svr4) || defined(SVR4) |
-#include <sys/systeminfo.h> |
- |
-#define getdtablesize() sysconf(_SC_OPEN_MAX) |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- int rv; |
- char buf[2000]; |
- |
- rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
-} |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- hrtime_t t; |
- t = gethrtime(); |
- if (t) { |
- return CopyLowBits(buf, maxbytes, &t, sizeof(t)); |
- } |
- return 0; |
-} |
-#else /* SunOS (Sun, but not SVR4) */ |
- |
-extern long sysconf(int name); |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- return 0; |
-} |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- long si; |
- |
- /* This is not very good */ |
- si = sysconf(_SC_CHILD_MAX); |
- RNG_RandomUpdate(&si, sizeof(si)); |
-} |
-#endif |
-#endif /* Sun */ |
- |
-#if defined(__hpux) |
-#include <sys/unistd.h> |
- |
-#define getdtablesize() sysconf(_SC_OPEN_MAX) |
- |
-#if defined(__ia64) |
-#include <ia64/sys/inline.h> |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- PRUint64 t; |
- |
- t = _Asm_mov_from_ar(_AREG44); |
- return CopyLowBits(buf, maxbytes, &t, sizeof(t)); |
-} |
-#else |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- extern int ret_cr16(); |
- int cr16val; |
- |
- cr16val = ret_cr16(); |
- return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val)); |
-} |
-#endif |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- long si; |
- |
- /* This is not very good */ |
- si = sysconf(_AES_OS_VERSION); |
- RNG_RandomUpdate(&si, sizeof(si)); |
- si = sysconf(_SC_CPU_VERSION); |
- RNG_RandomUpdate(&si, sizeof(si)); |
-} |
-#endif /* HPUX */ |
- |
-#if defined(OSF1) |
-#include <sys/types.h> |
-#include <sys/sysinfo.h> |
-#include <sys/systeminfo.h> |
-#include <c_asm.h> |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- char buf[BUFSIZ]; |
- int rv; |
- int off = 0; |
- |
- rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
-} |
- |
-/* |
- * Use the "get the cycle counter" instruction on the alpha. |
- * The low 32 bits completely turn over in less than a minute. |
- * The high 32 bits are some non-counter gunk that changes sometimes. |
- */ |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- unsigned long t; |
- |
- t = asm("rpcc %v0"); |
- return CopyLowBits(buf, maxbytes, &t, sizeof(t)); |
-} |
- |
-#endif /* Alpha */ |
- |
-#if defined(_IBMR2) |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- return 0; |
-} |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- /* XXX haven't found any yet! */ |
-} |
-#endif /* IBM R2 */ |
- |
-#if defined(LINUX) |
-#include <sys/sysinfo.h> |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- return 0; |
-} |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
-#ifndef NO_SYSINFO |
- struct sysinfo si; |
- if (sysinfo(&si) == 0) { |
- RNG_RandomUpdate(&si, sizeof(si)); |
- } |
-#endif |
-} |
-#endif /* LINUX */ |
- |
-#if defined(NCR) |
- |
-#include <sys/utsname.h> |
-#include <sys/systeminfo.h> |
- |
-#define getdtablesize() sysconf(_SC_OPEN_MAX) |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- return 0; |
-} |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- int rv; |
- char buf[2000]; |
- |
- rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
-} |
- |
-#endif /* NCR */ |
- |
-#if defined(sgi) |
-#include <fcntl.h> |
-#undef PRIVATE |
-#include <sys/mman.h> |
-#include <sys/syssgi.h> |
-#include <sys/immu.h> |
-#include <sys/systeminfo.h> |
-#include <sys/utsname.h> |
-#include <wait.h> |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- int rv; |
- char buf[4096]; |
- |
- rv = syssgi(SGI_SYSID, &buf[0]); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, MAXSYSIDSIZE); |
- } |
-#ifdef SGI_RDUBLK |
- rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, sizeof(buf)); |
- } |
-#endif /* SGI_RDUBLK */ |
- rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, sizeof(buf)); |
- } |
- rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
-} |
- |
-static size_t GetHighResClock(void *buf, size_t maxbuf) |
-{ |
- unsigned phys_addr, raddr, cycleval; |
- static volatile unsigned *iotimer_addr = NULL; |
- static int tries = 0; |
- static int cntr_size; |
- int mfd; |
- long s0[2]; |
- struct timeval tv; |
- |
-#ifndef SGI_CYCLECNTR_SIZE |
-#define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ |
-#endif |
- |
- if (iotimer_addr == NULL) { |
- if (tries++ > 1) { |
- /* Don't keep trying if it didn't work */ |
- return 0; |
- } |
- |
- /* |
- ** For SGI machines we can use the cycle counter, if it has one, |
- ** to generate some truly random numbers |
- */ |
- phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); |
- if (phys_addr) { |
- int pgsz = getpagesize(); |
- int pgoffmask = pgsz - 1; |
- |
- raddr = phys_addr & ~pgoffmask; |
- mfd = open("/dev/mmem", O_RDONLY); |
- if (mfd < 0) { |
- return 0; |
- } |
- iotimer_addr = (unsigned *) |
- mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr); |
- if (iotimer_addr == (void*)-1) { |
- close(mfd); |
- iotimer_addr = NULL; |
- return 0; |
- } |
- iotimer_addr = (unsigned*) |
- ((__psint_t)iotimer_addr | (phys_addr & pgoffmask)); |
- /* |
- * The file 'mfd' is purposefully not closed. |
- */ |
- cntr_size = syssgi(SGI_CYCLECNTR_SIZE); |
- if (cntr_size < 0) { |
- struct utsname utsinfo; |
- |
- /* |
- * We must be executing on a 6.0 or earlier system, since the |
- * SGI_CYCLECNTR_SIZE call is not supported. |
- * |
- * The only pre-6.1 platforms with 64-bit counters are |
- * IP19 and IP21 (Challenge, PowerChallenge, Onyx). |
- */ |
- uname(&utsinfo); |
- if (!strncmp(utsinfo.machine, "IP19", 4) || |
- !strncmp(utsinfo.machine, "IP21", 4)) |
- cntr_size = 64; |
- else |
- cntr_size = 32; |
- } |
- cntr_size /= 8; /* Convert from bits to bytes */ |
- } |
- } |
- |
- s0[0] = *iotimer_addr; |
- if (cntr_size > 4) |
- s0[1] = *(iotimer_addr + 1); |
- memcpy(buf, (char *)&s0[0], cntr_size); |
- return CopyLowBits(buf, maxbuf, &s0, cntr_size); |
-} |
-#endif |
- |
-#if defined(sony) |
-#include <sys/systeminfo.h> |
- |
-#define getdtablesize() sysconf(_SC_OPEN_MAX) |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- return 0; |
-} |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- int rv; |
- char buf[2000]; |
- |
- rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
-} |
-#endif /* sony */ |
- |
-#if defined(sinix) |
-#include <sys/systeminfo.h> |
-#include <sys/times.h> |
- |
-int gettimeofday(struct timeval *, struct timezone *); |
-int gethostname(char *, int); |
- |
-#define getdtablesize() sysconf(_SC_OPEN_MAX) |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- int ticks; |
- struct tms buffer; |
- |
- ticks=times(&buffer); |
- return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); |
-} |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- int rv; |
- char buf[2000]; |
- |
- rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
-} |
-#endif /* sinix */ |
- |
- |
-#ifdef BEOS |
-#include <be/kernel/OS.h> |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- bigtime_t bigtime; /* Actually an int64 */ |
- |
- bigtime = real_time_clock_usecs(); |
- return CopyLowBits(buf, maxbytes, &bigtime, sizeof(bigtime)); |
-} |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- system_info *info = NULL; |
- int32 val; |
- get_system_info(info); |
- if (info) { |
- val = info->boot_time; |
- RNG_RandomUpdate(&val, sizeof(val)); |
- val = info->used_pages; |
- RNG_RandomUpdate(&val, sizeof(val)); |
- val = info->used_ports; |
- RNG_RandomUpdate(&val, sizeof(val)); |
- val = info->used_threads; |
- RNG_RandomUpdate(&val, sizeof(val)); |
- val = info->used_teams; |
- RNG_RandomUpdate(&val, sizeof(val)); |
- } |
-} |
-#endif /* BEOS */ |
- |
-#if defined(nec_ews) |
-#include <sys/systeminfo.h> |
- |
-#define getdtablesize() sysconf(_SC_OPEN_MAX) |
- |
-static size_t |
-GetHighResClock(void *buf, size_t maxbytes) |
-{ |
- return 0; |
-} |
- |
-static void |
-GiveSystemInfo(void) |
-{ |
- int rv; |
- char buf[2000]; |
- |
- rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
- rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); |
- if (rv > 0) { |
- RNG_RandomUpdate(buf, rv); |
- } |
-} |
-#endif /* nec_ews */ |
- |
-size_t RNG_GetNoise(void *buf, size_t maxbytes) |
-{ |
- struct timeval tv; |
- int n = 0; |
- int c; |
- |
- n = GetHighResClock(buf, maxbytes); |
- maxbytes -= n; |
- |
- (void)gettimeofday(&tv, 0); |
- c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec)); |
- n += c; |
- maxbytes -= c; |
- c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec)); |
- n += c; |
- return n; |
-} |
- |
-#define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */ |
- |
-/* |
- * safe_popen is static to this module and we know what arguments it is |
- * called with. Note that this version only supports a single open child |
- * process at any time. |
- */ |
-static pid_t safe_popen_pid; |
-static struct sigaction oldact; |
- |
-static FILE * |
-safe_popen(char *cmd) |
-{ |
- int p[2], fd, argc; |
- pid_t pid; |
- char *argv[SAFE_POPEN_MAXARGS + 1]; |
- FILE *fp; |
- static char blank[] = " \t"; |
- static struct sigaction newact; |
- |
- if (pipe(p) < 0) |
- return 0; |
- |
- fp = fdopen(p[0], "r"); |
- if (fp == 0) { |
- close(p[0]); |
- close(p[1]); |
- return 0; |
- } |
- |
- /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */ |
- newact.sa_handler = SIG_DFL; |
- newact.sa_flags = 0; |
- sigfillset(&newact.sa_mask); |
- sigaction (SIGCHLD, &newact, &oldact); |
- |
- pid = fork(); |
- switch (pid) { |
- int ndesc; |
- |
- case -1: |
- fclose(fp); /* this closes p[0], the fd associated with fp */ |
- close(p[1]); |
- sigaction (SIGCHLD, &oldact, NULL); |
- return 0; |
- |
- case 0: |
- /* dup write-side of pipe to stderr and stdout */ |
- if (p[1] != 1) dup2(p[1], 1); |
- if (p[1] != 2) dup2(p[1], 2); |
- |
- /* |
- * close the other file descriptors, except stdin which we |
- * try reassociating with /dev/null, first (bug 174993) |
- */ |
- if (!freopen("/dev/null", "r", stdin)) |
- close(0); |
- ndesc = getdtablesize(); |
- for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd)); |
- |
- /* clean up environment in the child process */ |
- putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"); |
- putenv("SHELL=/bin/sh"); |
- putenv("IFS= \t"); |
- |
- /* |
- * The caller may have passed us a string that is in text |
- * space. It may be illegal to modify the string |
- */ |
- cmd = strdup(cmd); |
- /* format argv */ |
- argv[0] = strtok(cmd, blank); |
- argc = 1; |
- while ((argv[argc] = strtok(0, blank)) != 0) { |
- if (++argc == SAFE_POPEN_MAXARGS) { |
- argv[argc] = 0; |
- break; |
- } |
- } |
- |
- /* and away we go */ |
- execvp(argv[0], argv); |
- exit(127); |
- break; |
- |
- default: |
- close(p[1]); |
- break; |
- } |
- |
- /* non-zero means there's a cmd running */ |
- safe_popen_pid = pid; |
- return fp; |
-} |
- |
-static int |
-safe_pclose(FILE *fp) |
-{ |
- pid_t pid; |
- int status = -1, rv; |
- |
- if ((pid = safe_popen_pid) == 0) |
- return -1; |
- safe_popen_pid = 0; |
- |
- fclose(fp); |
- |
- /* yield the processor so the child gets some time to exit normally */ |
- PR_Sleep(PR_INTERVAL_NO_WAIT); |
- |
- /* if the child hasn't exited, kill it -- we're done with its output */ |
- while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR) |
- ; |
- if (rv == 0) { |
- kill(pid, SIGKILL); |
- while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR) |
- ; |
- } |
- |
- /* Reset SIGCHLD signal hander before returning */ |
- sigaction(SIGCHLD, &oldact, NULL); |
- |
- return status; |
-} |
- |
-#ifdef DARWIN |
-#include <TargetConditionals.h> |
-#if !TARGET_OS_IPHONE |
-#include <crt_externs.h> |
-#endif |
-#endif |
- |
-/* Fork netstat to collect its output by default. Do not unset this unless |
- * another source of entropy is available |
- */ |
-#define DO_NETSTAT 1 |
- |
-void RNG_SystemInfoForRNG(void) |
-{ |
- FILE *fp; |
- char buf[BUFSIZ]; |
- size_t bytes; |
- const char * const *cp; |
- char *randfile; |
-#ifdef DARWIN |
-#if TARGET_OS_IPHONE |
- /* iOS does not expose a way to access environ. */ |
- char **environ = NULL; |
-#else |
- char **environ = *_NSGetEnviron(); |
-#endif |
-#else |
- extern char **environ; |
-#endif |
-#ifdef BEOS |
- static const char * const files[] = { |
- "/boot/var/swap", |
- "/boot/var/log/syslog", |
- "/boot/var/tmp", |
- "/boot/home/config/settings", |
- "/boot/home", |
- 0 |
- }; |
-#else |
- static const char * const files[] = { |
- "/etc/passwd", |
- "/etc/utmp", |
- "/tmp", |
- "/var/tmp", |
- "/usr/tmp", |
- 0 |
- }; |
-#endif |
- |
-#if defined(BSDI) |
- static char netstat_ni_cmd[] = "netstat -nis"; |
-#else |
- static char netstat_ni_cmd[] = "netstat -ni"; |
-#endif |
- |
- GiveSystemInfo(); |
- |
- bytes = RNG_GetNoise(buf, sizeof(buf)); |
- RNG_RandomUpdate(buf, bytes); |
- |
- /* |
- * Pass the C environment and the addresses of the pointers to the |
- * hash function. This makes the random number function depend on the |
- * execution environment of the user and on the platform the program |
- * is running on. |
- */ |
- if (environ != NULL) { |
- cp = (const char * const *) environ; |
- while (*cp) { |
- RNG_RandomUpdate(*cp, strlen(*cp)); |
- cp++; |
- } |
- RNG_RandomUpdate(environ, (char*)cp - (char*)environ); |
- } |
- |
- /* Give in system information */ |
- if (gethostname(buf, sizeof(buf)) == 0) { |
- RNG_RandomUpdate(buf, strlen(buf)); |
- } |
- GiveSystemInfo(); |
- |
- /* grab some data from system's PRNG before any other files. */ |
- bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT); |
- |
- /* If the user points us to a random file, pass it through the rng */ |
- randfile = getenv("NSRANDFILE"); |
- if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) { |
- char *randCountString = getenv("NSRANDCOUNT"); |
- int randCount = randCountString ? atoi(randCountString) : 0; |
- if (randCount != 0) { |
- RNG_FileUpdate(randfile, randCount); |
- } else { |
- RNG_FileForRNG(randfile); |
- } |
- } |
- |
- /* pass other files through */ |
- for (cp = files; *cp; cp++) |
- RNG_FileForRNG(*cp); |
- |
-/* |
- * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen |
- * in a pthreads environment. Therefore, we call safe_popen last and on |
- * BSD/OS we do not call safe_popen when we succeeded in getting data |
- * from /dev/urandom. |
- * |
- * Bug 174993: On platforms providing /dev/urandom, don't fork netstat |
- * either, if data has been gathered successfully. |
- */ |
- |
-#if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \ |
- || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) \ |
- || defined(HPUX) |
- if (bytes) |
- return; |
-#endif |
- |
-#ifdef SOLARIS |
- |
-/* |
- * On Solaris, NSS may be initialized automatically from libldap in |
- * applications that are unaware of the use of NSS. safe_popen forks, and |
- * sometimes creates issues with some applications' pthread_atfork handlers. |
- * We always have /dev/urandom on Solaris 9 and above as an entropy source, |
- * and for Solaris 8 we have the libkstat interface, so we don't need to |
- * fork netstat. |
- */ |
- |
-#undef DO_NETSTAT |
- if (!bytes) { |
- /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */ |
- PRUint32 kstat_bytes = 0; |
- if (SECSuccess != RNG_kstat(&kstat_bytes)) { |
- PORT_Assert(0); |
- } |
- bytes += kstat_bytes; |
- PORT_Assert(bytes); |
- } |
-#endif |
- |
-#ifdef DO_NETSTAT |
- fp = safe_popen(netstat_ni_cmd); |
- if (fp != NULL) { |
- while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) |
- RNG_RandomUpdate(buf, bytes); |
- safe_pclose(fp); |
- } |
-#endif |
- |
-} |
- |
-#define TOTAL_FILE_LIMIT 1000000 /* one million */ |
- |
-size_t RNG_FileUpdate(const char *fileName, size_t limit) |
-{ |
- FILE * file; |
- size_t bytes; |
- size_t fileBytes = 0; |
- struct stat stat_buf; |
- unsigned char buffer[BUFSIZ]; |
- static size_t totalFileBytes = 0; |
- |
- /* suppress valgrind warnings due to holes in struct stat */ |
- memset(&stat_buf, 0, sizeof(stat_buf)); |
- |
- if (stat((char *)fileName, &stat_buf) < 0) |
- return fileBytes; |
- RNG_RandomUpdate(&stat_buf, sizeof(stat_buf)); |
- |
- file = fopen((char *)fileName, "r"); |
- if (file != NULL) { |
- while (limit > fileBytes) { |
- bytes = PR_MIN(sizeof buffer, limit - fileBytes); |
- bytes = fread(buffer, 1, bytes, file); |
- if (bytes == 0) |
- break; |
- RNG_RandomUpdate(buffer, bytes); |
- fileBytes += bytes; |
- totalFileBytes += bytes; |
- /* after TOTAL_FILE_LIMIT has been reached, only read in first |
- ** buffer of data from each subsequent file. |
- */ |
- if (totalFileBytes > TOTAL_FILE_LIMIT) |
- break; |
- } |
- fclose(file); |
- } |
- /* |
- * Pass yet another snapshot of our highest resolution clock into |
- * the hash function. |
- */ |
- bytes = RNG_GetNoise(buffer, sizeof(buffer)); |
- RNG_RandomUpdate(buffer, bytes); |
- return fileBytes; |
-} |
- |
-void RNG_FileForRNG(const char *fileName) |
-{ |
- RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT); |
-} |
- |
-void ReadSingleFile(const char *fileName) |
-{ |
- FILE * file; |
- unsigned char buffer[BUFSIZ]; |
- |
- file = fopen((char *)fileName, "rb"); |
- if (file != NULL) { |
- while (fread(buffer, 1, sizeof(buffer), file) > 0) |
- ; |
- fclose(file); |
- } |
-} |
- |
-#define _POSIX_PTHREAD_SEMANTICS |
-#include <dirent.h> |
- |
-PRBool |
-ReadFileOK(char *dir, char *file) |
-{ |
- struct stat stat_buf; |
- char filename[PATH_MAX]; |
- int count = snprintf(filename, sizeof filename, "%s/%s",dir, file); |
- |
- if (count <= 0) { |
- return PR_FALSE; /* name too long, can't read it anyway */ |
- } |
- |
- if (stat(filename, &stat_buf) < 0) |
- return PR_FALSE; /* can't stat, probably can't read it then as well */ |
- return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE; |
-} |
- |
-/* |
- * read one file out of either /etc or the user's home directory. |
- * fileToRead tells which file to read. |
- * |
- * return 1 if it's time to reset the fileToRead (no more files to read). |
- */ |
-int ReadOneFile(int fileToRead) |
-{ |
- char *dir = "/etc"; |
- DIR *fd = opendir(dir); |
- int resetCount = 0; |
-#ifdef SOLARIS |
- /* grumble, Solaris does not define struct dirent to be the full length */ |
- typedef union { |
- unsigned char space[sizeof(struct dirent) + MAXNAMELEN]; |
- struct dirent dir; |
- } dirent_hack; |
- dirent_hack entry, firstEntry; |
- |
-#define entry_dir entry.dir |
-#else |
- struct dirent entry, firstEntry; |
-#define entry_dir entry |
-#endif |
- |
- int i, error = -1; |
- |
- if (fd == NULL) { |
- dir = getenv("HOME"); |
- if (dir) { |
- fd = opendir(dir); |
- } |
- } |
- if (fd == NULL) { |
- return 1; |
- } |
- |
- for (i=0; i <= fileToRead; i++) { |
- struct dirent *result = NULL; |
- do { |
- error = readdir_r(fd, &entry_dir, &result); |
- } while (error == 0 && result != NULL && |
- !ReadFileOK(dir,&result->d_name[0])); |
- if (error != 0 || result == NULL) { |
- resetCount = 1; /* read to the end, start again at the beginning */ |
- if (i != 0) { |
- /* ran out of entries in the directory, use the first one */ |
- entry = firstEntry; |
- error = 0; |
- break; |
- } |
- /* if i== 0, there were no readable entries in the directory */ |
- break; |
- } |
- if (i==0) { |
- /* save the first entry in case we run out of entries */ |
- firstEntry = entry; |
- } |
- } |
- |
- if (error == 0) { |
- char filename[PATH_MAX]; |
- int count = snprintf(filename, sizeof filename, |
- "%s/%s",dir, &entry_dir.d_name[0]); |
- if (count >= 1) { |
- ReadSingleFile(filename); |
- } |
- } |
- |
- closedir(fd); |
- return resetCount; |
-} |
- |
-/* |
- * do something to try to introduce more noise into the 'GetNoise' call |
- */ |
-static void rng_systemJitter(void) |
-{ |
- static int fileToRead = 1; |
- |
- if (ReadOneFile(fileToRead)) { |
- fileToRead = 1; |
- } else { |
- fileToRead++; |
- } |
-} |
- |
-size_t RNG_SystemRNG(void *dest, size_t maxLen) |
-{ |
- FILE *file; |
- size_t bytes; |
- size_t fileBytes = 0; |
- unsigned char *buffer = dest; |
- |
- file = fopen("/dev/urandom", "r"); |
- if (file == NULL) { |
- return rng_systemFromNoise(dest, maxLen); |
- } |
- while (maxLen > fileBytes) { |
- bytes = maxLen - fileBytes; |
- bytes = fread(buffer, 1, bytes, file); |
- if (bytes == 0) |
- break; |
- fileBytes += bytes; |
- buffer += bytes; |
- } |
- fclose(file); |
- if (fileBytes != maxLen) { |
- PORT_SetError(SEC_ERROR_NEED_RANDOM); /* system RNG failed */ |
- fileBytes = 0; |
- } |
- return fileBytes; |
-} |