diff options
Diffstat (limited to 'security/nss/lib/freebl/unix_rand.c')
-rw-r--r-- | security/nss/lib/freebl/unix_rand.c | 1280 |
1 files changed, 0 insertions, 1280 deletions
diff --git a/security/nss/lib/freebl/unix_rand.c b/security/nss/lib/freebl/unix_rand.c deleted file mode 100644 index 28b523759..000000000 --- a/security/nss/lib/freebl/unix_rand.c +++ /dev/null @@ -1,1280 +0,0 @@ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is the Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#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> -#include <sys/times.h> -#include <wait.h> - -int gettimeofday(struct timeval *); -int gethostname(char *, int); - -#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) -{ - struct sysinfo si; - if (sysinfo(&si) == 0) { - RNG_RandomUpdate(&si, sizeof(si)); - } -} -#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 */ - -#if defined(VMS) -#include <c_asm.h> - -static void -GiveSystemInfo(void) -{ - long si; - - /* - * This is copied from the SCO/UNIXWARE etc section. And like the comment - * there says, what's the point? This isn't random, it generates the same - * stuff every time its run! - */ - 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)); -} - -/* - * 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 /* VMS */ - -#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; - -#if defined(__sun) && (defined(_svr4) || defined(SVR4)) || defined(sony) - (void)gettimeofday(&tv); -#else - (void)gettimeofday(&tv, 0); -#endif - 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; -} - - -#if !defined(VMS) - -#ifdef DARWIN -#include <crt_externs.h> -#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 - char **environ = *_NSGetEnviron(); -#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: LINUX provides /dev/urandom, don't fork netstat - * if data has been gathered successfully - */ - -#if defined(BSDI) || defined(LINUX) - 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 - -} -#else -void RNG_SystemInfoForRNG(void) -{ - FILE *fp; - char buf[BUFSIZ]; - size_t bytes; - int extra; - char **cp; - extern char **environ; - char *randfile; - - 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. - */ - cp = 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(); - - /* If the user points us to a random file, pass it through the rng */ - randfile = getenv("NSRANDFILE"); - if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) { - RNG_FileForRNG(randfile); - } - - /* - ** We need to generate at least 1024 bytes of seed data. Since we don't - ** do the file stuff for VMS, and because the environ list is so short - ** on VMS, we need to make sure we generate enough. So do another 1000 - ** bytes to be sure. - */ - extra = 1000; - while (extra > 0) { - cp = environ; - while (*cp) { - int n = strlen(*cp); - RNG_RandomUpdate(*cp, n); - extra -= n; - cp++; - } - } -} -#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; -} |