1290001Sglebius/* 2290001Sglebius * Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") 3290001Sglebius * Copyright (C) 2000-2003 Internet Software Consortium. 4290001Sglebius * 5290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any 6290001Sglebius * purpose with or without fee is hereby granted, provided that the above 7290001Sglebius * copyright notice and this permission notice appear in all copies. 8290001Sglebius * 9290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11290001Sglebius * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15290001Sglebius * PERFORMANCE OF THIS SOFTWARE. 16290001Sglebius */ 17290001Sglebius 18290001Sglebius/* $Id: entropy.c,v 1.82 2008/12/01 23:47:45 tbox Exp $ */ 19290001Sglebius 20290001Sglebius/* \file unix/entropy.c 21290001Sglebius * \brief 22290001Sglebius * This is the system dependent part of the ISC entropy API. 23290001Sglebius */ 24290001Sglebius 25290001Sglebius#include <config.h> 26290001Sglebius 27290001Sglebius#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */ 28290001Sglebius#include <sys/types.h> 29290001Sglebius#include <sys/time.h> 30290001Sglebius#include <sys/stat.h> 31290001Sglebius#include <sys/socket.h> 32290001Sglebius#include <sys/un.h> 33290001Sglebius 34290001Sglebius#ifdef HAVE_NANOSLEEP 35290001Sglebius#include <time.h> 36290001Sglebius#endif 37290001Sglebius#include <unistd.h> 38290001Sglebius 39290001Sglebius#include <isc/platform.h> 40290001Sglebius#include <isc/strerror.h> 41290001Sglebius 42290001Sglebius#ifdef ISC_PLATFORM_NEEDSYSSELECTH 43290001Sglebius#include <sys/select.h> 44290001Sglebius#endif 45290001Sglebius 46290001Sglebius#include "errno2result.h" 47290001Sglebius 48290001Sglebius/*% 49290001Sglebius * There is only one variable in the entropy data structures that is not 50290001Sglebius * system independent, but pulling the structure that uses it into this file 51290001Sglebius * ultimately means pulling several other independent structures here also to 52290001Sglebius * resolve their interdependencies. Thus only the problem variable's type 53290001Sglebius * is defined here. 54290001Sglebius */ 55290001Sglebius#define FILESOURCE_HANDLE_TYPE int 56290001Sglebius 57290001Sglebiustypedef struct { 58290001Sglebius int handle; 59290001Sglebius enum { 60290001Sglebius isc_usocketsource_disconnected, 61290001Sglebius isc_usocketsource_connecting, 62290001Sglebius isc_usocketsource_connected, 63290001Sglebius isc_usocketsource_ndesired, 64290001Sglebius isc_usocketsource_wrote, 65290001Sglebius isc_usocketsource_reading 66290001Sglebius } status; 67290001Sglebius size_t sz_to_recv; 68290001Sglebius} isc_entropyusocketsource_t; 69290001Sglebius 70290001Sglebius#include "../entropy.c" 71290001Sglebius 72290001Sglebiusstatic unsigned int 73290001Sglebiusget_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) { 74290001Sglebius isc_entropy_t *ent = source->ent; 75290001Sglebius unsigned char buf[128]; 76290001Sglebius int fd = source->sources.file.handle; 77290001Sglebius ssize_t n, ndesired; 78290001Sglebius unsigned int added; 79290001Sglebius 80290001Sglebius if (source->bad) 81290001Sglebius return (0); 82290001Sglebius 83290001Sglebius desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); 84290001Sglebius 85290001Sglebius added = 0; 86290001Sglebius while (desired > 0) { 87290001Sglebius ndesired = ISC_MIN(desired, sizeof(buf)); 88290001Sglebius n = read(fd, buf, ndesired); 89290001Sglebius if (n < 0) { 90290001Sglebius if (errno == EAGAIN || errno == EINTR) 91290001Sglebius goto out; 92290001Sglebius goto err; 93290001Sglebius } 94290001Sglebius if (n == 0) 95290001Sglebius goto err; 96290001Sglebius 97290001Sglebius entropypool_adddata(ent, buf, n, n * 8); 98290001Sglebius added += n * 8; 99290001Sglebius desired -= n; 100290001Sglebius } 101290001Sglebius goto out; 102290001Sglebius 103290001Sglebius err: 104290001Sglebius (void)close(fd); 105290001Sglebius source->sources.file.handle = -1; 106290001Sglebius source->bad = ISC_TRUE; 107290001Sglebius 108290001Sglebius out: 109290001Sglebius return (added); 110290001Sglebius} 111290001Sglebius 112290001Sglebiusstatic unsigned int 113290001Sglebiusget_from_usocketsource(isc_entropysource_t *source, isc_uint32_t desired) { 114290001Sglebius isc_entropy_t *ent = source->ent; 115290001Sglebius unsigned char buf[128]; 116290001Sglebius int fd = source->sources.usocket.handle; 117290001Sglebius ssize_t n = 0, ndesired; 118290001Sglebius unsigned int added; 119290001Sglebius size_t sz_to_recv = source->sources.usocket.sz_to_recv; 120290001Sglebius 121290001Sglebius if (source->bad) 122290001Sglebius return (0); 123290001Sglebius 124290001Sglebius desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0); 125290001Sglebius 126290001Sglebius added = 0; 127290001Sglebius while (desired > 0) { 128290001Sglebius ndesired = ISC_MIN(desired, sizeof(buf)); 129290001Sglebius eagain_loop: 130290001Sglebius 131290001Sglebius switch ( source->sources.usocket.status ) { 132290001Sglebius case isc_usocketsource_ndesired: 133290001Sglebius buf[0] = ndesired; 134290001Sglebius if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) { 135290001Sglebius if (errno == EWOULDBLOCK || errno == EINTR || 136290001Sglebius errno == ECONNRESET) 137290001Sglebius goto out; 138290001Sglebius goto err; 139290001Sglebius } 140290001Sglebius INSIST(n == 1); 141290001Sglebius source->sources.usocket.status = 142290001Sglebius isc_usocketsource_wrote; 143290001Sglebius goto eagain_loop; 144290001Sglebius 145290001Sglebius case isc_usocketsource_connecting: 146290001Sglebius case isc_usocketsource_connected: 147290001Sglebius buf[0] = 1; 148290001Sglebius buf[1] = ndesired; 149290001Sglebius if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) { 150290001Sglebius if (errno == EWOULDBLOCK || errno == EINTR || 151290001Sglebius errno == ECONNRESET) 152290001Sglebius goto out; 153290001Sglebius goto err; 154290001Sglebius } 155290001Sglebius if (n == 1) { 156290001Sglebius source->sources.usocket.status = 157290001Sglebius isc_usocketsource_ndesired; 158290001Sglebius goto eagain_loop; 159290001Sglebius } 160290001Sglebius INSIST(n == 2); 161290001Sglebius source->sources.usocket.status = 162290001Sglebius isc_usocketsource_wrote; 163290001Sglebius /*FALLTHROUGH*/ 164290001Sglebius 165290001Sglebius case isc_usocketsource_wrote: 166290001Sglebius if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) { 167290001Sglebius if (errno == EAGAIN) { 168290001Sglebius /* 169290001Sglebius * The problem of EAGAIN (try again 170290001Sglebius * later) is a major issue on HP-UX. 171290001Sglebius * Solaris actually tries the recvfrom 172290001Sglebius * call again, while HP-UX just dies. 173290001Sglebius * This code is an attempt to let the 174290001Sglebius * entropy pool fill back up (at least 175290001Sglebius * that's what I think the problem is.) 176290001Sglebius * We go to eagain_loop because if we 177290001Sglebius * just "break", then the "desired" 178290001Sglebius * amount gets borked. 179290001Sglebius */ 180290001Sglebius#ifdef HAVE_NANOSLEEP 181290001Sglebius struct timespec ts; 182290001Sglebius 183290001Sglebius ts.tv_sec = 0; 184290001Sglebius ts.tv_nsec = 1000000; 185290001Sglebius nanosleep(&ts, NULL); 186290001Sglebius#else 187290001Sglebius usleep(1000); 188290001Sglebius#endif 189290001Sglebius goto eagain_loop; 190290001Sglebius } 191290001Sglebius if (errno == EWOULDBLOCK || errno == EINTR) 192290001Sglebius goto out; 193290001Sglebius goto err; 194290001Sglebius } 195290001Sglebius source->sources.usocket.status = 196290001Sglebius isc_usocketsource_reading; 197290001Sglebius sz_to_recv = buf[0]; 198290001Sglebius source->sources.usocket.sz_to_recv = sz_to_recv; 199290001Sglebius if (sz_to_recv > sizeof(buf)) 200290001Sglebius goto err; 201290001Sglebius /*FALLTHROUGH*/ 202290001Sglebius 203290001Sglebius case isc_usocketsource_reading: 204290001Sglebius if (sz_to_recv != 0U) { 205290001Sglebius n = recv(fd, buf, sz_to_recv, 0); 206290001Sglebius if (n < 0) { 207290001Sglebius if (errno == EWOULDBLOCK || 208290001Sglebius errno == EINTR) 209290001Sglebius goto out; 210290001Sglebius goto err; 211290001Sglebius } 212290001Sglebius } else 213290001Sglebius n = 0; 214290001Sglebius break; 215290001Sglebius 216290001Sglebius default: 217290001Sglebius goto err; 218290001Sglebius } 219290001Sglebius 220290001Sglebius if ((size_t)n != sz_to_recv) 221290001Sglebius source->sources.usocket.sz_to_recv -= n; 222290001Sglebius else 223290001Sglebius source->sources.usocket.status = 224290001Sglebius isc_usocketsource_connected; 225290001Sglebius 226290001Sglebius if (n == 0) 227290001Sglebius goto out; 228290001Sglebius 229290001Sglebius entropypool_adddata(ent, buf, n, n * 8); 230290001Sglebius added += n * 8; 231290001Sglebius desired -= n; 232290001Sglebius } 233290001Sglebius goto out; 234290001Sglebius 235290001Sglebius err: 236290001Sglebius close(fd); 237290001Sglebius source->bad = ISC_TRUE; 238290001Sglebius source->sources.usocket.status = isc_usocketsource_disconnected; 239290001Sglebius source->sources.usocket.handle = -1; 240290001Sglebius 241290001Sglebius out: 242290001Sglebius return (added); 243290001Sglebius} 244290001Sglebius 245290001Sglebius/* 246290001Sglebius * Poll each source, trying to get data from it to stuff into the entropy 247290001Sglebius * pool. 248290001Sglebius */ 249290001Sglebiusstatic void 250290001Sglebiusfillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) { 251290001Sglebius unsigned int added; 252290001Sglebius unsigned int remaining; 253290001Sglebius unsigned int needed; 254290001Sglebius unsigned int nsource; 255290001Sglebius isc_entropysource_t *source; 256290001Sglebius 257290001Sglebius REQUIRE(VALID_ENTROPY(ent)); 258290001Sglebius 259290001Sglebius needed = desired; 260290001Sglebius 261290001Sglebius /* 262290001Sglebius * This logic is a little strange, so an explanation is in order. 263290001Sglebius * 264290001Sglebius * If needed is 0, it means we are being asked to "fill to whatever 265290001Sglebius * we think is best." This means that if we have at least a 266290001Sglebius * partially full pool (say, > 1/4th of the pool) we probably don't 267290001Sglebius * need to add anything. 268290001Sglebius * 269290001Sglebius * Also, we will check to see if the "pseudo" count is too high. 270290001Sglebius * If it is, try to mix in better data. Too high is currently 271290001Sglebius * defined as 1/4th of the pool. 272290001Sglebius * 273290001Sglebius * Next, if we are asked to add a specific bit of entropy, make 274290001Sglebius * certain that we will do so. Clamp how much we try to add to 275290001Sglebius * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy). 276290001Sglebius * 277290001Sglebius * Note that if we are in a blocking mode, we will only try to 278290001Sglebius * get as much data as we need, not as much as we might want 279290001Sglebius * to build up. 280290001Sglebius */ 281290001Sglebius if (needed == 0) { 282290001Sglebius REQUIRE(!blocking); 283290001Sglebius 284290001Sglebius if ((ent->pool.entropy >= RND_POOLBITS / 4) 285290001Sglebius && (ent->pool.pseudo <= RND_POOLBITS / 4)) 286290001Sglebius return; 287290001Sglebius 288290001Sglebius needed = THRESHOLD_BITS * 4; 289290001Sglebius } else { 290290001Sglebius needed = ISC_MAX(needed, THRESHOLD_BITS); 291290001Sglebius needed = ISC_MIN(needed, RND_POOLBITS); 292290001Sglebius } 293290001Sglebius 294290001Sglebius /* 295290001Sglebius * In any case, clamp how much we need to how much we can add. 296290001Sglebius */ 297290001Sglebius needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy); 298290001Sglebius 299290001Sglebius /* 300290001Sglebius * But wait! If we're not yet initialized, we need at least 301290001Sglebius * THRESHOLD_BITS 302290001Sglebius * of randomness. 303290001Sglebius */ 304290001Sglebius if (ent->initialized < THRESHOLD_BITS) 305290001Sglebius needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized); 306290001Sglebius 307290001Sglebius /* 308290001Sglebius * Poll each file source to see if we can read anything useful from 309290001Sglebius * it. XXXMLG When where are multiple sources, we should keep a 310290001Sglebius * record of which one we last used so we can start from it (or the 311290001Sglebius * next one) to avoid letting some sources build up entropy while 312290001Sglebius * others are always drained. 313290001Sglebius */ 314290001Sglebius 315290001Sglebius added = 0; 316290001Sglebius remaining = needed; 317290001Sglebius if (ent->nextsource == NULL) { 318290001Sglebius ent->nextsource = ISC_LIST_HEAD(ent->sources); 319290001Sglebius if (ent->nextsource == NULL) 320290001Sglebius return; 321290001Sglebius } 322290001Sglebius source = ent->nextsource; 323290001Sglebius again_file: 324290001Sglebius for (nsource = 0; nsource < ent->nsources; nsource++) { 325290001Sglebius unsigned int got; 326290001Sglebius 327290001Sglebius if (remaining == 0) 328290001Sglebius break; 329290001Sglebius 330290001Sglebius got = 0; 331290001Sglebius 332290001Sglebius switch ( source->type ) { 333290001Sglebius case ENTROPY_SOURCETYPE_FILE: 334290001Sglebius got = get_from_filesource(source, remaining); 335290001Sglebius break; 336290001Sglebius 337290001Sglebius case ENTROPY_SOURCETYPE_USOCKET: 338290001Sglebius got = get_from_usocketsource(source, remaining); 339290001Sglebius break; 340290001Sglebius } 341290001Sglebius 342290001Sglebius added += got; 343290001Sglebius 344290001Sglebius remaining -= ISC_MIN(remaining, got); 345290001Sglebius 346290001Sglebius source = ISC_LIST_NEXT(source, link); 347290001Sglebius if (source == NULL) 348290001Sglebius source = ISC_LIST_HEAD(ent->sources); 349290001Sglebius } 350290001Sglebius ent->nextsource = source; 351290001Sglebius 352290001Sglebius if (blocking && remaining != 0) { 353290001Sglebius int fds; 354290001Sglebius 355290001Sglebius fds = wait_for_sources(ent); 356290001Sglebius if (fds > 0) 357290001Sglebius goto again_file; 358290001Sglebius } 359290001Sglebius 360290001Sglebius /* 361290001Sglebius * Here, if there are bits remaining to be had and we can block, 362290001Sglebius * check to see if we have a callback source. If so, call them. 363290001Sglebius */ 364290001Sglebius source = ISC_LIST_HEAD(ent->sources); 365290001Sglebius while ((remaining != 0) && (source != NULL)) { 366290001Sglebius unsigned int got; 367290001Sglebius 368290001Sglebius got = 0; 369290001Sglebius 370290001Sglebius if (source->type == ENTROPY_SOURCETYPE_CALLBACK) 371290001Sglebius got = get_from_callback(source, remaining, blocking); 372290001Sglebius 373290001Sglebius added += got; 374290001Sglebius remaining -= ISC_MIN(remaining, got); 375290001Sglebius 376290001Sglebius if (added >= needed) 377290001Sglebius break; 378290001Sglebius 379290001Sglebius source = ISC_LIST_NEXT(source, link); 380290001Sglebius } 381290001Sglebius 382290001Sglebius /* 383290001Sglebius * Mark as initialized if we've added enough data. 384290001Sglebius */ 385290001Sglebius if (ent->initialized < THRESHOLD_BITS) 386290001Sglebius ent->initialized += added; 387290001Sglebius} 388290001Sglebius 389290001Sglebiusstatic int 390290001Sglebiuswait_for_sources(isc_entropy_t *ent) { 391290001Sglebius isc_entropysource_t *source; 392290001Sglebius int maxfd, fd; 393290001Sglebius int cc; 394290001Sglebius fd_set reads; 395290001Sglebius fd_set writes; 396290001Sglebius 397290001Sglebius maxfd = -1; 398290001Sglebius FD_ZERO(&reads); 399290001Sglebius FD_ZERO(&writes); 400290001Sglebius 401290001Sglebius source = ISC_LIST_HEAD(ent->sources); 402290001Sglebius while (source != NULL) { 403290001Sglebius if (source->type == ENTROPY_SOURCETYPE_FILE) { 404290001Sglebius fd = source->sources.file.handle; 405290001Sglebius if (fd >= 0) { 406290001Sglebius maxfd = ISC_MAX(maxfd, fd); 407290001Sglebius FD_SET(fd, &reads); 408290001Sglebius } 409290001Sglebius } 410290001Sglebius if (source->type == ENTROPY_SOURCETYPE_USOCKET) { 411290001Sglebius fd = source->sources.usocket.handle; 412290001Sglebius if (fd >= 0) { 413290001Sglebius switch (source->sources.usocket.status) { 414290001Sglebius case isc_usocketsource_disconnected: 415290001Sglebius break; 416290001Sglebius case isc_usocketsource_connecting: 417290001Sglebius case isc_usocketsource_connected: 418290001Sglebius case isc_usocketsource_ndesired: 419290001Sglebius maxfd = ISC_MAX(maxfd, fd); 420290001Sglebius FD_SET(fd, &writes); 421290001Sglebius break; 422290001Sglebius case isc_usocketsource_wrote: 423290001Sglebius case isc_usocketsource_reading: 424290001Sglebius maxfd = ISC_MAX(maxfd, fd); 425290001Sglebius FD_SET(fd, &reads); 426290001Sglebius break; 427290001Sglebius } 428290001Sglebius } 429290001Sglebius } 430290001Sglebius source = ISC_LIST_NEXT(source, link); 431290001Sglebius } 432290001Sglebius 433290001Sglebius if (maxfd < 0) 434290001Sglebius return (-1); 435290001Sglebius 436290001Sglebius cc = select(maxfd + 1, &reads, &writes, NULL, NULL); 437290001Sglebius if (cc < 0) 438290001Sglebius return (-1); 439290001Sglebius 440290001Sglebius return (cc); 441290001Sglebius} 442290001Sglebius 443290001Sglebiusstatic void 444290001Sglebiusdestroyfilesource(isc_entropyfilesource_t *source) { 445290001Sglebius (void)close(source->handle); 446290001Sglebius} 447290001Sglebius 448290001Sglebiusstatic void 449290001Sglebiusdestroyusocketsource(isc_entropyusocketsource_t *source) { 450290001Sglebius close(source->handle); 451290001Sglebius} 452290001Sglebius 453290001Sglebius/* 454290001Sglebius * Make a fd non-blocking 455290001Sglebius */ 456290001Sglebiusstatic isc_result_t 457290001Sglebiusmake_nonblock(int fd) { 458290001Sglebius int ret; 459290001Sglebius int flags; 460290001Sglebius char strbuf[ISC_STRERRORSIZE]; 461290001Sglebius#ifdef USE_FIONBIO_IOCTL 462290001Sglebius int on = 1; 463290001Sglebius 464290001Sglebius ret = ioctl(fd, FIONBIO, (char *)&on); 465290001Sglebius#else 466290001Sglebius flags = fcntl(fd, F_GETFL, 0); 467290001Sglebius flags |= PORT_NONBLOCK; 468290001Sglebius ret = fcntl(fd, F_SETFL, flags); 469290001Sglebius#endif 470290001Sglebius 471290001Sglebius if (ret == -1) { 472290001Sglebius isc__strerror(errno, strbuf, sizeof(strbuf)); 473290001Sglebius UNEXPECTED_ERROR(__FILE__, __LINE__, 474290001Sglebius#ifdef USE_FIONBIO_IOCTL 475290001Sglebius "ioctl(%d, FIONBIO, &on): %s", fd, 476290001Sglebius#else 477290001Sglebius "fcntl(%d, F_SETFL, %d): %s", fd, flags, 478290001Sglebius#endif 479290001Sglebius strbuf); 480290001Sglebius 481290001Sglebius return (ISC_R_UNEXPECTED); 482290001Sglebius } 483290001Sglebius 484290001Sglebius return (ISC_R_SUCCESS); 485290001Sglebius} 486290001Sglebius 487290001Sglebiusisc_result_t 488290001Sglebiusisc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) { 489290001Sglebius int fd; 490290001Sglebius struct stat _stat; 491290001Sglebius isc_boolean_t is_usocket = ISC_FALSE; 492290001Sglebius isc_boolean_t is_connected = ISC_FALSE; 493290001Sglebius isc_result_t ret; 494290001Sglebius isc_entropysource_t *source; 495290001Sglebius 496290001Sglebius REQUIRE(VALID_ENTROPY(ent)); 497290001Sglebius REQUIRE(fname != NULL); 498290001Sglebius 499290001Sglebius LOCK(&ent->lock); 500290001Sglebius 501290001Sglebius if (stat(fname, &_stat) < 0) { 502290001Sglebius ret = isc__errno2result(errno); 503290001Sglebius goto errout; 504290001Sglebius } 505290001Sglebius /* 506290001Sglebius * Solaris 2.5.1 does not have support for sockets (S_IFSOCK), 507290001Sglebius * but it does return type S_IFIFO (the OS believes that 508290001Sglebius * the socket is a fifo). This may be an issue if we tell 509290001Sglebius * the program to look at an actual FIFO as its source of 510290001Sglebius * entropy. 511290001Sglebius */ 512290001Sglebius#if defined(S_ISSOCK) 513290001Sglebius if (S_ISSOCK(_stat.st_mode)) 514290001Sglebius is_usocket = ISC_TRUE; 515290001Sglebius#endif 516290001Sglebius#if defined(S_ISFIFO) && defined(sun) 517290001Sglebius if (S_ISFIFO(_stat.st_mode)) 518290001Sglebius is_usocket = ISC_TRUE; 519290001Sglebius#endif 520290001Sglebius if (is_usocket) 521290001Sglebius fd = socket(PF_UNIX, SOCK_STREAM, 0); 522290001Sglebius else 523290001Sglebius fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0); 524290001Sglebius 525290001Sglebius if (fd < 0) { 526290001Sglebius ret = isc__errno2result(errno); 527290001Sglebius goto errout; 528290001Sglebius } 529290001Sglebius 530290001Sglebius ret = make_nonblock(fd); 531290001Sglebius if (ret != ISC_R_SUCCESS) 532290001Sglebius goto closefd; 533290001Sglebius 534290001Sglebius if (is_usocket) { 535290001Sglebius struct sockaddr_un sname; 536290001Sglebius 537290001Sglebius memset(&sname, 0, sizeof(sname)); 538290001Sglebius sname.sun_family = AF_UNIX; 539290001Sglebius strncpy(sname.sun_path, fname, sizeof(sname.sun_path)); 540290001Sglebius sname.sun_path[sizeof(sname.sun_path)-1] = '0'; 541290001Sglebius#ifdef ISC_PLATFORM_HAVESALEN 542290001Sglebius#if !defined(SUN_LEN) 543290001Sglebius#define SUN_LEN(su) \ 544290001Sglebius (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path)) 545290001Sglebius#endif 546290001Sglebius sname.sun_len = SUN_LEN(&sname); 547290001Sglebius#endif 548290001Sglebius 549290001Sglebius if (connect(fd, (struct sockaddr *) &sname, 550290001Sglebius sizeof(struct sockaddr_un)) < 0) { 551290001Sglebius if (errno != EINPROGRESS) { 552290001Sglebius ret = isc__errno2result(errno); 553290001Sglebius goto closefd; 554290001Sglebius } 555290001Sglebius } else 556290001Sglebius is_connected = ISC_TRUE; 557290001Sglebius } 558290001Sglebius 559290001Sglebius source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t)); 560290001Sglebius if (source == NULL) { 561290001Sglebius ret = ISC_R_NOMEMORY; 562290001Sglebius goto closefd; 563290001Sglebius } 564290001Sglebius 565290001Sglebius /* 566290001Sglebius * From here down, no failures can occur. 567290001Sglebius */ 568290001Sglebius source->magic = SOURCE_MAGIC; 569290001Sglebius source->ent = ent; 570290001Sglebius source->total = 0; 571290001Sglebius source->bad = ISC_FALSE; 572290001Sglebius memset(source->name, 0, sizeof(source->name)); 573290001Sglebius ISC_LINK_INIT(source, link); 574290001Sglebius if (is_usocket) { 575290001Sglebius source->sources.usocket.handle = fd; 576290001Sglebius if (is_connected) 577290001Sglebius source->sources.usocket.status = 578290001Sglebius isc_usocketsource_connected; 579290001Sglebius else 580290001Sglebius source->sources.usocket.status = 581290001Sglebius isc_usocketsource_connecting; 582290001Sglebius source->sources.usocket.sz_to_recv = 0; 583290001Sglebius source->type = ENTROPY_SOURCETYPE_USOCKET; 584290001Sglebius } else { 585290001Sglebius source->sources.file.handle = fd; 586290001Sglebius source->type = ENTROPY_SOURCETYPE_FILE; 587290001Sglebius } 588290001Sglebius 589290001Sglebius /* 590290001Sglebius * Hook it into the entropy system. 591290001Sglebius */ 592290001Sglebius ISC_LIST_APPEND(ent->sources, source, link); 593290001Sglebius ent->nsources++; 594290001Sglebius 595290001Sglebius UNLOCK(&ent->lock); 596290001Sglebius return (ISC_R_SUCCESS); 597290001Sglebius 598290001Sglebius closefd: 599290001Sglebius (void)close(fd); 600290001Sglebius 601290001Sglebius errout: 602290001Sglebius UNLOCK(&ent->lock); 603290001Sglebius 604290001Sglebius return (ret); 605290001Sglebius} 606