Blame nss/lib/freebl/unix_rand.c

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