security/nss/lib/freebl/unix_rand.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/security/nss/lib/freebl/unix_rand.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1171 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +#include <stdio.h>
     1.9 +#include <string.h>
    1.10 +#include <signal.h>
    1.11 +#include <unistd.h>
    1.12 +#include <limits.h>
    1.13 +#include <errno.h>
    1.14 +#include <stdlib.h>
    1.15 +#include <sys/time.h>
    1.16 +#include <sys/wait.h>
    1.17 +#include <sys/stat.h>
    1.18 +#include "secrng.h"
    1.19 +#include "secerr.h"
    1.20 +#include "prerror.h"
    1.21 +#include "prthread.h"
    1.22 +#include "prprf.h"
    1.23 +
    1.24 +size_t RNG_FileUpdate(const char *fileName, size_t limit);
    1.25 +
    1.26 +/*
    1.27 + * When copying data to the buffer we want the least signicant bytes
    1.28 + * from the input since those bits are changing the fastest. The address
    1.29 + * of least significant byte depends upon whether we are running on
    1.30 + * a big-endian or little-endian machine.
    1.31 + *
    1.32 + * Does this mean the least signicant bytes are the most significant
    1.33 + * to us? :-)
    1.34 + */
    1.35 +    
    1.36 +static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
    1.37 +{
    1.38 +    union endianness {
    1.39 +	PRInt32 i;
    1.40 +	char c[4];
    1.41 +    } u;
    1.42 +
    1.43 +    if (srclen <= dstlen) {
    1.44 +	memcpy(dst, src, srclen);
    1.45 +	return srclen;
    1.46 +    }
    1.47 +    u.i = 0x01020304;
    1.48 +    if (u.c[0] == 0x01) {
    1.49 +	/* big-endian case */
    1.50 +	memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
    1.51 +    } else {
    1.52 +	/* little-endian case */
    1.53 +	memcpy(dst, src, dstlen);
    1.54 +    }
    1.55 +    return dstlen;
    1.56 +}
    1.57 +
    1.58 +#ifdef SOLARIS
    1.59 +
    1.60 +#include <kstat.h>
    1.61 +
    1.62 +static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */
    1.63 +
    1.64 +/* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time.
    1.65 + * Returns error if RNG_RandomUpdate fails. Also increments *total_fed
    1.66 + * by the number of bytes successfully buffered.
    1.67 + */
    1.68 +static SECStatus BufferEntropy(char* inbuf, PRUint32 inlen,
    1.69 +                                char* entropy_buf, PRUint32* entropy_buffered,
    1.70 +                                PRUint32* total_fed)
    1.71 +{
    1.72 +    PRUint32 tocopy = 0;
    1.73 +    PRUint32 avail = 0;
    1.74 +    SECStatus rv = SECSuccess;
    1.75 +
    1.76 +    while (inlen) {
    1.77 +        avail = entropy_buf_len - *entropy_buffered;
    1.78 +        if (!avail) {
    1.79 +            /* Buffer is full, time to feed it to the RNG. */
    1.80 +            rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len);
    1.81 +            if (SECSuccess != rv) {
    1.82 +                break;
    1.83 +            }
    1.84 +            *entropy_buffered = 0;
    1.85 +            avail = entropy_buf_len;
    1.86 +        }
    1.87 +        tocopy = PR_MIN(avail, inlen);
    1.88 +        memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy);
    1.89 +        *entropy_buffered += tocopy;
    1.90 +        inlen -= tocopy;
    1.91 +        inbuf += tocopy;
    1.92 +        *total_fed += tocopy;
    1.93 +    }
    1.94 +    return rv;
    1.95 +}
    1.96 +
    1.97 +/* Feed kernel statistics structures and ks_data field to the RNG.
    1.98 + * Returns status as well as the number of bytes successfully fed to the RNG.
    1.99 + */
   1.100 +static SECStatus RNG_kstat(PRUint32* fed)
   1.101 +{
   1.102 +    kstat_ctl_t*    kc = NULL;
   1.103 +    kstat_t*        ksp = NULL;
   1.104 +    PRUint32        entropy_buffered = 0;
   1.105 +    char*           entropy_buf = NULL;
   1.106 +    SECStatus       rv = SECSuccess;
   1.107 +
   1.108 +    PORT_Assert(fed);
   1.109 +    if (!fed) {
   1.110 +        return SECFailure;
   1.111 +    }
   1.112 +    *fed = 0;
   1.113 +
   1.114 +    kc = kstat_open();
   1.115 +    PORT_Assert(kc);
   1.116 +    if (!kc) {
   1.117 +        return SECFailure;
   1.118 +    }
   1.119 +    entropy_buf = (char*) PORT_Alloc(entropy_buf_len);
   1.120 +    PORT_Assert(entropy_buf);
   1.121 +    if (entropy_buf) {
   1.122 +        for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
   1.123 +            if (-1 == kstat_read(kc, ksp, NULL)) {
   1.124 +                /* missing data from a single kstat shouldn't be fatal */
   1.125 +                continue;
   1.126 +            }
   1.127 +            rv = BufferEntropy((char*)ksp, sizeof(kstat_t),
   1.128 +                                    entropy_buf, &entropy_buffered,
   1.129 +                                    fed);
   1.130 +            if (SECSuccess != rv) {
   1.131 +                break;
   1.132 +            }
   1.133 +
   1.134 +            if (ksp->ks_data && ksp->ks_data_size>0 && ksp->ks_ndata>0) {
   1.135 +                rv = BufferEntropy((char*)ksp->ks_data, ksp->ks_data_size,
   1.136 +                                        entropy_buf, &entropy_buffered,
   1.137 +                                        fed);
   1.138 +                if (SECSuccess != rv) {
   1.139 +                    break;
   1.140 +                }
   1.141 +            }
   1.142 +        }
   1.143 +        if (SECSuccess == rv && entropy_buffered) {
   1.144 +            /* Buffer is not empty, time to feed it to the RNG */
   1.145 +            rv = RNG_RandomUpdate(entropy_buf, entropy_buffered);
   1.146 +        }
   1.147 +        PORT_Free(entropy_buf);
   1.148 +    } else {
   1.149 +        rv = SECFailure;
   1.150 +    }
   1.151 +    if (kstat_close(kc)) {
   1.152 +        PORT_Assert(0);
   1.153 +        rv = SECFailure;
   1.154 +    }
   1.155 +    return rv;
   1.156 +}
   1.157 +
   1.158 +#endif
   1.159 +
   1.160 +#if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \
   1.161 +    || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) \
   1.162 +    || defined(NTO) || defined(__riscos__)
   1.163 +#include <sys/times.h>
   1.164 +
   1.165 +#define getdtablesize() sysconf(_SC_OPEN_MAX)
   1.166 +
   1.167 +static size_t
   1.168 +GetHighResClock(void *buf, size_t maxbytes)
   1.169 +{
   1.170 +    int ticks;
   1.171 +    struct tms buffer;
   1.172 +
   1.173 +    ticks=times(&buffer);
   1.174 +    return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
   1.175 +}
   1.176 +
   1.177 +static void
   1.178 +GiveSystemInfo(void)
   1.179 +{
   1.180 +    long si;
   1.181 +
   1.182 +    /* 
   1.183 +     * Is this really necessary?  Why not use rand48 or something?
   1.184 +     */
   1.185 +    si = sysconf(_SC_CHILD_MAX);
   1.186 +    RNG_RandomUpdate(&si, sizeof(si));
   1.187 +
   1.188 +    si = sysconf(_SC_STREAM_MAX);
   1.189 +    RNG_RandomUpdate(&si, sizeof(si));
   1.190 +
   1.191 +    si = sysconf(_SC_OPEN_MAX);
   1.192 +    RNG_RandomUpdate(&si, sizeof(si));
   1.193 +}
   1.194 +#endif
   1.195 +
   1.196 +#if defined(__sun)
   1.197 +#if defined(__svr4) || defined(SVR4)
   1.198 +#include <sys/systeminfo.h>
   1.199 +
   1.200 +#define getdtablesize() sysconf(_SC_OPEN_MAX)
   1.201 +
   1.202 +static void
   1.203 +GiveSystemInfo(void)
   1.204 +{
   1.205 +    int rv;
   1.206 +    char buf[2000];
   1.207 +
   1.208 +    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   1.209 +    if (rv > 0) {
   1.210 +	RNG_RandomUpdate(buf, rv);
   1.211 +    }
   1.212 +    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   1.213 +    if (rv > 0) {
   1.214 +	RNG_RandomUpdate(buf, rv);
   1.215 +    }
   1.216 +    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   1.217 +    if (rv > 0) {
   1.218 +	RNG_RandomUpdate(buf, rv);
   1.219 +    }
   1.220 +}
   1.221 +
   1.222 +static size_t
   1.223 +GetHighResClock(void *buf, size_t maxbytes)
   1.224 +{
   1.225 +    hrtime_t t;
   1.226 +    t = gethrtime();
   1.227 +    if (t) {
   1.228 +	return CopyLowBits(buf, maxbytes, &t, sizeof(t));
   1.229 +    }
   1.230 +    return 0;
   1.231 +}
   1.232 +#else /* SunOS (Sun, but not SVR4) */
   1.233 +
   1.234 +extern long sysconf(int name);
   1.235 +
   1.236 +static size_t
   1.237 +GetHighResClock(void *buf, size_t maxbytes)
   1.238 +{
   1.239 +    return 0;
   1.240 +}
   1.241 +
   1.242 +static void
   1.243 +GiveSystemInfo(void)
   1.244 +{
   1.245 +    long si;
   1.246 +
   1.247 +    /* This is not very good */
   1.248 +    si = sysconf(_SC_CHILD_MAX);
   1.249 +    RNG_RandomUpdate(&si, sizeof(si));
   1.250 +}
   1.251 +#endif
   1.252 +#endif /* Sun */
   1.253 +
   1.254 +#if defined(__hpux)
   1.255 +#include <sys/unistd.h>
   1.256 +
   1.257 +#define getdtablesize() sysconf(_SC_OPEN_MAX)
   1.258 +
   1.259 +#if defined(__ia64)
   1.260 +#include <ia64/sys/inline.h>
   1.261 +
   1.262 +static size_t
   1.263 +GetHighResClock(void *buf, size_t maxbytes)
   1.264 +{
   1.265 +    PRUint64 t;
   1.266 +
   1.267 +    t = _Asm_mov_from_ar(_AREG44);
   1.268 +    return CopyLowBits(buf, maxbytes, &t, sizeof(t));
   1.269 +}
   1.270 +#else
   1.271 +static size_t
   1.272 +GetHighResClock(void *buf, size_t maxbytes)
   1.273 +{
   1.274 +    extern int ret_cr16();
   1.275 +    int cr16val;
   1.276 +
   1.277 +    cr16val = ret_cr16();
   1.278 +    return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val));
   1.279 +}
   1.280 +#endif
   1.281 +
   1.282 +static void
   1.283 +GiveSystemInfo(void)
   1.284 +{
   1.285 +    long si;
   1.286 +
   1.287 +    /* This is not very good */
   1.288 +    si = sysconf(_AES_OS_VERSION);
   1.289 +    RNG_RandomUpdate(&si, sizeof(si));
   1.290 +    si = sysconf(_SC_CPU_VERSION);
   1.291 +    RNG_RandomUpdate(&si, sizeof(si));
   1.292 +}
   1.293 +#endif /* HPUX */
   1.294 +
   1.295 +#if defined(OSF1)
   1.296 +#include <sys/types.h>
   1.297 +#include <sys/sysinfo.h>
   1.298 +#include <sys/systeminfo.h>
   1.299 +#include <c_asm.h>
   1.300 +
   1.301 +static void
   1.302 +GiveSystemInfo(void)
   1.303 +{
   1.304 +    char buf[BUFSIZ];
   1.305 +    int rv;
   1.306 +    int off = 0;
   1.307 +
   1.308 +    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   1.309 +    if (rv > 0) {
   1.310 +	RNG_RandomUpdate(buf, rv);
   1.311 +    }
   1.312 +    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   1.313 +    if (rv > 0) {
   1.314 +	RNG_RandomUpdate(buf, rv);
   1.315 +    }
   1.316 +    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   1.317 +    if (rv > 0) {
   1.318 +	RNG_RandomUpdate(buf, rv);
   1.319 +    }
   1.320 +}
   1.321 +
   1.322 +/*
   1.323 + * Use the "get the cycle counter" instruction on the alpha.
   1.324 + * The low 32 bits completely turn over in less than a minute.
   1.325 + * The high 32 bits are some non-counter gunk that changes sometimes.
   1.326 + */
   1.327 +static size_t
   1.328 +GetHighResClock(void *buf, size_t maxbytes)
   1.329 +{
   1.330 +    unsigned long t;
   1.331 +
   1.332 +    t = asm("rpcc %v0");
   1.333 +    return CopyLowBits(buf, maxbytes, &t, sizeof(t));
   1.334 +}
   1.335 +
   1.336 +#endif /* Alpha */
   1.337 +
   1.338 +#if defined(_IBMR2)
   1.339 +static size_t
   1.340 +GetHighResClock(void *buf, size_t maxbytes)
   1.341 +{
   1.342 +    return 0;
   1.343 +}
   1.344 +
   1.345 +static void
   1.346 +GiveSystemInfo(void)
   1.347 +{
   1.348 +    /* XXX haven't found any yet! */
   1.349 +}
   1.350 +#endif /* IBM R2 */
   1.351 +
   1.352 +#if defined(LINUX)
   1.353 +#include <sys/sysinfo.h>
   1.354 +
   1.355 +static size_t
   1.356 +GetHighResClock(void *buf, size_t maxbytes)
   1.357 +{
   1.358 +    return 0;
   1.359 +}
   1.360 +
   1.361 +static void
   1.362 +GiveSystemInfo(void)
   1.363 +{
   1.364 +#ifndef NO_SYSINFO
   1.365 +    struct sysinfo si;
   1.366 +    if (sysinfo(&si) == 0) {
   1.367 +	RNG_RandomUpdate(&si, sizeof(si));
   1.368 +    }
   1.369 +#endif
   1.370 +}
   1.371 +#endif /* LINUX */
   1.372 +
   1.373 +#if defined(NCR)
   1.374 +
   1.375 +#include <sys/utsname.h>
   1.376 +#include <sys/systeminfo.h>
   1.377 +
   1.378 +#define getdtablesize() sysconf(_SC_OPEN_MAX)
   1.379 +
   1.380 +static size_t
   1.381 +GetHighResClock(void *buf, size_t maxbytes)
   1.382 +{
   1.383 +    return 0;
   1.384 +}
   1.385 +
   1.386 +static void
   1.387 +GiveSystemInfo(void)
   1.388 +{
   1.389 +    int rv;
   1.390 +    char buf[2000];
   1.391 +
   1.392 +    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   1.393 +    if (rv > 0) {
   1.394 +	RNG_RandomUpdate(buf, rv);
   1.395 +    }
   1.396 +    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   1.397 +    if (rv > 0) {
   1.398 +	RNG_RandomUpdate(buf, rv);
   1.399 +    }
   1.400 +    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   1.401 +    if (rv > 0) {
   1.402 +	RNG_RandomUpdate(buf, rv);
   1.403 +    }
   1.404 +}
   1.405 +
   1.406 +#endif /* NCR */
   1.407 +
   1.408 +#if defined(sgi)
   1.409 +#include <fcntl.h>
   1.410 +#undef PRIVATE
   1.411 +#include <sys/mman.h>
   1.412 +#include <sys/syssgi.h>
   1.413 +#include <sys/immu.h>
   1.414 +#include <sys/systeminfo.h>
   1.415 +#include <sys/utsname.h>
   1.416 +#include <wait.h>
   1.417 +
   1.418 +static void
   1.419 +GiveSystemInfo(void)
   1.420 +{
   1.421 +    int rv;
   1.422 +    char buf[4096];
   1.423 +
   1.424 +    rv = syssgi(SGI_SYSID, &buf[0]);
   1.425 +    if (rv > 0) {
   1.426 +	RNG_RandomUpdate(buf, MAXSYSIDSIZE);
   1.427 +    }
   1.428 +#ifdef SGI_RDUBLK
   1.429 +    rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf));
   1.430 +    if (rv > 0) {
   1.431 +	RNG_RandomUpdate(buf, sizeof(buf));
   1.432 +    }
   1.433 +#endif /* SGI_RDUBLK */
   1.434 +    rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf));
   1.435 +    if (rv > 0) {
   1.436 +	RNG_RandomUpdate(buf, sizeof(buf));
   1.437 +    }
   1.438 +    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   1.439 +    if (rv > 0) {
   1.440 +	RNG_RandomUpdate(buf, rv);
   1.441 +    }
   1.442 +    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   1.443 +    if (rv > 0) {
   1.444 +	RNG_RandomUpdate(buf, rv);
   1.445 +    }
   1.446 +    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   1.447 +    if (rv > 0) {
   1.448 +	RNG_RandomUpdate(buf, rv);
   1.449 +    }
   1.450 +}
   1.451 +
   1.452 +static size_t GetHighResClock(void *buf, size_t maxbuf)
   1.453 +{
   1.454 +    unsigned phys_addr, raddr, cycleval;
   1.455 +    static volatile unsigned *iotimer_addr = NULL;
   1.456 +    static int tries = 0;
   1.457 +    static int cntr_size;
   1.458 +    int mfd;
   1.459 +    long s0[2];
   1.460 +    struct timeval tv;
   1.461 +
   1.462 +#ifndef SGI_CYCLECNTR_SIZE
   1.463 +#define SGI_CYCLECNTR_SIZE      165     /* Size user needs to use to read CC */
   1.464 +#endif
   1.465 +
   1.466 +    if (iotimer_addr == NULL) {
   1.467 +	if (tries++ > 1) {
   1.468 +	    /* Don't keep trying if it didn't work */
   1.469 +	    return 0;
   1.470 +	}
   1.471 +
   1.472 +	/*
   1.473 +	** For SGI machines we can use the cycle counter, if it has one,
   1.474 +	** to generate some truly random numbers
   1.475 +	*/
   1.476 +	phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
   1.477 +	if (phys_addr) {
   1.478 +	    int pgsz = getpagesize();
   1.479 +	    int pgoffmask = pgsz - 1;
   1.480 +
   1.481 +	    raddr = phys_addr & ~pgoffmask;
   1.482 +	    mfd = open("/dev/mmem", O_RDONLY);
   1.483 +	    if (mfd < 0) {
   1.484 +		return 0;
   1.485 +	    }
   1.486 +	    iotimer_addr = (unsigned *)
   1.487 +		mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
   1.488 +	    if (iotimer_addr == (void*)-1) {
   1.489 +		close(mfd);
   1.490 +		iotimer_addr = NULL;
   1.491 +		return 0;
   1.492 +	    }
   1.493 +	    iotimer_addr = (unsigned*)
   1.494 +		((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
   1.495 +	    /*
   1.496 +	     * The file 'mfd' is purposefully not closed.
   1.497 +	     */
   1.498 +	    cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
   1.499 +	    if (cntr_size < 0) {
   1.500 +		struct utsname utsinfo;
   1.501 +
   1.502 +		/* 
   1.503 +		 * We must be executing on a 6.0 or earlier system, since the
   1.504 +		 * SGI_CYCLECNTR_SIZE call is not supported.
   1.505 +		 * 
   1.506 +		 * The only pre-6.1 platforms with 64-bit counters are
   1.507 +		 * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
   1.508 +		 */
   1.509 +		uname(&utsinfo);
   1.510 +		if (!strncmp(utsinfo.machine, "IP19", 4) ||
   1.511 +		    !strncmp(utsinfo.machine, "IP21", 4))
   1.512 +			cntr_size = 64;
   1.513 +		else
   1.514 +			cntr_size = 32;
   1.515 +	    }
   1.516 +	    cntr_size /= 8;	/* Convert from bits to bytes */
   1.517 +	}
   1.518 +    }
   1.519 +
   1.520 +    s0[0] = *iotimer_addr;
   1.521 +    if (cntr_size > 4)
   1.522 +	s0[1] = *(iotimer_addr + 1);
   1.523 +    memcpy(buf, (char *)&s0[0], cntr_size);
   1.524 +    return CopyLowBits(buf, maxbuf, &s0, cntr_size);
   1.525 +}
   1.526 +#endif
   1.527 +
   1.528 +#if defined(sony)
   1.529 +#include <sys/systeminfo.h>
   1.530 +
   1.531 +#define getdtablesize() sysconf(_SC_OPEN_MAX)
   1.532 +
   1.533 +static size_t
   1.534 +GetHighResClock(void *buf, size_t maxbytes)
   1.535 +{
   1.536 +    return 0;
   1.537 +}
   1.538 +
   1.539 +static void
   1.540 +GiveSystemInfo(void)
   1.541 +{
   1.542 +    int rv;
   1.543 +    char buf[2000];
   1.544 +
   1.545 +    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   1.546 +    if (rv > 0) {
   1.547 +	RNG_RandomUpdate(buf, rv);
   1.548 +    }
   1.549 +    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   1.550 +    if (rv > 0) {
   1.551 +	RNG_RandomUpdate(buf, rv);
   1.552 +    }
   1.553 +    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   1.554 +    if (rv > 0) {
   1.555 +	RNG_RandomUpdate(buf, rv);
   1.556 +    }
   1.557 +}
   1.558 +#endif /* sony */
   1.559 +
   1.560 +#if defined(sinix)
   1.561 +#include <sys/systeminfo.h>
   1.562 +#include <sys/times.h>
   1.563 +
   1.564 +int gettimeofday(struct timeval *, struct timezone *);
   1.565 +int gethostname(char *, int);
   1.566 +
   1.567 +#define getdtablesize() sysconf(_SC_OPEN_MAX)
   1.568 +
   1.569 +static size_t
   1.570 +GetHighResClock(void *buf, size_t maxbytes)
   1.571 +{
   1.572 +    int ticks;
   1.573 +    struct tms buffer;
   1.574 +
   1.575 +    ticks=times(&buffer);
   1.576 +    return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
   1.577 +}
   1.578 +
   1.579 +static void
   1.580 +GiveSystemInfo(void)
   1.581 +{
   1.582 +    int rv;
   1.583 +    char buf[2000];
   1.584 +
   1.585 +    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   1.586 +    if (rv > 0) {
   1.587 +	RNG_RandomUpdate(buf, rv);
   1.588 +    }
   1.589 +    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   1.590 +    if (rv > 0) {
   1.591 +	RNG_RandomUpdate(buf, rv);
   1.592 +    }
   1.593 +    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   1.594 +    if (rv > 0) {
   1.595 +	RNG_RandomUpdate(buf, rv);
   1.596 +    }
   1.597 +}
   1.598 +#endif /* sinix */
   1.599 +
   1.600 +
   1.601 +#ifdef BEOS
   1.602 +#include <be/kernel/OS.h>
   1.603 +
   1.604 +static size_t
   1.605 +GetHighResClock(void *buf, size_t maxbytes)
   1.606 +{
   1.607 +    bigtime_t bigtime; /* Actually a int64 */
   1.608 +
   1.609 +    bigtime = real_time_clock_usecs();
   1.610 +    return CopyLowBits(buf, maxbytes, &bigtime, sizeof(bigtime));
   1.611 +}
   1.612 +
   1.613 +static void
   1.614 +GiveSystemInfo(void)
   1.615 +{
   1.616 +    system_info *info = NULL;
   1.617 +    PRInt32 val;
   1.618 +    get_system_info(info);
   1.619 +    if (info) {
   1.620 +        val = info->boot_time;
   1.621 +        RNG_RandomUpdate(&val, sizeof(val));
   1.622 +        val = info->used_pages;
   1.623 +        RNG_RandomUpdate(&val, sizeof(val));
   1.624 +        val = info->used_ports;
   1.625 +        RNG_RandomUpdate(&val, sizeof(val));
   1.626 +        val = info->used_threads;
   1.627 +        RNG_RandomUpdate(&val, sizeof(val));
   1.628 +        val = info->used_teams;
   1.629 +        RNG_RandomUpdate(&val, sizeof(val));
   1.630 +    }
   1.631 +}
   1.632 +#endif /* BEOS */
   1.633 +
   1.634 +#if defined(nec_ews)
   1.635 +#include <sys/systeminfo.h>
   1.636 +
   1.637 +#define getdtablesize() sysconf(_SC_OPEN_MAX)
   1.638 +
   1.639 +static size_t
   1.640 +GetHighResClock(void *buf, size_t maxbytes)
   1.641 +{
   1.642 +    return 0;
   1.643 +}
   1.644 +
   1.645 +static void
   1.646 +GiveSystemInfo(void)
   1.647 +{
   1.648 +    int rv;
   1.649 +    char buf[2000];
   1.650 +
   1.651 +    rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   1.652 +    if (rv > 0) {
   1.653 +	RNG_RandomUpdate(buf, rv);
   1.654 +    }
   1.655 +    rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   1.656 +    if (rv > 0) {
   1.657 +	RNG_RandomUpdate(buf, rv);
   1.658 +    }
   1.659 +    rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   1.660 +    if (rv > 0) {
   1.661 +	RNG_RandomUpdate(buf, rv);
   1.662 +    }
   1.663 +}
   1.664 +#endif /* nec_ews */
   1.665 +
   1.666 +size_t RNG_GetNoise(void *buf, size_t maxbytes)
   1.667 +{
   1.668 +    struct timeval tv;
   1.669 +    int n = 0;
   1.670 +    int c;
   1.671 +
   1.672 +    n = GetHighResClock(buf, maxbytes);
   1.673 +    maxbytes -= n;
   1.674 +
   1.675 +    (void)gettimeofday(&tv, 0);
   1.676 +    c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
   1.677 +    n += c;
   1.678 +    maxbytes -= c;
   1.679 +    c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
   1.680 +    n += c;
   1.681 +    return n;
   1.682 +}
   1.683 +
   1.684 +#define SAFE_POPEN_MAXARGS	10	/* must be at least 2 */
   1.685 +
   1.686 +/*
   1.687 + * safe_popen is static to this module and we know what arguments it is
   1.688 + * called with. Note that this version only supports a single open child
   1.689 + * process at any time.
   1.690 + */
   1.691 +static pid_t safe_popen_pid;
   1.692 +static struct sigaction oldact;
   1.693 +
   1.694 +static FILE *
   1.695 +safe_popen(char *cmd)
   1.696 +{
   1.697 +    int p[2], fd, argc;
   1.698 +    pid_t pid;
   1.699 +    char *argv[SAFE_POPEN_MAXARGS + 1];
   1.700 +    FILE *fp;
   1.701 +    static char blank[] = " \t";
   1.702 +    static struct sigaction newact;
   1.703 +
   1.704 +    if (pipe(p) < 0)
   1.705 +	return 0;
   1.706 +
   1.707 +    fp = fdopen(p[0], "r");
   1.708 +    if (fp == 0) {
   1.709 +	close(p[0]);
   1.710 +	close(p[1]);
   1.711 +	return 0;
   1.712 +    }
   1.713 +
   1.714 +    /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
   1.715 +    newact.sa_handler = SIG_DFL;
   1.716 +    newact.sa_flags = 0;
   1.717 +    sigfillset(&newact.sa_mask);
   1.718 +    sigaction (SIGCHLD, &newact, &oldact);
   1.719 +
   1.720 +    pid = fork();
   1.721 +    switch (pid) {
   1.722 +      int ndesc;
   1.723 +
   1.724 +      case -1:
   1.725 +	fclose(fp); /* this closes p[0], the fd associated with fp */
   1.726 +	close(p[1]);
   1.727 +	sigaction (SIGCHLD, &oldact, NULL);
   1.728 +	return 0;
   1.729 +
   1.730 +      case 0:
   1.731 +	/* dup write-side of pipe to stderr and stdout */
   1.732 +	if (p[1] != 1) dup2(p[1], 1);
   1.733 +	if (p[1] != 2) dup2(p[1], 2);
   1.734 +
   1.735 +	/* 
   1.736 +	 * close the other file descriptors, except stdin which we
   1.737 +	 * try reassociating with /dev/null, first (bug 174993)
   1.738 +	 */
   1.739 +	if (!freopen("/dev/null", "r", stdin))
   1.740 +	    close(0);
   1.741 +	ndesc = getdtablesize();
   1.742 +	for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd));
   1.743 +
   1.744 +	/* clean up environment in the child process */
   1.745 +	putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
   1.746 +	putenv("SHELL=/bin/sh");
   1.747 +	putenv("IFS= \t");
   1.748 +
   1.749 +	/*
   1.750 +	 * The caller may have passed us a string that is in text
   1.751 +	 * space. It may be illegal to modify the string
   1.752 +	 */
   1.753 +	cmd = strdup(cmd);
   1.754 +	/* format argv */
   1.755 +	argv[0] = strtok(cmd, blank);
   1.756 +	argc = 1;
   1.757 +	while ((argv[argc] = strtok(0, blank)) != 0) {
   1.758 +	    if (++argc == SAFE_POPEN_MAXARGS) {
   1.759 +		argv[argc] = 0;
   1.760 +		break;
   1.761 +	    }
   1.762 +	}
   1.763 +
   1.764 +	/* and away we go */
   1.765 +	execvp(argv[0], argv);
   1.766 +	exit(127);
   1.767 +	break;
   1.768 +
   1.769 +      default:
   1.770 +	close(p[1]);
   1.771 +	break;
   1.772 +    }
   1.773 +
   1.774 +    /* non-zero means there's a cmd running */
   1.775 +    safe_popen_pid = pid;
   1.776 +    return fp;
   1.777 +}
   1.778 +
   1.779 +static int
   1.780 +safe_pclose(FILE *fp)
   1.781 +{
   1.782 +    pid_t pid;
   1.783 +    int status = -1, rv;
   1.784 +
   1.785 +    if ((pid = safe_popen_pid) == 0)
   1.786 +	return -1;
   1.787 +    safe_popen_pid = 0;
   1.788 +
   1.789 +    fclose(fp);
   1.790 +
   1.791 +    /* yield the processor so the child gets some time to exit normally */
   1.792 +    PR_Sleep(PR_INTERVAL_NO_WAIT);
   1.793 +
   1.794 +    /* if the child hasn't exited, kill it -- we're done with its output */
   1.795 +    while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR)
   1.796 +	;
   1.797 +    if (rv == 0) {
   1.798 +	kill(pid, SIGKILL);
   1.799 +	while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
   1.800 +	    ;
   1.801 +    }
   1.802 +
   1.803 +    /* Reset SIGCHLD signal hander before returning */
   1.804 +    sigaction(SIGCHLD, &oldact, NULL);
   1.805 +
   1.806 +    return status;
   1.807 +}
   1.808 +
   1.809 +#ifdef DARWIN
   1.810 +#include <TargetConditionals.h>
   1.811 +#if !TARGET_OS_IPHONE
   1.812 +#include <crt_externs.h>
   1.813 +#endif
   1.814 +#endif
   1.815 +
   1.816 +/* Fork netstat to collect its output by default. Do not unset this unless
   1.817 + * another source of entropy is available
   1.818 + */
   1.819 +#define DO_NETSTAT 1
   1.820 +
   1.821 +void RNG_SystemInfoForRNG(void)
   1.822 +{
   1.823 +    FILE *fp;
   1.824 +    char buf[BUFSIZ];
   1.825 +    size_t bytes;
   1.826 +    const char * const *cp;
   1.827 +    char *randfile;
   1.828 +#ifdef DARWIN
   1.829 +#if TARGET_OS_IPHONE
   1.830 +    /* iOS does not expose a way to access environ. */
   1.831 +    char **environ = NULL;
   1.832 +#else
   1.833 +    char **environ = *_NSGetEnviron();
   1.834 +#endif
   1.835 +#else
   1.836 +    extern char **environ;
   1.837 +#endif
   1.838 +#ifdef BEOS
   1.839 +    static const char * const files[] = {
   1.840 +	"/boot/var/swap",
   1.841 +	"/boot/var/log/syslog",
   1.842 +	"/boot/var/tmp",
   1.843 +	"/boot/home/config/settings",
   1.844 +	"/boot/home",
   1.845 +	0
   1.846 +    };
   1.847 +#else
   1.848 +    static const char * const files[] = {
   1.849 +	"/etc/passwd",
   1.850 +	"/etc/utmp",
   1.851 +	"/tmp",
   1.852 +	"/var/tmp",
   1.853 +	"/usr/tmp",
   1.854 +	0
   1.855 +    };
   1.856 +#endif
   1.857 +
   1.858 +#if defined(BSDI)
   1.859 +    static char netstat_ni_cmd[] = "netstat -nis";
   1.860 +#else
   1.861 +    static char netstat_ni_cmd[] = "netstat -ni";
   1.862 +#endif
   1.863 +
   1.864 +    GiveSystemInfo();
   1.865 +
   1.866 +    bytes = RNG_GetNoise(buf, sizeof(buf));
   1.867 +    RNG_RandomUpdate(buf, bytes);
   1.868 +
   1.869 +    /*
   1.870 +     * Pass the C environment and the addresses of the pointers to the
   1.871 +     * hash function. This makes the random number function depend on the
   1.872 +     * execution environment of the user and on the platform the program
   1.873 +     * is running on.
   1.874 +     */
   1.875 +    if (environ != NULL) {
   1.876 +        cp = (const char * const *) environ;
   1.877 +        while (*cp) {
   1.878 +	    RNG_RandomUpdate(*cp, strlen(*cp));
   1.879 +	    cp++;
   1.880 +        }
   1.881 +        RNG_RandomUpdate(environ, (char*)cp - (char*)environ);
   1.882 +    }
   1.883 +
   1.884 +    /* Give in system information */
   1.885 +    if (gethostname(buf, sizeof(buf)) == 0) {
   1.886 +	RNG_RandomUpdate(buf, strlen(buf));
   1.887 +    }
   1.888 +    GiveSystemInfo();
   1.889 +
   1.890 +    /* grab some data from system's PRNG before any other files. */
   1.891 +    bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);
   1.892 +
   1.893 +    /* If the user points us to a random file, pass it through the rng */
   1.894 +    randfile = getenv("NSRANDFILE");
   1.895 +    if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) {
   1.896 +	char *randCountString = getenv("NSRANDCOUNT");
   1.897 +	int randCount = randCountString ? atoi(randCountString) : 0;
   1.898 +	if (randCount != 0) {
   1.899 +	    RNG_FileUpdate(randfile, randCount);
   1.900 +	} else {
   1.901 +	    RNG_FileForRNG(randfile);
   1.902 +	}
   1.903 +    }
   1.904 +
   1.905 +    /* pass other files through */
   1.906 +    for (cp = files; *cp; cp++)
   1.907 +	RNG_FileForRNG(*cp);
   1.908 +
   1.909 +/*
   1.910 + * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen
   1.911 + * in a pthreads environment.  Therefore, we call safe_popen last and on
   1.912 + * BSD/OS we do not call safe_popen when we succeeded in getting data
   1.913 + * from /dev/urandom.
   1.914 + *
   1.915 + * Bug 174993: On platforms providing /dev/urandom, don't fork netstat
   1.916 + * either, if data has been gathered successfully.
   1.917 + */
   1.918 +
   1.919 +#if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \
   1.920 +    || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) \
   1.921 +    || defined(HPUX)
   1.922 +    if (bytes)
   1.923 +        return;
   1.924 +#endif
   1.925 +
   1.926 +#ifdef SOLARIS
   1.927 +
   1.928 +/*
   1.929 + * On Solaris, NSS may be initialized automatically from libldap in
   1.930 + * applications that are unaware of the use of NSS. safe_popen forks, and
   1.931 + * sometimes creates issues with some applications' pthread_atfork handlers.
   1.932 + * We always have /dev/urandom on Solaris 9 and above as an entropy source,
   1.933 + * and for Solaris 8 we have the libkstat interface, so we don't need to
   1.934 + * fork netstat.
   1.935 + */
   1.936 +
   1.937 +#undef DO_NETSTAT
   1.938 +    if (!bytes) {
   1.939 +        /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
   1.940 +        PRUint32 kstat_bytes = 0;
   1.941 +        if (SECSuccess != RNG_kstat(&kstat_bytes)) {
   1.942 +            PORT_Assert(0);
   1.943 +        }
   1.944 +        bytes += kstat_bytes;
   1.945 +        PORT_Assert(bytes);
   1.946 +    }
   1.947 +#endif
   1.948 +
   1.949 +#ifdef DO_NETSTAT
   1.950 +    fp = safe_popen(netstat_ni_cmd);
   1.951 +    if (fp != NULL) {
   1.952 +	while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
   1.953 +	    RNG_RandomUpdate(buf, bytes);
   1.954 +	safe_pclose(fp);
   1.955 +    }
   1.956 +#endif
   1.957 +
   1.958 +}
   1.959 +
   1.960 +#define TOTAL_FILE_LIMIT 1000000	/* one million */
   1.961 +
   1.962 +size_t RNG_FileUpdate(const char *fileName, size_t limit)
   1.963 +{
   1.964 +    FILE *        file;
   1.965 +    int           fd;
   1.966 +    int           bytes;
   1.967 +    size_t        fileBytes = 0;
   1.968 +    struct stat   stat_buf;
   1.969 +    unsigned char buffer[BUFSIZ];
   1.970 +    static size_t totalFileBytes = 0;
   1.971 +    
   1.972 +    /* suppress valgrind warnings due to holes in struct stat */
   1.973 +    memset(&stat_buf, 0, sizeof(stat_buf));
   1.974 +
   1.975 +    if (stat((char *)fileName, &stat_buf) < 0)
   1.976 +	return fileBytes;
   1.977 +    RNG_RandomUpdate(&stat_buf, sizeof(stat_buf));
   1.978 +    
   1.979 +    file = fopen(fileName, "r");
   1.980 +    if (file != NULL) {
   1.981 +	/* Read from the underlying file descriptor directly to bypass stdio
   1.982 +	 * buffering and avoid reading more bytes than we need from
   1.983 +	 * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because
   1.984 +	 * fread may return EOF in unbuffered I/O mode on Android.
   1.985 +	 *
   1.986 +	 * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O
   1.987 +	 * has no performance advantage. */
   1.988 +	fd = fileno(file);
   1.989 +	/* 'file' was just opened, so this should not fail. */
   1.990 +	PORT_Assert(fd != -1);
   1.991 +	while (limit > fileBytes) {
   1.992 +	    bytes = PR_MIN(sizeof buffer, limit - fileBytes);
   1.993 +	    bytes = read(fd, buffer, bytes);
   1.994 +	    if (bytes <= 0)
   1.995 +		break;
   1.996 +	    RNG_RandomUpdate(buffer, bytes);
   1.997 +	    fileBytes      += bytes;
   1.998 +	    totalFileBytes += bytes;
   1.999 +	    /* after TOTAL_FILE_LIMIT has been reached, only read in first
  1.1000 +	    ** buffer of data from each subsequent file.
  1.1001 +	    */
  1.1002 +	    if (totalFileBytes > TOTAL_FILE_LIMIT) 
  1.1003 +		break;
  1.1004 +	}
  1.1005 +	fclose(file);
  1.1006 +    }
  1.1007 +    /*
  1.1008 +     * Pass yet another snapshot of our highest resolution clock into
  1.1009 +     * the hash function.
  1.1010 +     */
  1.1011 +    bytes = RNG_GetNoise(buffer, sizeof(buffer));
  1.1012 +    RNG_RandomUpdate(buffer, bytes);
  1.1013 +    return fileBytes;
  1.1014 +}
  1.1015 +
  1.1016 +void RNG_FileForRNG(const char *fileName)
  1.1017 +{
  1.1018 +    RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT);
  1.1019 +}
  1.1020 +
  1.1021 +void ReadSingleFile(const char *fileName)
  1.1022 +{
  1.1023 +    FILE *        file;
  1.1024 +    unsigned char buffer[BUFSIZ];
  1.1025 +    
  1.1026 +    file = fopen(fileName, "rb");
  1.1027 +    if (file != NULL) {
  1.1028 +	while (fread(buffer, 1, sizeof(buffer), file) > 0)
  1.1029 +	    ;
  1.1030 +	fclose(file);
  1.1031 +    } 
  1.1032 +}
  1.1033 +
  1.1034 +#define _POSIX_PTHREAD_SEMANTICS
  1.1035 +#include <dirent.h>
  1.1036 +
  1.1037 +PRBool
  1.1038 +ReadFileOK(char *dir, char *file)
  1.1039 +{
  1.1040 +    struct stat   stat_buf;
  1.1041 +    char filename[PATH_MAX];
  1.1042 +    int count = snprintf(filename, sizeof filename, "%s/%s",dir, file);
  1.1043 +
  1.1044 +    if (count <= 0) {
  1.1045 +	return PR_FALSE; /* name too long, can't read it anyway */
  1.1046 +    }
  1.1047 +    
  1.1048 +    if (stat(filename, &stat_buf) < 0)
  1.1049 +	return PR_FALSE; /* can't stat, probably can't read it then as well */
  1.1050 +    return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE;
  1.1051 +}
  1.1052 +
  1.1053 +/*
  1.1054 + * read one file out of either /etc or the user's home directory.
  1.1055 + * fileToRead tells which file to read.
  1.1056 + *
  1.1057 + * return 1 if it's time to reset the fileToRead (no more files to read).
  1.1058 + */
  1.1059 +int ReadOneFile(int fileToRead)
  1.1060 +{
  1.1061 +    char *dir = "/etc";
  1.1062 +    DIR *fd = opendir(dir);
  1.1063 +    int resetCount = 0;
  1.1064 +#ifdef SOLARIS
  1.1065 +     /* grumble, Solaris does not define struct dirent to be the full length */
  1.1066 +    typedef union {
  1.1067 +	unsigned char space[sizeof(struct dirent) + MAXNAMELEN];
  1.1068 +	struct dirent dir;
  1.1069 +    } dirent_hack;
  1.1070 +    dirent_hack entry, firstEntry;
  1.1071 +
  1.1072 +#define entry_dir entry.dir
  1.1073 +#else
  1.1074 +    struct dirent entry, firstEntry;
  1.1075 +#define entry_dir entry
  1.1076 +#endif
  1.1077 +
  1.1078 +    int i, error = -1;
  1.1079 +
  1.1080 +    if (fd == NULL) {
  1.1081 +	dir = getenv("HOME");
  1.1082 +	if (dir) {
  1.1083 +	    fd = opendir(dir);
  1.1084 +	}
  1.1085 +    }
  1.1086 +    if (fd == NULL) {
  1.1087 +	return 1;
  1.1088 +    }
  1.1089 +
  1.1090 +    for (i=0; i <= fileToRead; i++) {
  1.1091 +	struct dirent *result = NULL;
  1.1092 +	do {
  1.1093 +	    error = readdir_r(fd, &entry_dir, &result);
  1.1094 +	} while (error == 0 && result != NULL  &&
  1.1095 +					!ReadFileOK(dir,&result->d_name[0]));
  1.1096 +	if (error != 0 || result == NULL)  {
  1.1097 +	    resetCount = 1; /* read to the end, start again at the beginning */
  1.1098 +	    if (i != 0) {
  1.1099 +		/* ran out of entries in the directory, use the first one */
  1.1100 +	 	entry = firstEntry;
  1.1101 +	 	error = 0;
  1.1102 +	 	break;
  1.1103 +	    }
  1.1104 +	    /* if i== 0, there were no readable entries in the directory */
  1.1105 +	    break;
  1.1106 +	}
  1.1107 +	if (i==0) {
  1.1108 +	    /* save the first entry in case we run out of entries */
  1.1109 +	    firstEntry = entry;
  1.1110 +	}
  1.1111 +    }
  1.1112 +
  1.1113 +    if (error == 0) {
  1.1114 +	char filename[PATH_MAX];
  1.1115 +	int count = snprintf(filename, sizeof filename, 
  1.1116 +				"%s/%s",dir, &entry_dir.d_name[0]);
  1.1117 +	if (count >= 1) {
  1.1118 +	    ReadSingleFile(filename);
  1.1119 +	}
  1.1120 +    } 
  1.1121 +
  1.1122 +    closedir(fd);
  1.1123 +    return resetCount;
  1.1124 +}
  1.1125 +
  1.1126 +/*
  1.1127 + * do something to try to introduce more noise into the 'GetNoise' call
  1.1128 + */
  1.1129 +static void rng_systemJitter(void)
  1.1130 +{
  1.1131 +   static int fileToRead = 1;
  1.1132 +
  1.1133 +   if (ReadOneFile(fileToRead)) {
  1.1134 +	fileToRead = 1;
  1.1135 +   } else {
  1.1136 +	fileToRead++;
  1.1137 +   }
  1.1138 +}
  1.1139 +
  1.1140 +size_t RNG_SystemRNG(void *dest, size_t maxLen)
  1.1141 +{
  1.1142 +    FILE *file;
  1.1143 +    int fd;
  1.1144 +    int bytes;
  1.1145 +    size_t fileBytes = 0;
  1.1146 +    unsigned char *buffer = dest;
  1.1147 +
  1.1148 +    file = fopen("/dev/urandom", "r");
  1.1149 +    if (file == NULL) {
  1.1150 +	return rng_systemFromNoise(dest, maxLen);
  1.1151 +    }
  1.1152 +    /* Read from the underlying file descriptor directly to bypass stdio
  1.1153 +     * buffering and avoid reading more bytes than we need from /dev/urandom.
  1.1154 +     * NOTE: we can't use fread with unbuffered I/O because fread may return
  1.1155 +     * EOF in unbuffered I/O mode on Android.
  1.1156 +     */
  1.1157 +    fd = fileno(file);
  1.1158 +    /* 'file' was just opened, so this should not fail. */
  1.1159 +    PORT_Assert(fd != -1);
  1.1160 +    while (maxLen > fileBytes) {
  1.1161 +	bytes = maxLen - fileBytes;
  1.1162 +	bytes = read(fd, buffer, bytes);
  1.1163 +	if (bytes <= 0)
  1.1164 +	    break;
  1.1165 +	fileBytes += bytes;
  1.1166 +	buffer += bytes;
  1.1167 +    }
  1.1168 +    fclose(file);
  1.1169 +    if (fileBytes != maxLen) {
  1.1170 +	PORT_SetError(SEC_ERROR_NEED_RANDOM);  /* system RNG failed */
  1.1171 +	fileBytes = 0;
  1.1172 +    }
  1.1173 +    return fileBytes;
  1.1174 +}

mercurial