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