~ubuntu-branches/ubuntu/trusty/xulrunner/trusty

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