summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bind/lib/isc/unix/entropy.c
diff options
context:
space:
mode:
authorjakob <jakob@openbsd.org>2004-09-28 16:32:07 +0000
committerjakob <jakob@openbsd.org>2004-09-28 16:32:07 +0000
commitfaa7e856a16b326b2afee3ddb8d19f2f91f85161 (patch)
treea66b6d52d6af5dba140eb36c266ce2cc83b741f9 /usr.sbin/bind/lib/isc/unix/entropy.c
parentsync (oops) (diff)
downloadwireguard-openbsd-faa7e856a16b326b2afee3ddb8d19f2f91f85161.tar.xz
wireguard-openbsd-faa7e856a16b326b2afee3ddb8d19f2f91f85161.zip
ISC BIND version 9.3.0. ok deraadt@
Diffstat (limited to 'usr.sbin/bind/lib/isc/unix/entropy.c')
-rw-r--r--usr.sbin/bind/lib/isc/unix/entropy.c288
1 files changed, 264 insertions, 24 deletions
diff --git a/usr.sbin/bind/lib/isc/unix/entropy.c b/usr.sbin/bind/lib/isc/unix/entropy.c
index 005de6810d7..8c73be6f14b 100644
--- a/usr.sbin/bind/lib/isc/unix/entropy.c
+++ b/usr.sbin/bind/lib/isc/unix/entropy.c
@@ -1,21 +1,21 @@
/*
- * Copyright (C) 2000-2002 Internet Software Consortium.
+ * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2000-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
- * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
- * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
- * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
- * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
- * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
*/
-/* $ISC: entropy.c,v 1.60.2.3 2002/08/05 06:57:16 marka Exp $ */
+/* $ISC: entropy.c,v 1.60.2.3.8.9 2004/03/16 05:02:31 marka Exp $ */
/*
* This is the system depenedent part of the ISC entropy API.
@@ -26,6 +26,9 @@
#include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
#include <sys/types.h>
#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/un.h>
#include <unistd.h>
@@ -47,6 +50,19 @@
*/
#define FILESOURCE_HANDLE_TYPE int
+typedef struct {
+ int handle;
+ enum {
+ isc_usocketsource_disconnected,
+ isc_usocketsource_connecting,
+ isc_usocketsource_connected,
+ isc_usocketsource_ndesired,
+ isc_usocketsource_wrote,
+ isc_usocketsource_reading
+ } status;
+ size_t sz_to_recv;
+} isc_entropyusocketsource_t;
+
#include "../entropy.c"
static unsigned int
@@ -69,20 +85,146 @@ get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
if (n < 0) {
if (errno == EAGAIN || errno == EINTR)
goto out;
- close(fd);
- source->bad = ISC_TRUE;
- goto out;
+ goto err;
}
- if (n == 0) {
- close(fd);
- source->bad = ISC_TRUE;
- goto out;
+ if (n == 0)
+ goto err;
+
+ entropypool_adddata(ent, buf, n, n * 8);
+ added += n * 8;
+ desired -= n;
+ }
+ goto out;
+
+ err:
+ (void)close(fd);
+ source->sources.file.handle = -1;
+ source->bad = ISC_TRUE;
+
+ out:
+ return (added);
+}
+
+static unsigned int
+get_from_usocketsource(isc_entropysource_t *source, isc_uint32_t desired) {
+ isc_entropy_t *ent = source->ent;
+ unsigned char buf[128];
+ int fd = source->sources.usocket.handle;
+ ssize_t n = 0, ndesired;
+ unsigned int added;
+ size_t sz_to_recv = source->sources.usocket.sz_to_recv;
+
+ if (source->bad)
+ return (0);
+
+ desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
+
+ added = 0;
+ while (desired > 0) {
+ ndesired = ISC_MIN(desired, sizeof(buf));
+ eagain_loop:
+
+ switch ( source->sources.usocket.status ) {
+ case isc_usocketsource_ndesired:
+ buf[0] = ndesired;
+ if ((n = send(fd, buf, 1, 0)) < 0) {
+ if (errno == EWOULDBLOCK || errno == EINTR ||
+ errno == ECONNRESET)
+ goto out;
+ goto err;
+ }
+ INSIST(n == 1);
+ source->sources.usocket.status =
+ isc_usocketsource_wrote;
+ goto eagain_loop;
+
+ case isc_usocketsource_connecting:
+ case isc_usocketsource_connected:
+ buf[0] = 1;
+ buf[1] = ndesired;
+ if ((n = send(fd, buf, 2, 0)) < 0) {
+ if (errno == EWOULDBLOCK || errno == EINTR ||
+ errno == ECONNRESET)
+ goto out;
+ goto err;
+ }
+ if (n == 1) {
+ source->sources.usocket.status =
+ isc_usocketsource_ndesired;
+ goto eagain_loop;
+ }
+ INSIST(n == 2);
+ source->sources.usocket.status =
+ isc_usocketsource_wrote;
+ /*FALLTHROUGH*/
+
+ case isc_usocketsource_wrote:
+ if (recv(fd, buf, 1, 0) != 1) {
+ if (errno == EAGAIN) {
+ /*
+ * The problem of EAGAIN (try again
+ * later) is a major issue on HP-UX.
+ * Solaris actually tries the recv
+ * call again, while HP-UX just dies.
+ * This code is an attempt to let the
+ * entropy pool fill back up (at least
+ * that's what I think the problem is.)
+ * We go to eagain_loop because if we
+ * just "break", then the "desired"
+ * amount gets borked.
+ */
+ usleep(1000);
+ goto eagain_loop;
+ }
+ if (errno == EWOULDBLOCK || errno == EINTR)
+ goto out;
+ goto err;
+ }
+ source->sources.usocket.status =
+ isc_usocketsource_reading;
+ sz_to_recv = buf[0];
+ source->sources.usocket.sz_to_recv = sz_to_recv;
+ if (sz_to_recv > sizeof(buf))
+ goto err;
+ /*FALLTHROUGH*/
+
+ case isc_usocketsource_reading:
+ if (sz_to_recv != 0U) {
+ n = recv(fd, buf, sz_to_recv, 0);
+ if (n < 0) {
+ if (errno == EWOULDBLOCK ||
+ errno == EINTR)
+ goto out;
+ goto err;
+ }
+ } else
+ n = 0;
+ break;
+
+ default:
+ goto err;
}
+ if ((size_t)n != sz_to_recv)
+ source->sources.usocket.sz_to_recv -= n;
+ else
+ source->sources.usocket.status =
+ isc_usocketsource_connected;
+
+ if (n == 0)
+ goto out;
+
entropypool_adddata(ent, buf, n, n * 8);
added += n * 8;
desired -= n;
}
+ goto out;
+
+ err:
+ close(fd);
+ source->bad = ISC_TRUE;
+ source->sources.usocket.status = isc_usocketsource_disconnected;
+ source->sources.usocket.handle = -1;
out:
return (added);
@@ -167,7 +309,7 @@ fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
}
source = ent->nextsource;
again_file:
- for (nsource = 0 ; nsource < ent->nsources ; nsource++) {
+ for (nsource = 0; nsource < ent->nsources; nsource++) {
unsigned int got;
if (remaining == 0)
@@ -175,8 +317,15 @@ fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
got = 0;
- if (source->type == ENTROPY_SOURCETYPE_FILE)
+ switch ( source->type ) {
+ case ENTROPY_SOURCETYPE_FILE:
got = get_from_filesource(source, remaining);
+ break;
+
+ case ENTROPY_SOURCETYPE_USOCKET:
+ got = get_from_usocketsource(source, remaining);
+ break;
+ }
added += got;
@@ -231,9 +380,11 @@ wait_for_sources(isc_entropy_t *ent) {
int maxfd, fd;
int cc;
fd_set reads;
+ fd_set writes;
maxfd = -1;
FD_ZERO(&reads);
+ FD_ZERO(&writes);
source = ISC_LIST_HEAD(ent->sources);
while (source != NULL) {
@@ -244,13 +395,33 @@ wait_for_sources(isc_entropy_t *ent) {
FD_SET(fd, &reads);
}
}
+ if (source->type == ENTROPY_SOURCETYPE_USOCKET) {
+ fd = source->sources.usocket.handle;
+ if (fd >= 0) {
+ switch (source->sources.usocket.status) {
+ case isc_usocketsource_disconnected:
+ break;
+ case isc_usocketsource_connecting:
+ case isc_usocketsource_connected:
+ case isc_usocketsource_ndesired:
+ maxfd = ISC_MAX(maxfd, fd);
+ FD_SET(fd, &writes);
+ break;
+ case isc_usocketsource_wrote:
+ case isc_usocketsource_reading:
+ maxfd = ISC_MAX(maxfd, fd);
+ FD_SET(fd, &reads);
+ break;
+ }
+ }
+ }
source = ISC_LIST_NEXT(source, link);
}
if (maxfd < 0)
return (-1);
- cc = select(maxfd + 1, &reads, NULL, NULL, NULL);
+ cc = select(maxfd + 1, &reads, &writes, NULL, NULL);
if (cc < 0)
return (-1);
@@ -259,6 +430,11 @@ wait_for_sources(isc_entropy_t *ent) {
static void
destroyfilesource(isc_entropyfilesource_t *source) {
+ (void)close(source->handle);
+}
+
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source) {
close(source->handle);
}
@@ -290,6 +466,9 @@ make_nonblock(int fd) {
isc_result_t
isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
int fd;
+ struct stat _stat;
+ isc_boolean_t is_usocket = ISC_FALSE;
+ isc_boolean_t is_connected = ISC_FALSE;
isc_result_t ret;
isc_entropysource_t *source;
@@ -300,15 +479,64 @@ isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
source = NULL;
- fd = open(fname, O_RDONLY | O_NONBLOCK, 0);
+ if (stat(fname, &_stat) < 0) {
+ ret = isc__errno2result(errno);
+ goto errout;
+ }
+ /*
+ * Solaris 2.5.1 does not have support for sockets (S_IFSOCK),
+ * but it does return type S_IFIFO (the OS believes that
+ * the socket is a fifo). This may be an issue if we tell
+ * the program to look at an actual FIFO as its source of
+ * entropy.
+ */
+#if defined(S_ISSOCK)
+ if (S_ISSOCK(_stat.st_mode))
+ is_usocket = ISC_TRUE;
+#endif
+#if defined(S_ISFIFO)
+ if (S_ISFIFO(_stat.st_mode))
+ is_usocket = ISC_TRUE;
+#endif
+ if (is_usocket)
+ fd = socket(PF_UNIX, SOCK_STREAM, 0);
+ else
+ fd = open(fname, O_RDONLY | O_NONBLOCK, 0);
+
if (fd < 0) {
ret = isc__errno2result(errno);
goto errout;
}
+
ret = make_nonblock(fd);
if (ret != ISC_R_SUCCESS)
goto closefd;
+ if (is_usocket) {
+ struct sockaddr_un sname;
+
+ memset(&sname, 0, sizeof(sname));
+ sname.sun_family = AF_UNIX;
+ strncpy(sname.sun_path, fname, sizeof(sname.sun_path));
+ sname.sun_path[sizeof(sname.sun_path)-1] = '0';
+#ifdef ISC_PLATFORM_HAVESALEN
+#if !defined(SUN_LEN)
+#define SUN_LEN(su) \
+ (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
+#endif
+ sname.sun_len = SUN_LEN(&sname);
+#endif
+
+ if (connect(fd, (struct sockaddr *) &sname,
+ sizeof(struct sockaddr_un)) < 0) {
+ if (errno != EINPROGRESS) {
+ ret = isc__errno2result(errno);
+ goto closefd;
+ }
+ } else
+ is_connected = ISC_TRUE;
+ }
+
source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
if (source == NULL) {
ret = ISC_R_NOMEMORY;
@@ -319,13 +547,25 @@ isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
* From here down, no failures can occur.
*/
source->magic = SOURCE_MAGIC;
- source->type = ENTROPY_SOURCETYPE_FILE;
source->ent = ent;
source->total = 0;
source->bad = ISC_FALSE;
memset(source->name, 0, sizeof(source->name));
ISC_LINK_INIT(source, link);
- source->sources.file.handle = fd;
+ if (is_usocket) {
+ source->sources.usocket.handle = fd;
+ if (is_connected)
+ source->sources.usocket.status =
+ isc_usocketsource_connected;
+ else
+ source->sources.usocket.status =
+ isc_usocketsource_connecting;
+ source->sources.usocket.sz_to_recv = 0;
+ source->type = ENTROPY_SOURCETYPE_USOCKET;
+ } else {
+ source->sources.file.handle = fd;
+ source->type = ENTROPY_SOURCETYPE_FILE;
+ }
/*
* Hook it into the entropy system.
@@ -337,7 +577,7 @@ isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
return (ISC_R_SUCCESS);
closefd:
- close(fd);
+ (void)close(fd);
errout:
if (source != NULL)