1254721Semaste/* 2254721Semaste * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") 3254721Semaste * Copyright (C) 2000-2003 Internet Software Consortium. 4254721Semaste * 5254721Semaste * Permission to use, copy, modify, and/or distribute this software for any 6254721Semaste * purpose with or without fee is hereby granted, provided that the above 7254721Semaste * copyright notice and this permission notice appear in all copies. 8254721Semaste * 9254721Semaste * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10254721Semaste * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11254721Semaste * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12254721Semaste * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13254721Semaste * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14254721Semaste * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15254721Semaste * PERFORMANCE OF THIS SOFTWARE. 16254721Semaste */ 17254721Semaste 18254721Semaste/* $Id: entropy.c,v 1.82 2008/12/01 23:47:45 tbox Exp $ */ 19254721Semaste 20254721Semaste/* \file unix/entropy.c 21269024Semaste * \brief 22254721Semaste * This is the system dependent part of the ISC entropy API. 23254721Semaste */ 24254721Semaste 25254721Semaste#include <config.h> 26254721Semaste 27254721Semaste#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */ 28254721Semaste#include <sys/types.h> 29254721Semaste#include <sys/time.h> 30254721Semaste#include <sys/stat.h> 31254721Semaste#include <sys/socket.h> 32254721Semaste#include <sys/un.h> 33254721Semaste 34254721Semaste#ifdef HAVE_NANOSLEEP 35254721Semaste#include <time.h> 36254721Semaste#endif 37254721Semaste#include <unistd.h> 38254721Semaste 39254721Semaste#include <isc/platform.h> 40254721Semaste#include <isc/strerror.h> 41254721Semaste 42254721Semaste#ifdef ISC_PLATFORM_NEEDSYSSELECTH 43254721Semaste#include <sys/select.h> 44254721Semaste#endif 45254721Semaste 46254721Semaste#include "errno2result.h" 47254721Semaste 48254721Semaste/*% 49254721Semaste * There is only one variable in the entropy data structures that is not 50254721Semaste * system independent, but pulling the structure that uses it into this file 51254721Semaste * ultimately means pulling several other independent structures here also to 52254721Semaste * resolve their interdependencies. Thus only the problem variable's type 53254721Semaste * is defined here. 54254721Semaste */ 55254721Semaste#define FILESOURCE_HANDLE_TYPE int 56254721Semaste 57254721Semastetypedef struct { 58254721Semaste int handle; 59254721Semaste enum { 60254721Semaste isc_usocketsource_disconnected, 61254721Semaste isc_usocketsource_connecting, 62254721Semaste isc_usocketsource_connected, 63254721Semaste isc_usocketsource_ndesired, 64254721Semaste isc_usocketsource_wrote, 65269024Semaste isc_usocketsource_reading 66254721Semaste } status; 67254721Semaste size_t sz_to_recv; 68254721Semaste} isc_entropyusocketsource_t; 69254721Semaste 70254721Semaste#include "../entropy.c" 71254721Semaste 72269024Semastestatic unsigned int 73254721Semasteget_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) { 74254721Semaste isc_entropy_t *ent = source->ent; 75254721Semaste unsigned char buf[128]; 76254721Semaste int fd = source->sources.file.handle; 77254721Semaste ssize_t n, ndesired; 78254721Semaste unsigned int added; 79254721Semaste 80254721Semaste if (source->bad) 81254721Semaste return (0); 82254721Semaste 83254721Semaste desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); 84254721Semaste 85254721Semaste added = 0; 86254721Semaste while (desired > 0) { 87254721Semaste ndesired = ISC_MIN(desired, sizeof(buf)); 88254721Semaste n = read(fd, buf, ndesired); 89254721Semaste if (n < 0) { 90254721Semaste if (errno == EAGAIN || errno == EINTR) 91254721Semaste goto out; 92254721Semaste goto err; 93254721Semaste } 94254721Semaste if (n == 0) 95254721Semaste goto err; 96254721Semaste 97254721Semaste entropypool_adddata(ent, buf, n, n * 8); 98254721Semaste added += n * 8; 99254721Semaste desired -= n; 100254721Semaste } 101254721Semaste goto out; 102254721Semaste 103254721Semaste err: 104254721Semaste (void)close(fd); 105254721Semaste source->sources.file.handle = -1; 106254721Semaste source->bad = ISC_TRUE; 107254721Semaste 108254721Semaste out: 109254721Semaste return (added); 110254721Semaste} 111254721Semaste 112254721Semastestatic unsigned int 113254721Semasteget_from_usocketsource(isc_entropysource_t *source, isc_uint32_t desired) { 114254721Semaste isc_entropy_t *ent = source->ent; 115254721Semaste unsigned char buf[128]; 116254721Semaste int fd = source->sources.usocket.handle; 117254721Semaste ssize_t n = 0, ndesired; 118254721Semaste unsigned int added; 119254721Semaste size_t sz_to_recv = source->sources.usocket.sz_to_recv; 120254721Semaste 121254721Semaste if (source->bad) 122254721Semaste return (0); 123254721Semaste 124254721Semaste desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); 125254721Semaste 126254721Semaste added = 0; 127254721Semaste while (desired > 0) { 128254721Semaste ndesired = ISC_MIN(desired, sizeof(buf)); 129254721Semaste eagain_loop: 130254721Semaste 131254721Semaste switch ( source->sources.usocket.status ) { 132254721Semaste case isc_usocketsource_ndesired: 133254721Semaste buf[0] = ndesired; 134254721Semaste if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) { 135254721Semaste if (errno == EWOULDBLOCK || errno == EINTR || 136254721Semaste errno == ECONNRESET) 137254721Semaste goto out; 138269024Semaste goto err; 139269024Semaste } 140269024Semaste INSIST(n == 1); 141269024Semaste source->sources.usocket.status = 142269024Semaste isc_usocketsource_wrote; 143269024Semaste goto eagain_loop; 144269024Semaste 145269024Semaste case isc_usocketsource_connecting: 146269024Semaste case isc_usocketsource_connected: 147254721Semaste buf[0] = 1; 148254721Semaste buf[1] = ndesired; 149254721Semaste if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) { 150254721Semaste if (errno == EWOULDBLOCK || errno == EINTR || 151254721Semaste errno == ECONNRESET) 152254721Semaste goto out; 153254721Semaste goto err; 154254721Semaste } 155254721Semaste if (n == 1) { 156254721Semaste source->sources.usocket.status = 157254721Semaste isc_usocketsource_ndesired; 158254721Semaste goto eagain_loop; 159254721Semaste } 160254721Semaste INSIST(n == 2); 161254721Semaste source->sources.usocket.status = 162254721Semaste isc_usocketsource_wrote; 163254721Semaste /*FALLTHROUGH*/ 164254721Semaste 165254721Semaste case isc_usocketsource_wrote: 166254721Semaste if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) { 167254721Semaste if (errno == EAGAIN) { 168254721Semaste /* 169254721Semaste * The problem of EAGAIN (try again 170254721Semaste * later) is a major issue on HP-UX. 171254721Semaste * Solaris actually tries the recvfrom 172254721Semaste * call again, while HP-UX just dies. 173254721Semaste * This code is an attempt to let the 174254721Semaste * entropy pool fill back up (at least 175254721Semaste * that's what I think the problem is.) 176254721Semaste * We go to eagain_loop because if we 177254721Semaste * just "break", then the "desired" 178254721Semaste * amount gets borked. 179254721Semaste */ 180254721Semaste#ifdef HAVE_NANOSLEEP 181254721Semaste struct timespec ts; 182254721Semaste 183254721Semaste ts.tv_sec = 0; 184254721Semaste ts.tv_nsec = 1000000; 185254721Semaste nanosleep(&ts, NULL); 186254721Semaste#else 187254721Semaste usleep(1000); 188254721Semaste#endif 189254721Semaste goto eagain_loop; 190254721Semaste } 191254721Semaste if (errno == EWOULDBLOCK || errno == EINTR) 192254721Semaste goto out; 193254721Semaste goto err; 194254721Semaste } 195254721Semaste source->sources.usocket.status = 196254721Semaste isc_usocketsource_reading; 197254721Semaste sz_to_recv = buf[0]; 198254721Semaste source->sources.usocket.sz_to_recv = sz_to_recv; 199254721Semaste if (sz_to_recv > sizeof(buf)) 200254721Semaste goto err; 201254721Semaste /*FALLTHROUGH*/ 202254721Semaste 203254721Semaste case isc_usocketsource_reading: 204254721Semaste if (sz_to_recv != 0U) { 205254721Semaste n = recv(fd, buf, sz_to_recv, 0); 206254721Semaste if (n < 0) { 207254721Semaste if (errno == EWOULDBLOCK || 208254721Semaste errno == EINTR) 209254721Semaste goto out; 210254721Semaste goto err; 211254721Semaste } 212254721Semaste } else 213254721Semaste n = 0; 214254721Semaste break; 215254721Semaste 216254721Semaste default: 217254721Semaste goto err; 218254721Semaste } 219254721Semaste 220254721Semaste if ((size_t)n != sz_to_recv) 221254721Semaste source->sources.usocket.sz_to_recv -= n; 222254721Semaste else 223254721Semaste source->sources.usocket.status = 224254721Semaste isc_usocketsource_connected; 225254721Semaste 226254721Semaste if (n == 0) 227254721Semaste goto out; 228254721Semaste 229254721Semaste entropypool_adddata(ent, buf, n, n * 8); 230254721Semaste added += n * 8; 231254721Semaste desired -= n; 232254721Semaste } 233254721Semaste goto out; 234254721Semaste 235254721Semaste err: 236254721Semaste close(fd); 237254721Semaste source->bad = ISC_TRUE; 238254721Semaste source->sources.usocket.status = isc_usocketsource_disconnected; 239254721Semaste source->sources.usocket.handle = -1; 240254721Semaste 241254721Semaste out: 242254721Semaste return (added); 243254721Semaste} 244254721Semaste 245254721Semaste/* 246254721Semaste * Poll each source, trying to get data from it to stuff into the entropy 247254721Semaste * pool. 248254721Semaste */ 249254721Semastestatic void 250254721Semastefillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) { 251254721Semaste unsigned int added; 252254721Semaste unsigned int remaining; 253254721Semaste unsigned int needed; 254254721Semaste unsigned int nsource; 255254721Semaste isc_entropysource_t *source; 256254721Semaste 257254721Semaste REQUIRE(VALID_ENTROPY(ent)); 258254721Semaste 259254721Semaste needed = desired; 260254721Semaste 261254721Semaste /* 262254721Semaste * This logic is a little strange, so an explanation is in order. 263254721Semaste * 264254721Semaste * If needed is 0, it means we are being asked to "fill to whatever 265254721Semaste * we think is best." This means that if we have at least a 266254721Semaste * partially full pool (say, > 1/4th of the pool) we probably don't 267254721Semaste * need to add anything. 268254721Semaste * 269254721Semaste * Also, we will check to see if the "pseudo" count is too high. 270254721Semaste * If it is, try to mix in better data. Too high is currently 271254721Semaste * defined as 1/4th of the pool. 272254721Semaste * 273254721Semaste * Next, if we are asked to add a specific bit of entropy, make 274254721Semaste * certain that we will do so. Clamp how much we try to add to 275254721Semaste * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy). 276254721Semaste * 277254721Semaste * Note that if we are in a blocking mode, we will only try to 278254721Semaste * get as much data as we need, not as much as we might want 279254721Semaste * to build up. 280254721Semaste */ 281254721Semaste if (needed == 0) { 282254721Semaste REQUIRE(!blocking); 283254721Semaste 284254721Semaste if ((ent->pool.entropy >= RND_POOLBITS / 4) 285254721Semaste && (ent->pool.pseudo <= RND_POOLBITS / 4)) 286254721Semaste return; 287254721Semaste 288254721Semaste needed = THRESHOLD_BITS * 4; 289254721Semaste } else { 290254721Semaste needed = ISC_MAX(needed, THRESHOLD_BITS); 291254721Semaste needed = ISC_MIN(needed, RND_POOLBITS); 292254721Semaste } 293254721Semaste 294254721Semaste /* 295254721Semaste * In any case, clamp how much we need to how much we can add. 296254721Semaste */ 297263363Semaste needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy); 298263363Semaste 299263363Semaste /* 300254721Semaste * But wait! If we're not yet initialized, we need at least 301254721Semaste * THRESHOLD_BITS 302254721Semaste * of randomness. 303263363Semaste */ 304263363Semaste if (ent->initialized < THRESHOLD_BITS) 305263363Semaste needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized); 306263363Semaste 307263363Semaste /* 308263363Semaste * Poll each file source to see if we can read anything useful from 309254721Semaste * it. XXXMLG When where are multiple sources, we should keep a 310254721Semaste * record of which one we last used so we can start from it (or the 311254721Semaste * next one) to avoid letting some sources build up entropy while 312254721Semaste * others are always drained. 313254721Semaste */ 314254721Semaste 315254721Semaste added = 0; 316254721Semaste remaining = needed; 317254721Semaste if (ent->nextsource == NULL) { 318254721Semaste ent->nextsource = ISC_LIST_HEAD(ent->sources); 319254721Semaste if (ent->nextsource == NULL) 320254721Semaste return; 321254721Semaste } 322254721Semaste source = ent->nextsource; 323254721Semaste again_file: 324254721Semaste for (nsource = 0; nsource < ent->nsources; nsource++) { 325254721Semaste unsigned int got; 326254721Semaste 327254721Semaste if (remaining == 0) 328254721Semaste break; 329254721Semaste 330254721Semaste got = 0; 331254721Semaste 332254721Semaste switch ( source->type ) { 333254721Semaste case ENTROPY_SOURCETYPE_FILE: 334254721Semaste got = get_from_filesource(source, remaining); 335254721Semaste break; 336254721Semaste 337254721Semaste case ENTROPY_SOURCETYPE_USOCKET: 338254721Semaste got = get_from_usocketsource(source, remaining); 339254721Semaste break; 340254721Semaste } 341254721Semaste 342254721Semaste added += got; 343254721Semaste 344254721Semaste remaining -= ISC_MIN(remaining, got); 345254721Semaste 346254721Semaste source = ISC_LIST_NEXT(source, link); 347254721Semaste if (source == NULL) 348254721Semaste source = ISC_LIST_HEAD(ent->sources); 349254721Semaste } 350254721Semaste ent->nextsource = source; 351254721Semaste 352254721Semaste if (blocking && remaining != 0) { 353254721Semaste int fds; 354254721Semaste 355254721Semaste fds = wait_for_sources(ent); 356254721Semaste if (fds > 0) 357254721Semaste goto again_file; 358254721Semaste } 359254721Semaste 360254721Semaste /* 361254721Semaste * Here, if there are bits remaining to be had and we can block, 362254721Semaste * check to see if we have a callback source. If so, call them. 363254721Semaste */ 364254721Semaste source = ISC_LIST_HEAD(ent->sources); 365254721Semaste while ((remaining != 0) && (source != NULL)) { 366254721Semaste unsigned int got; 367254721Semaste 368254721Semaste got = 0; 369254721Semaste 370254721Semaste if (source->type == ENTROPY_SOURCETYPE_CALLBACK) 371254721Semaste got = get_from_callback(source, remaining, blocking); 372254721Semaste 373254721Semaste added += got; 374254721Semaste remaining -= ISC_MIN(remaining, got); 375254721Semaste 376254721Semaste if (added >= needed) 377254721Semaste break; 378254721Semaste 379254721Semaste source = ISC_LIST_NEXT(source, link); 380254721Semaste } 381254721Semaste 382254721Semaste /* 383254721Semaste * Mark as initialized if we've added enough data. 384254721Semaste */ 385254721Semaste if (ent->initialized < THRESHOLD_BITS) 386254721Semaste ent->initialized += added; 387254721Semaste} 388254721Semaste 389254721Semastestatic int 390254721Semastewait_for_sources(isc_entropy_t *ent) { 391254721Semaste isc_entropysource_t *source; 392254721Semaste int maxfd, fd; 393254721Semaste int cc; 394254721Semaste fd_set reads; 395254721Semaste fd_set writes; 396254721Semaste 397254721Semaste maxfd = -1; 398254721Semaste FD_ZERO(&reads); 399254721Semaste FD_ZERO(&writes); 400254721Semaste 401254721Semaste source = ISC_LIST_HEAD(ent->sources); 402254721Semaste while (source != NULL) { 403254721Semaste if (source->type == ENTROPY_SOURCETYPE_FILE) { 404254721Semaste fd = source->sources.file.handle; 405254721Semaste if (fd >= 0) { 406254721Semaste maxfd = ISC_MAX(maxfd, fd); 407254721Semaste FD_SET(fd, &reads); 408254721Semaste } 409254721Semaste } 410254721Semaste if (source->type == ENTROPY_SOURCETYPE_USOCKET) { 411254721Semaste fd = source->sources.usocket.handle; 412254721Semaste if (fd >= 0) { 413254721Semaste switch (source->sources.usocket.status) { 414254721Semaste case isc_usocketsource_disconnected: 415254721Semaste break; 416254721Semaste case isc_usocketsource_connecting: 417254721Semaste case isc_usocketsource_connected: 418254721Semaste case isc_usocketsource_ndesired: 419254721Semaste maxfd = ISC_MAX(maxfd, fd); 420254721Semaste FD_SET(fd, &writes); 421254721Semaste break; 422254721Semaste case isc_usocketsource_wrote: 423254721Semaste case isc_usocketsource_reading: 424254721Semaste maxfd = ISC_MAX(maxfd, fd); 425254721Semaste FD_SET(fd, &reads); 426254721Semaste break; 427254721Semaste } 428254721Semaste } 429254721Semaste } 430254721Semaste source = ISC_LIST_NEXT(source, link); 431254721Semaste } 432254721Semaste 433254721Semaste if (maxfd < 0) 434254721Semaste return (-1); 435254721Semaste 436254721Semaste cc = select(maxfd + 1, &reads, &writes, NULL, NULL); 437254721Semaste if (cc < 0) 438254721Semaste return (-1); 439254721Semaste 440254721Semaste return (cc); 441254721Semaste} 442254721Semaste 443254721Semastestatic void 444254721Semastedestroyfilesource(isc_entropyfilesource_t *source) { 445254721Semaste (void)close(source->handle); 446254721Semaste} 447254721Semaste 448254721Semastestatic void 449254721Semastedestroyusocketsource(isc_entropyusocketsource_t *source) { 450254721Semaste close(source->handle); 451254721Semaste} 452254721Semaste 453254721Semaste/* 454254721Semaste * Make a fd non-blocking 455254721Semaste */ 456254721Semastestatic isc_result_t 457254721Semastemake_nonblock(int fd) { 458254721Semaste int ret; 459254721Semaste int flags; 460254721Semaste char strbuf[ISC_STRERRORSIZE]; 461254721Semaste#ifdef USE_FIONBIO_IOCTL 462254721Semaste int on = 1; 463254721Semaste 464254721Semaste ret = ioctl(fd, FIONBIO, (char *)&on); 465254721Semaste#else 466254721Semaste flags = fcntl(fd, F_GETFL, 0); 467254721Semaste flags |= PORT_NONBLOCK; 468254721Semaste ret = fcntl(fd, F_SETFL, flags); 469254721Semaste#endif 470254721Semaste 471254721Semaste if (ret == -1) { 472254721Semaste isc__strerror(errno, strbuf, sizeof(strbuf)); 473254721Semaste UNEXPECTED_ERROR(__FILE__, __LINE__, 474254721Semaste#ifdef USE_FIONBIO_IOCTL 475254721Semaste "ioctl(%d, FIONBIO, &on): %s", fd, 476254721Semaste#else 477254721Semaste "fcntl(%d, F_SETFL, %d): %s", fd, flags, 478254721Semaste#endif 479254721Semaste strbuf); 480254721Semaste 481254721Semaste return (ISC_R_UNEXPECTED); 482254721Semaste } 483254721Semaste 484254721Semaste return (ISC_R_SUCCESS); 485254721Semaste} 486254721Semaste 487254721Semasteisc_result_t 488254721Semasteisc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) { 489254721Semaste int fd; 490254721Semaste struct stat _stat; 491254721Semaste isc_boolean_t is_usocket = ISC_FALSE; 492254721Semaste isc_boolean_t is_connected = ISC_FALSE; 493254721Semaste isc_result_t ret; 494254721Semaste isc_entropysource_t *source; 495254721Semaste 496254721Semaste REQUIRE(VALID_ENTROPY(ent)); 497254721Semaste REQUIRE(fname != NULL); 498254721Semaste 499254721Semaste LOCK(&ent->lock); 500254721Semaste 501254721Semaste if (stat(fname, &_stat) < 0) { 502254721Semaste ret = isc__errno2result(errno); 503254721Semaste goto errout; 504254721Semaste } 505254721Semaste /* 506254721Semaste * Solaris 2.5.1 does not have support for sockets (S_IFSOCK), 507254721Semaste * but it does return type S_IFIFO (the OS believes that 508254721Semaste * the socket is a fifo). This may be an issue if we tell 509254721Semaste * the program to look at an actual FIFO as its source of 510254721Semaste * entropy. 511263367Semaste */ 512263367Semaste#if defined(S_ISSOCK) 513263367Semaste if (S_ISSOCK(_stat.st_mode)) 514263367Semaste is_usocket = ISC_TRUE; 515263367Semaste#endif 516263367Semaste#if defined(S_ISFIFO) && defined(sun) 517263367Semaste if (S_ISFIFO(_stat.st_mode)) 518263367Semaste is_usocket = ISC_TRUE; 519263367Semaste#endif 520263367Semaste if (is_usocket) 521263367Semaste fd = socket(PF_UNIX, SOCK_STREAM, 0); 522263367Semaste else 523263367Semaste fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0); 524254721Semaste 525254721Semaste if (fd < 0) { 526254721Semaste ret = isc__errno2result(errno); 527254721Semaste goto errout; 528254721Semaste } 529254721Semaste 530254721Semaste ret = make_nonblock(fd); 531254721Semaste if (ret != ISC_R_SUCCESS) 532254721Semaste goto closefd; 533254721Semaste 534254721Semaste if (is_usocket) { 535254721Semaste struct sockaddr_un sname; 536254721Semaste 537254721Semaste memset(&sname, 0, sizeof(sname)); 538263367Semaste sname.sun_family = AF_UNIX; 539263367Semaste strncpy(sname.sun_path, fname, sizeof(sname.sun_path)); 540263367Semaste sname.sun_path[sizeof(sname.sun_path)-1] = '0'; 541263367Semaste#ifdef ISC_PLATFORM_HAVESALEN 542263367Semaste#if !defined(SUN_LEN) 543263367Semaste#define SUN_LEN(su) \ 544263367Semaste (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 545263367Semaste#endif 546263367Semaste sname.sun_len = SUN_LEN(&sname); 547263367Semaste#endif 548263367Semaste 549263367Semaste if (connect(fd, (struct sockaddr *) &sname, 550263367Semaste sizeof(struct sockaddr_un)) < 0) { 551263367Semaste if (errno != EINPROGRESS) { 552263367Semaste ret = isc__errno2result(errno); 553263367Semaste goto closefd; 554263367Semaste } 555263367Semaste } else 556263367Semaste is_connected = ISC_TRUE; 557263367Semaste } 558254721Semaste 559254721Semaste source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); 560254721Semaste if (source == NULL) { 561254721Semaste ret = ISC_R_NOMEMORY; 562254721Semaste goto closefd; 563254721Semaste } 564254721Semaste 565254721Semaste /* 566254721Semaste * From here down, no failures can occur. 567254721Semaste */ 568254721Semaste source->magic = SOURCE_MAGIC; 569254721Semaste source->ent = ent; 570254721Semaste source->total = 0; 571254721Semaste source->bad = ISC_FALSE; 572254721Semaste memset(source->name, 0, sizeof(source->name)); 573254721Semaste ISC_LINK_INIT(source, link); 574254721Semaste if (is_usocket) { 575254721Semaste source->sources.usocket.handle = fd; 576254721Semaste if (is_connected) 577254721Semaste source->sources.usocket.status = 578254721Semaste isc_usocketsource_connected; 579254721Semaste else 580254721Semaste source->sources.usocket.status = 581254721Semaste isc_usocketsource_connecting; 582254721Semaste source->sources.usocket.sz_to_recv = 0; 583254721Semaste source->type = ENTROPY_SOURCETYPE_USOCKET; 584254721Semaste } else { 585254721Semaste source->sources.file.handle = fd; 586254721Semaste source->type = ENTROPY_SOURCETYPE_FILE; 587254721Semaste } 588254721Semaste 589254721Semaste /* 590254721Semaste * Hook it into the entropy system. 591254721Semaste */ 592254721Semaste ISC_LIST_APPEND(ent->sources, source, link); 593254721Semaste ent->nsources++; 594254721Semaste 595254721Semaste UNLOCK(&ent->lock); 596254721Semaste return (ISC_R_SUCCESS); 597254721Semaste 598254721Semaste closefd: 599254721Semaste (void)close(fd); 600254721Semaste 601254721Semaste errout: 602254721Semaste UNLOCK(&ent->lock); 603254721Semaste 604254721Semaste return (ret); 605254721Semaste} 606254721Semaste