security/nss/lib/freebl/unix_rand.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include <stdio.h>
     6 #include <string.h>
     7 #include <signal.h>
     8 #include <unistd.h>
     9 #include <limits.h>
    10 #include <errno.h>
    11 #include <stdlib.h>
    12 #include <sys/time.h>
    13 #include <sys/wait.h>
    14 #include <sys/stat.h>
    15 #include "secrng.h"
    16 #include "secerr.h"
    17 #include "prerror.h"
    18 #include "prthread.h"
    19 #include "prprf.h"
    21 size_t RNG_FileUpdate(const char *fileName, size_t limit);
    23 /*
    24  * When copying data to the buffer we want the least signicant bytes
    25  * from the input since those bits are changing the fastest. The address
    26  * of least significant byte depends upon whether we are running on
    27  * a big-endian or little-endian machine.
    28  *
    29  * Does this mean the least signicant bytes are the most significant
    30  * to us? :-)
    31  */
    33 static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen)
    34 {
    35     union endianness {
    36 	PRInt32 i;
    37 	char c[4];
    38     } u;
    40     if (srclen <= dstlen) {
    41 	memcpy(dst, src, srclen);
    42 	return srclen;
    43     }
    44     u.i = 0x01020304;
    45     if (u.c[0] == 0x01) {
    46 	/* big-endian case */
    47 	memcpy(dst, (char*)src + (srclen - dstlen), dstlen);
    48     } else {
    49 	/* little-endian case */
    50 	memcpy(dst, src, dstlen);
    51     }
    52     return dstlen;
    53 }
    55 #ifdef SOLARIS
    57 #include <kstat.h>
    59 static const PRUint32 entropy_buf_len = 4096; /* buffer up to 4 KB */
    61 /* Buffer entropy data, and feed it to the RNG, entropy_buf_len bytes at a time.
    62  * Returns error if RNG_RandomUpdate fails. Also increments *total_fed
    63  * by the number of bytes successfully buffered.
    64  */
    65 static SECStatus BufferEntropy(char* inbuf, PRUint32 inlen,
    66                                 char* entropy_buf, PRUint32* entropy_buffered,
    67                                 PRUint32* total_fed)
    68 {
    69     PRUint32 tocopy = 0;
    70     PRUint32 avail = 0;
    71     SECStatus rv = SECSuccess;
    73     while (inlen) {
    74         avail = entropy_buf_len - *entropy_buffered;
    75         if (!avail) {
    76             /* Buffer is full, time to feed it to the RNG. */
    77             rv = RNG_RandomUpdate(entropy_buf, entropy_buf_len);
    78             if (SECSuccess != rv) {
    79                 break;
    80             }
    81             *entropy_buffered = 0;
    82             avail = entropy_buf_len;
    83         }
    84         tocopy = PR_MIN(avail, inlen);
    85         memcpy(entropy_buf + *entropy_buffered, inbuf, tocopy);
    86         *entropy_buffered += tocopy;
    87         inlen -= tocopy;
    88         inbuf += tocopy;
    89         *total_fed += tocopy;
    90     }
    91     return rv;
    92 }
    94 /* Feed kernel statistics structures and ks_data field to the RNG.
    95  * Returns status as well as the number of bytes successfully fed to the RNG.
    96  */
    97 static SECStatus RNG_kstat(PRUint32* fed)
    98 {
    99     kstat_ctl_t*    kc = NULL;
   100     kstat_t*        ksp = NULL;
   101     PRUint32        entropy_buffered = 0;
   102     char*           entropy_buf = NULL;
   103     SECStatus       rv = SECSuccess;
   105     PORT_Assert(fed);
   106     if (!fed) {
   107         return SECFailure;
   108     }
   109     *fed = 0;
   111     kc = kstat_open();
   112     PORT_Assert(kc);
   113     if (!kc) {
   114         return SECFailure;
   115     }
   116     entropy_buf = (char*) PORT_Alloc(entropy_buf_len);
   117     PORT_Assert(entropy_buf);
   118     if (entropy_buf) {
   119         for (ksp = kc->kc_chain; ksp != NULL; ksp = ksp->ks_next) {
   120             if (-1 == kstat_read(kc, ksp, NULL)) {
   121                 /* missing data from a single kstat shouldn't be fatal */
   122                 continue;
   123             }
   124             rv = BufferEntropy((char*)ksp, sizeof(kstat_t),
   125                                     entropy_buf, &entropy_buffered,
   126                                     fed);
   127             if (SECSuccess != rv) {
   128                 break;
   129             }
   131             if (ksp->ks_data && ksp->ks_data_size>0 && ksp->ks_ndata>0) {
   132                 rv = BufferEntropy((char*)ksp->ks_data, ksp->ks_data_size,
   133                                         entropy_buf, &entropy_buffered,
   134                                         fed);
   135                 if (SECSuccess != rv) {
   136                     break;
   137                 }
   138             }
   139         }
   140         if (SECSuccess == rv && entropy_buffered) {
   141             /* Buffer is not empty, time to feed it to the RNG */
   142             rv = RNG_RandomUpdate(entropy_buf, entropy_buffered);
   143         }
   144         PORT_Free(entropy_buf);
   145     } else {
   146         rv = SECFailure;
   147     }
   148     if (kstat_close(kc)) {
   149         PORT_Assert(0);
   150         rv = SECFailure;
   151     }
   152     return rv;
   153 }
   155 #endif
   157 #if defined(SCO) || defined(UNIXWARE) || defined(BSDI) || defined(FREEBSD) \
   158     || defined(NETBSD) || defined(DARWIN) || defined(OPENBSD) \
   159     || defined(NTO) || defined(__riscos__)
   160 #include <sys/times.h>
   162 #define getdtablesize() sysconf(_SC_OPEN_MAX)
   164 static size_t
   165 GetHighResClock(void *buf, size_t maxbytes)
   166 {
   167     int ticks;
   168     struct tms buffer;
   170     ticks=times(&buffer);
   171     return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
   172 }
   174 static void
   175 GiveSystemInfo(void)
   176 {
   177     long si;
   179     /* 
   180      * Is this really necessary?  Why not use rand48 or something?
   181      */
   182     si = sysconf(_SC_CHILD_MAX);
   183     RNG_RandomUpdate(&si, sizeof(si));
   185     si = sysconf(_SC_STREAM_MAX);
   186     RNG_RandomUpdate(&si, sizeof(si));
   188     si = sysconf(_SC_OPEN_MAX);
   189     RNG_RandomUpdate(&si, sizeof(si));
   190 }
   191 #endif
   193 #if defined(__sun)
   194 #if defined(__svr4) || defined(SVR4)
   195 #include <sys/systeminfo.h>
   197 #define getdtablesize() sysconf(_SC_OPEN_MAX)
   199 static void
   200 GiveSystemInfo(void)
   201 {
   202     int rv;
   203     char buf[2000];
   205     rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   206     if (rv > 0) {
   207 	RNG_RandomUpdate(buf, rv);
   208     }
   209     rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   210     if (rv > 0) {
   211 	RNG_RandomUpdate(buf, rv);
   212     }
   213     rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   214     if (rv > 0) {
   215 	RNG_RandomUpdate(buf, rv);
   216     }
   217 }
   219 static size_t
   220 GetHighResClock(void *buf, size_t maxbytes)
   221 {
   222     hrtime_t t;
   223     t = gethrtime();
   224     if (t) {
   225 	return CopyLowBits(buf, maxbytes, &t, sizeof(t));
   226     }
   227     return 0;
   228 }
   229 #else /* SunOS (Sun, but not SVR4) */
   231 extern long sysconf(int name);
   233 static size_t
   234 GetHighResClock(void *buf, size_t maxbytes)
   235 {
   236     return 0;
   237 }
   239 static void
   240 GiveSystemInfo(void)
   241 {
   242     long si;
   244     /* This is not very good */
   245     si = sysconf(_SC_CHILD_MAX);
   246     RNG_RandomUpdate(&si, sizeof(si));
   247 }
   248 #endif
   249 #endif /* Sun */
   251 #if defined(__hpux)
   252 #include <sys/unistd.h>
   254 #define getdtablesize() sysconf(_SC_OPEN_MAX)
   256 #if defined(__ia64)
   257 #include <ia64/sys/inline.h>
   259 static size_t
   260 GetHighResClock(void *buf, size_t maxbytes)
   261 {
   262     PRUint64 t;
   264     t = _Asm_mov_from_ar(_AREG44);
   265     return CopyLowBits(buf, maxbytes, &t, sizeof(t));
   266 }
   267 #else
   268 static size_t
   269 GetHighResClock(void *buf, size_t maxbytes)
   270 {
   271     extern int ret_cr16();
   272     int cr16val;
   274     cr16val = ret_cr16();
   275     return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val));
   276 }
   277 #endif
   279 static void
   280 GiveSystemInfo(void)
   281 {
   282     long si;
   284     /* This is not very good */
   285     si = sysconf(_AES_OS_VERSION);
   286     RNG_RandomUpdate(&si, sizeof(si));
   287     si = sysconf(_SC_CPU_VERSION);
   288     RNG_RandomUpdate(&si, sizeof(si));
   289 }
   290 #endif /* HPUX */
   292 #if defined(OSF1)
   293 #include <sys/types.h>
   294 #include <sys/sysinfo.h>
   295 #include <sys/systeminfo.h>
   296 #include <c_asm.h>
   298 static void
   299 GiveSystemInfo(void)
   300 {
   301     char buf[BUFSIZ];
   302     int rv;
   303     int off = 0;
   305     rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   306     if (rv > 0) {
   307 	RNG_RandomUpdate(buf, rv);
   308     }
   309     rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   310     if (rv > 0) {
   311 	RNG_RandomUpdate(buf, rv);
   312     }
   313     rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   314     if (rv > 0) {
   315 	RNG_RandomUpdate(buf, rv);
   316     }
   317 }
   319 /*
   320  * Use the "get the cycle counter" instruction on the alpha.
   321  * The low 32 bits completely turn over in less than a minute.
   322  * The high 32 bits are some non-counter gunk that changes sometimes.
   323  */
   324 static size_t
   325 GetHighResClock(void *buf, size_t maxbytes)
   326 {
   327     unsigned long t;
   329     t = asm("rpcc %v0");
   330     return CopyLowBits(buf, maxbytes, &t, sizeof(t));
   331 }
   333 #endif /* Alpha */
   335 #if defined(_IBMR2)
   336 static size_t
   337 GetHighResClock(void *buf, size_t maxbytes)
   338 {
   339     return 0;
   340 }
   342 static void
   343 GiveSystemInfo(void)
   344 {
   345     /* XXX haven't found any yet! */
   346 }
   347 #endif /* IBM R2 */
   349 #if defined(LINUX)
   350 #include <sys/sysinfo.h>
   352 static size_t
   353 GetHighResClock(void *buf, size_t maxbytes)
   354 {
   355     return 0;
   356 }
   358 static void
   359 GiveSystemInfo(void)
   360 {
   361 #ifndef NO_SYSINFO
   362     struct sysinfo si;
   363     if (sysinfo(&si) == 0) {
   364 	RNG_RandomUpdate(&si, sizeof(si));
   365     }
   366 #endif
   367 }
   368 #endif /* LINUX */
   370 #if defined(NCR)
   372 #include <sys/utsname.h>
   373 #include <sys/systeminfo.h>
   375 #define getdtablesize() sysconf(_SC_OPEN_MAX)
   377 static size_t
   378 GetHighResClock(void *buf, size_t maxbytes)
   379 {
   380     return 0;
   381 }
   383 static void
   384 GiveSystemInfo(void)
   385 {
   386     int rv;
   387     char buf[2000];
   389     rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   390     if (rv > 0) {
   391 	RNG_RandomUpdate(buf, rv);
   392     }
   393     rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   394     if (rv > 0) {
   395 	RNG_RandomUpdate(buf, rv);
   396     }
   397     rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   398     if (rv > 0) {
   399 	RNG_RandomUpdate(buf, rv);
   400     }
   401 }
   403 #endif /* NCR */
   405 #if defined(sgi)
   406 #include <fcntl.h>
   407 #undef PRIVATE
   408 #include <sys/mman.h>
   409 #include <sys/syssgi.h>
   410 #include <sys/immu.h>
   411 #include <sys/systeminfo.h>
   412 #include <sys/utsname.h>
   413 #include <wait.h>
   415 static void
   416 GiveSystemInfo(void)
   417 {
   418     int rv;
   419     char buf[4096];
   421     rv = syssgi(SGI_SYSID, &buf[0]);
   422     if (rv > 0) {
   423 	RNG_RandomUpdate(buf, MAXSYSIDSIZE);
   424     }
   425 #ifdef SGI_RDUBLK
   426     rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf));
   427     if (rv > 0) {
   428 	RNG_RandomUpdate(buf, sizeof(buf));
   429     }
   430 #endif /* SGI_RDUBLK */
   431     rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf));
   432     if (rv > 0) {
   433 	RNG_RandomUpdate(buf, sizeof(buf));
   434     }
   435     rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   436     if (rv > 0) {
   437 	RNG_RandomUpdate(buf, rv);
   438     }
   439     rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   440     if (rv > 0) {
   441 	RNG_RandomUpdate(buf, rv);
   442     }
   443     rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   444     if (rv > 0) {
   445 	RNG_RandomUpdate(buf, rv);
   446     }
   447 }
   449 static size_t GetHighResClock(void *buf, size_t maxbuf)
   450 {
   451     unsigned phys_addr, raddr, cycleval;
   452     static volatile unsigned *iotimer_addr = NULL;
   453     static int tries = 0;
   454     static int cntr_size;
   455     int mfd;
   456     long s0[2];
   457     struct timeval tv;
   459 #ifndef SGI_CYCLECNTR_SIZE
   460 #define SGI_CYCLECNTR_SIZE      165     /* Size user needs to use to read CC */
   461 #endif
   463     if (iotimer_addr == NULL) {
   464 	if (tries++ > 1) {
   465 	    /* Don't keep trying if it didn't work */
   466 	    return 0;
   467 	}
   469 	/*
   470 	** For SGI machines we can use the cycle counter, if it has one,
   471 	** to generate some truly random numbers
   472 	*/
   473 	phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval);
   474 	if (phys_addr) {
   475 	    int pgsz = getpagesize();
   476 	    int pgoffmask = pgsz - 1;
   478 	    raddr = phys_addr & ~pgoffmask;
   479 	    mfd = open("/dev/mmem", O_RDONLY);
   480 	    if (mfd < 0) {
   481 		return 0;
   482 	    }
   483 	    iotimer_addr = (unsigned *)
   484 		mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr);
   485 	    if (iotimer_addr == (void*)-1) {
   486 		close(mfd);
   487 		iotimer_addr = NULL;
   488 		return 0;
   489 	    }
   490 	    iotimer_addr = (unsigned*)
   491 		((__psint_t)iotimer_addr | (phys_addr & pgoffmask));
   492 	    /*
   493 	     * The file 'mfd' is purposefully not closed.
   494 	     */
   495 	    cntr_size = syssgi(SGI_CYCLECNTR_SIZE);
   496 	    if (cntr_size < 0) {
   497 		struct utsname utsinfo;
   499 		/* 
   500 		 * We must be executing on a 6.0 or earlier system, since the
   501 		 * SGI_CYCLECNTR_SIZE call is not supported.
   502 		 * 
   503 		 * The only pre-6.1 platforms with 64-bit counters are
   504 		 * IP19 and IP21 (Challenge, PowerChallenge, Onyx).
   505 		 */
   506 		uname(&utsinfo);
   507 		if (!strncmp(utsinfo.machine, "IP19", 4) ||
   508 		    !strncmp(utsinfo.machine, "IP21", 4))
   509 			cntr_size = 64;
   510 		else
   511 			cntr_size = 32;
   512 	    }
   513 	    cntr_size /= 8;	/* Convert from bits to bytes */
   514 	}
   515     }
   517     s0[0] = *iotimer_addr;
   518     if (cntr_size > 4)
   519 	s0[1] = *(iotimer_addr + 1);
   520     memcpy(buf, (char *)&s0[0], cntr_size);
   521     return CopyLowBits(buf, maxbuf, &s0, cntr_size);
   522 }
   523 #endif
   525 #if defined(sony)
   526 #include <sys/systeminfo.h>
   528 #define getdtablesize() sysconf(_SC_OPEN_MAX)
   530 static size_t
   531 GetHighResClock(void *buf, size_t maxbytes)
   532 {
   533     return 0;
   534 }
   536 static void
   537 GiveSystemInfo(void)
   538 {
   539     int rv;
   540     char buf[2000];
   542     rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   543     if (rv > 0) {
   544 	RNG_RandomUpdate(buf, rv);
   545     }
   546     rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   547     if (rv > 0) {
   548 	RNG_RandomUpdate(buf, rv);
   549     }
   550     rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   551     if (rv > 0) {
   552 	RNG_RandomUpdate(buf, rv);
   553     }
   554 }
   555 #endif /* sony */
   557 #if defined(sinix)
   558 #include <sys/systeminfo.h>
   559 #include <sys/times.h>
   561 int gettimeofday(struct timeval *, struct timezone *);
   562 int gethostname(char *, int);
   564 #define getdtablesize() sysconf(_SC_OPEN_MAX)
   566 static size_t
   567 GetHighResClock(void *buf, size_t maxbytes)
   568 {
   569     int ticks;
   570     struct tms buffer;
   572     ticks=times(&buffer);
   573     return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks));
   574 }
   576 static void
   577 GiveSystemInfo(void)
   578 {
   579     int rv;
   580     char buf[2000];
   582     rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   583     if (rv > 0) {
   584 	RNG_RandomUpdate(buf, rv);
   585     }
   586     rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   587     if (rv > 0) {
   588 	RNG_RandomUpdate(buf, rv);
   589     }
   590     rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   591     if (rv > 0) {
   592 	RNG_RandomUpdate(buf, rv);
   593     }
   594 }
   595 #endif /* sinix */
   598 #ifdef BEOS
   599 #include <be/kernel/OS.h>
   601 static size_t
   602 GetHighResClock(void *buf, size_t maxbytes)
   603 {
   604     bigtime_t bigtime; /* Actually a int64 */
   606     bigtime = real_time_clock_usecs();
   607     return CopyLowBits(buf, maxbytes, &bigtime, sizeof(bigtime));
   608 }
   610 static void
   611 GiveSystemInfo(void)
   612 {
   613     system_info *info = NULL;
   614     PRInt32 val;
   615     get_system_info(info);
   616     if (info) {
   617         val = info->boot_time;
   618         RNG_RandomUpdate(&val, sizeof(val));
   619         val = info->used_pages;
   620         RNG_RandomUpdate(&val, sizeof(val));
   621         val = info->used_ports;
   622         RNG_RandomUpdate(&val, sizeof(val));
   623         val = info->used_threads;
   624         RNG_RandomUpdate(&val, sizeof(val));
   625         val = info->used_teams;
   626         RNG_RandomUpdate(&val, sizeof(val));
   627     }
   628 }
   629 #endif /* BEOS */
   631 #if defined(nec_ews)
   632 #include <sys/systeminfo.h>
   634 #define getdtablesize() sysconf(_SC_OPEN_MAX)
   636 static size_t
   637 GetHighResClock(void *buf, size_t maxbytes)
   638 {
   639     return 0;
   640 }
   642 static void
   643 GiveSystemInfo(void)
   644 {
   645     int rv;
   646     char buf[2000];
   648     rv = sysinfo(SI_MACHINE, buf, sizeof(buf));
   649     if (rv > 0) {
   650 	RNG_RandomUpdate(buf, rv);
   651     }
   652     rv = sysinfo(SI_RELEASE, buf, sizeof(buf));
   653     if (rv > 0) {
   654 	RNG_RandomUpdate(buf, rv);
   655     }
   656     rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf));
   657     if (rv > 0) {
   658 	RNG_RandomUpdate(buf, rv);
   659     }
   660 }
   661 #endif /* nec_ews */
   663 size_t RNG_GetNoise(void *buf, size_t maxbytes)
   664 {
   665     struct timeval tv;
   666     int n = 0;
   667     int c;
   669     n = GetHighResClock(buf, maxbytes);
   670     maxbytes -= n;
   672     (void)gettimeofday(&tv, 0);
   673     c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec));
   674     n += c;
   675     maxbytes -= c;
   676     c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec));
   677     n += c;
   678     return n;
   679 }
   681 #define SAFE_POPEN_MAXARGS	10	/* must be at least 2 */
   683 /*
   684  * safe_popen is static to this module and we know what arguments it is
   685  * called with. Note that this version only supports a single open child
   686  * process at any time.
   687  */
   688 static pid_t safe_popen_pid;
   689 static struct sigaction oldact;
   691 static FILE *
   692 safe_popen(char *cmd)
   693 {
   694     int p[2], fd, argc;
   695     pid_t pid;
   696     char *argv[SAFE_POPEN_MAXARGS + 1];
   697     FILE *fp;
   698     static char blank[] = " \t";
   699     static struct sigaction newact;
   701     if (pipe(p) < 0)
   702 	return 0;
   704     fp = fdopen(p[0], "r");
   705     if (fp == 0) {
   706 	close(p[0]);
   707 	close(p[1]);
   708 	return 0;
   709     }
   711     /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */
   712     newact.sa_handler = SIG_DFL;
   713     newact.sa_flags = 0;
   714     sigfillset(&newact.sa_mask);
   715     sigaction (SIGCHLD, &newact, &oldact);
   717     pid = fork();
   718     switch (pid) {
   719       int ndesc;
   721       case -1:
   722 	fclose(fp); /* this closes p[0], the fd associated with fp */
   723 	close(p[1]);
   724 	sigaction (SIGCHLD, &oldact, NULL);
   725 	return 0;
   727       case 0:
   728 	/* dup write-side of pipe to stderr and stdout */
   729 	if (p[1] != 1) dup2(p[1], 1);
   730 	if (p[1] != 2) dup2(p[1], 2);
   732 	/* 
   733 	 * close the other file descriptors, except stdin which we
   734 	 * try reassociating with /dev/null, first (bug 174993)
   735 	 */
   736 	if (!freopen("/dev/null", "r", stdin))
   737 	    close(0);
   738 	ndesc = getdtablesize();
   739 	for (fd = PR_MIN(65536, ndesc); --fd > 2; close(fd));
   741 	/* clean up environment in the child process */
   742 	putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc");
   743 	putenv("SHELL=/bin/sh");
   744 	putenv("IFS= \t");
   746 	/*
   747 	 * The caller may have passed us a string that is in text
   748 	 * space. It may be illegal to modify the string
   749 	 */
   750 	cmd = strdup(cmd);
   751 	/* format argv */
   752 	argv[0] = strtok(cmd, blank);
   753 	argc = 1;
   754 	while ((argv[argc] = strtok(0, blank)) != 0) {
   755 	    if (++argc == SAFE_POPEN_MAXARGS) {
   756 		argv[argc] = 0;
   757 		break;
   758 	    }
   759 	}
   761 	/* and away we go */
   762 	execvp(argv[0], argv);
   763 	exit(127);
   764 	break;
   766       default:
   767 	close(p[1]);
   768 	break;
   769     }
   771     /* non-zero means there's a cmd running */
   772     safe_popen_pid = pid;
   773     return fp;
   774 }
   776 static int
   777 safe_pclose(FILE *fp)
   778 {
   779     pid_t pid;
   780     int status = -1, rv;
   782     if ((pid = safe_popen_pid) == 0)
   783 	return -1;
   784     safe_popen_pid = 0;
   786     fclose(fp);
   788     /* yield the processor so the child gets some time to exit normally */
   789     PR_Sleep(PR_INTERVAL_NO_WAIT);
   791     /* if the child hasn't exited, kill it -- we're done with its output */
   792     while ((rv = waitpid(pid, &status, WNOHANG)) == -1 && errno == EINTR)
   793 	;
   794     if (rv == 0) {
   795 	kill(pid, SIGKILL);
   796 	while ((rv = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
   797 	    ;
   798     }
   800     /* Reset SIGCHLD signal hander before returning */
   801     sigaction(SIGCHLD, &oldact, NULL);
   803     return status;
   804 }
   806 #ifdef DARWIN
   807 #include <TargetConditionals.h>
   808 #if !TARGET_OS_IPHONE
   809 #include <crt_externs.h>
   810 #endif
   811 #endif
   813 /* Fork netstat to collect its output by default. Do not unset this unless
   814  * another source of entropy is available
   815  */
   816 #define DO_NETSTAT 1
   818 void RNG_SystemInfoForRNG(void)
   819 {
   820     FILE *fp;
   821     char buf[BUFSIZ];
   822     size_t bytes;
   823     const char * const *cp;
   824     char *randfile;
   825 #ifdef DARWIN
   826 #if TARGET_OS_IPHONE
   827     /* iOS does not expose a way to access environ. */
   828     char **environ = NULL;
   829 #else
   830     char **environ = *_NSGetEnviron();
   831 #endif
   832 #else
   833     extern char **environ;
   834 #endif
   835 #ifdef BEOS
   836     static const char * const files[] = {
   837 	"/boot/var/swap",
   838 	"/boot/var/log/syslog",
   839 	"/boot/var/tmp",
   840 	"/boot/home/config/settings",
   841 	"/boot/home",
   842 	0
   843     };
   844 #else
   845     static const char * const files[] = {
   846 	"/etc/passwd",
   847 	"/etc/utmp",
   848 	"/tmp",
   849 	"/var/tmp",
   850 	"/usr/tmp",
   851 	0
   852     };
   853 #endif
   855 #if defined(BSDI)
   856     static char netstat_ni_cmd[] = "netstat -nis";
   857 #else
   858     static char netstat_ni_cmd[] = "netstat -ni";
   859 #endif
   861     GiveSystemInfo();
   863     bytes = RNG_GetNoise(buf, sizeof(buf));
   864     RNG_RandomUpdate(buf, bytes);
   866     /*
   867      * Pass the C environment and the addresses of the pointers to the
   868      * hash function. This makes the random number function depend on the
   869      * execution environment of the user and on the platform the program
   870      * is running on.
   871      */
   872     if (environ != NULL) {
   873         cp = (const char * const *) environ;
   874         while (*cp) {
   875 	    RNG_RandomUpdate(*cp, strlen(*cp));
   876 	    cp++;
   877         }
   878         RNG_RandomUpdate(environ, (char*)cp - (char*)environ);
   879     }
   881     /* Give in system information */
   882     if (gethostname(buf, sizeof(buf)) == 0) {
   883 	RNG_RandomUpdate(buf, strlen(buf));
   884     }
   885     GiveSystemInfo();
   887     /* grab some data from system's PRNG before any other files. */
   888     bytes = RNG_FileUpdate("/dev/urandom", SYSTEM_RNG_SEED_COUNT);
   890     /* If the user points us to a random file, pass it through the rng */
   891     randfile = getenv("NSRANDFILE");
   892     if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) {
   893 	char *randCountString = getenv("NSRANDCOUNT");
   894 	int randCount = randCountString ? atoi(randCountString) : 0;
   895 	if (randCount != 0) {
   896 	    RNG_FileUpdate(randfile, randCount);
   897 	} else {
   898 	    RNG_FileForRNG(randfile);
   899 	}
   900     }
   902     /* pass other files through */
   903     for (cp = files; *cp; cp++)
   904 	RNG_FileForRNG(*cp);
   906 /*
   907  * Bug 100447: On BSD/OS 4.2 and 4.3, we have problem calling safe_popen
   908  * in a pthreads environment.  Therefore, we call safe_popen last and on
   909  * BSD/OS we do not call safe_popen when we succeeded in getting data
   910  * from /dev/urandom.
   911  *
   912  * Bug 174993: On platforms providing /dev/urandom, don't fork netstat
   913  * either, if data has been gathered successfully.
   914  */
   916 #if defined(BSDI) || defined(FREEBSD) || defined(NETBSD) \
   917     || defined(OPENBSD) || defined(DARWIN) || defined(LINUX) \
   918     || defined(HPUX)
   919     if (bytes)
   920         return;
   921 #endif
   923 #ifdef SOLARIS
   925 /*
   926  * On Solaris, NSS may be initialized automatically from libldap in
   927  * applications that are unaware of the use of NSS. safe_popen forks, and
   928  * sometimes creates issues with some applications' pthread_atfork handlers.
   929  * We always have /dev/urandom on Solaris 9 and above as an entropy source,
   930  * and for Solaris 8 we have the libkstat interface, so we don't need to
   931  * fork netstat.
   932  */
   934 #undef DO_NETSTAT
   935     if (!bytes) {
   936         /* On Solaris 8, /dev/urandom isn't available, so we use libkstat. */
   937         PRUint32 kstat_bytes = 0;
   938         if (SECSuccess != RNG_kstat(&kstat_bytes)) {
   939             PORT_Assert(0);
   940         }
   941         bytes += kstat_bytes;
   942         PORT_Assert(bytes);
   943     }
   944 #endif
   946 #ifdef DO_NETSTAT
   947     fp = safe_popen(netstat_ni_cmd);
   948     if (fp != NULL) {
   949 	while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0)
   950 	    RNG_RandomUpdate(buf, bytes);
   951 	safe_pclose(fp);
   952     }
   953 #endif
   955 }
   957 #define TOTAL_FILE_LIMIT 1000000	/* one million */
   959 size_t RNG_FileUpdate(const char *fileName, size_t limit)
   960 {
   961     FILE *        file;
   962     int           fd;
   963     int           bytes;
   964     size_t        fileBytes = 0;
   965     struct stat   stat_buf;
   966     unsigned char buffer[BUFSIZ];
   967     static size_t totalFileBytes = 0;
   969     /* suppress valgrind warnings due to holes in struct stat */
   970     memset(&stat_buf, 0, sizeof(stat_buf));
   972     if (stat((char *)fileName, &stat_buf) < 0)
   973 	return fileBytes;
   974     RNG_RandomUpdate(&stat_buf, sizeof(stat_buf));
   976     file = fopen(fileName, "r");
   977     if (file != NULL) {
   978 	/* Read from the underlying file descriptor directly to bypass stdio
   979 	 * buffering and avoid reading more bytes than we need from
   980 	 * /dev/urandom. NOTE: we can't use fread with unbuffered I/O because
   981 	 * fread may return EOF in unbuffered I/O mode on Android.
   982 	 *
   983 	 * Moreover, we read into a buffer of size BUFSIZ, so buffered I/O
   984 	 * has no performance advantage. */
   985 	fd = fileno(file);
   986 	/* 'file' was just opened, so this should not fail. */
   987 	PORT_Assert(fd != -1);
   988 	while (limit > fileBytes) {
   989 	    bytes = PR_MIN(sizeof buffer, limit - fileBytes);
   990 	    bytes = read(fd, buffer, bytes);
   991 	    if (bytes <= 0)
   992 		break;
   993 	    RNG_RandomUpdate(buffer, bytes);
   994 	    fileBytes      += bytes;
   995 	    totalFileBytes += bytes;
   996 	    /* after TOTAL_FILE_LIMIT has been reached, only read in first
   997 	    ** buffer of data from each subsequent file.
   998 	    */
   999 	    if (totalFileBytes > TOTAL_FILE_LIMIT) 
  1000 		break;
  1002 	fclose(file);
  1004     /*
  1005      * Pass yet another snapshot of our highest resolution clock into
  1006      * the hash function.
  1007      */
  1008     bytes = RNG_GetNoise(buffer, sizeof(buffer));
  1009     RNG_RandomUpdate(buffer, bytes);
  1010     return fileBytes;
  1013 void RNG_FileForRNG(const char *fileName)
  1015     RNG_FileUpdate(fileName, TOTAL_FILE_LIMIT);
  1018 void ReadSingleFile(const char *fileName)
  1020     FILE *        file;
  1021     unsigned char buffer[BUFSIZ];
  1023     file = fopen(fileName, "rb");
  1024     if (file != NULL) {
  1025 	while (fread(buffer, 1, sizeof(buffer), file) > 0)
  1027 	fclose(file);
  1031 #define _POSIX_PTHREAD_SEMANTICS
  1032 #include <dirent.h>
  1034 PRBool
  1035 ReadFileOK(char *dir, char *file)
  1037     struct stat   stat_buf;
  1038     char filename[PATH_MAX];
  1039     int count = snprintf(filename, sizeof filename, "%s/%s",dir, file);
  1041     if (count <= 0) {
  1042 	return PR_FALSE; /* name too long, can't read it anyway */
  1045     if (stat(filename, &stat_buf) < 0)
  1046 	return PR_FALSE; /* can't stat, probably can't read it then as well */
  1047     return S_ISREG(stat_buf.st_mode) ? PR_TRUE : PR_FALSE;
  1050 /*
  1051  * read one file out of either /etc or the user's home directory.
  1052  * fileToRead tells which file to read.
  1054  * return 1 if it's time to reset the fileToRead (no more files to read).
  1055  */
  1056 int ReadOneFile(int fileToRead)
  1058     char *dir = "/etc";
  1059     DIR *fd = opendir(dir);
  1060     int resetCount = 0;
  1061 #ifdef SOLARIS
  1062      /* grumble, Solaris does not define struct dirent to be the full length */
  1063     typedef union {
  1064 	unsigned char space[sizeof(struct dirent) + MAXNAMELEN];
  1065 	struct dirent dir;
  1066     } dirent_hack;
  1067     dirent_hack entry, firstEntry;
  1069 #define entry_dir entry.dir
  1070 #else
  1071     struct dirent entry, firstEntry;
  1072 #define entry_dir entry
  1073 #endif
  1075     int i, error = -1;
  1077     if (fd == NULL) {
  1078 	dir = getenv("HOME");
  1079 	if (dir) {
  1080 	    fd = opendir(dir);
  1083     if (fd == NULL) {
  1084 	return 1;
  1087     for (i=0; i <= fileToRead; i++) {
  1088 	struct dirent *result = NULL;
  1089 	do {
  1090 	    error = readdir_r(fd, &entry_dir, &result);
  1091 	} while (error == 0 && result != NULL  &&
  1092 					!ReadFileOK(dir,&result->d_name[0]));
  1093 	if (error != 0 || result == NULL)  {
  1094 	    resetCount = 1; /* read to the end, start again at the beginning */
  1095 	    if (i != 0) {
  1096 		/* ran out of entries in the directory, use the first one */
  1097 	 	entry = firstEntry;
  1098 	 	error = 0;
  1099 	 	break;
  1101 	    /* if i== 0, there were no readable entries in the directory */
  1102 	    break;
  1104 	if (i==0) {
  1105 	    /* save the first entry in case we run out of entries */
  1106 	    firstEntry = entry;
  1110     if (error == 0) {
  1111 	char filename[PATH_MAX];
  1112 	int count = snprintf(filename, sizeof filename, 
  1113 				"%s/%s",dir, &entry_dir.d_name[0]);
  1114 	if (count >= 1) {
  1115 	    ReadSingleFile(filename);
  1119     closedir(fd);
  1120     return resetCount;
  1123 /*
  1124  * do something to try to introduce more noise into the 'GetNoise' call
  1125  */
  1126 static void rng_systemJitter(void)
  1128    static int fileToRead = 1;
  1130    if (ReadOneFile(fileToRead)) {
  1131 	fileToRead = 1;
  1132    } else {
  1133 	fileToRead++;
  1137 size_t RNG_SystemRNG(void *dest, size_t maxLen)
  1139     FILE *file;
  1140     int fd;
  1141     int bytes;
  1142     size_t fileBytes = 0;
  1143     unsigned char *buffer = dest;
  1145     file = fopen("/dev/urandom", "r");
  1146     if (file == NULL) {
  1147 	return rng_systemFromNoise(dest, maxLen);
  1149     /* Read from the underlying file descriptor directly to bypass stdio
  1150      * buffering and avoid reading more bytes than we need from /dev/urandom.
  1151      * NOTE: we can't use fread with unbuffered I/O because fread may return
  1152      * EOF in unbuffered I/O mode on Android.
  1153      */
  1154     fd = fileno(file);
  1155     /* 'file' was just opened, so this should not fail. */
  1156     PORT_Assert(fd != -1);
  1157     while (maxLen > fileBytes) {
  1158 	bytes = maxLen - fileBytes;
  1159 	bytes = read(fd, buffer, bytes);
  1160 	if (bytes <= 0)
  1161 	    break;
  1162 	fileBytes += bytes;
  1163 	buffer += bytes;
  1165     fclose(file);
  1166     if (fileBytes != maxLen) {
  1167 	PORT_SetError(SEC_ERROR_NEED_RANDOM);  /* system RNG failed */
  1168 	fileBytes = 0;
  1170     return fileBytes;

mercurial