]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
1213. [func] Entropy can now be retrieved from EGDs. [RT #2438]
authorMark Andrews <marka@isc.org>
Thu, 30 May 2002 04:21:17 +0000 (04:21 +0000)
committerMark Andrews <marka@isc.org>
Thu, 30 May 2002 04:21:17 +0000 (04:21 +0000)
CHANGES
lib/isc/entropy.c
lib/isc/unix/entropy.c
lib/isc/win32/entropy.c

diff --git a/CHANGES b/CHANGES
index a8259bdd45e5f876b650f8ab10163a9c560c9e05..ac8381a509c3c9eef5d02f7deab39c3f3f2526fc 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+1213.  [func]          Entropy can now be retrieved from EGDs. [RT #2438]
+
 1212.  [func]          Enable IPv6 support when using ioctl style interface
                        scanning and OS supports SIOCGLIFADDR using struct
                        if_laddrreq.
index bf7a484d234dd34a576801def746c7f146082a0b..2f08bd55fd6cc7c7028800be6985938f58e247fe 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: entropy.c,v 1.8 2001/11/30 01:59:32 gson Exp $ */
+/* $Id: entropy.c,v 1.9 2002/05/30 04:21:14 marka Exp $ */
 
 /*
  * This is the system independent part of the entropy module.  It is
@@ -147,12 +147,14 @@ struct isc_entropysource {
                isc_entropysamplesource_t       sample;
                isc_entropyfilesource_t         file;
                isc_cbsource_t                  callback;
+               isc_entropyusocketsource_t      usocket;
        } sources;
 };
 
 #define ENTROPY_SOURCETYPE_SAMPLE      1       /* Type is a sample source */
 #define ENTROPY_SOURCETYPE_FILE                2       /* Type is a file source */
 #define ENTROPY_SOURCETYPE_CALLBACK    3       /* Type is a callback source */
+#define ENTROPY_SOURCETYPE_USOCKET     4       /* Type is a Unix socket source */
 
 /*
  * The random pool "taps"
@@ -176,6 +178,9 @@ wait_for_sources(isc_entropy_t *);
 static void
 destroyfilesource(isc_entropyfilesource_t *source);
 
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source);
+
 
 static void
 samplequeue_release(isc_entropy_t *ent, sample_queue_t *sq) {
@@ -721,6 +726,10 @@ destroysource(isc_entropysource_t **sourcep) {
                if (! source->bad)
                        destroyfilesource(&source->sources.file);
                break;
+       case ENTROPY_SOURCETYPE_USOCKET:
+               if (! source->bad)
+                       destroyusocketsource(&source->sources.usocket);
+               break;
        case ENTROPY_SOURCETYPE_SAMPLE:
                samplequeue_release(ent, &source->sources.sample.samplequeue);
                break;
@@ -750,6 +759,7 @@ destroy_check(isc_entropy_t *ent) {
        while (source != NULL) {
                switch (source->type) {
                case ENTROPY_SOURCETYPE_FILE:
+               case ENTROPY_SOURCETYPE_USOCKET:
                        break;
                default:
                        return (ISC_FALSE);
@@ -781,6 +791,7 @@ destroy(isc_entropy_t **entp) {
        while (source != NULL) {
                switch(source->type) {
                case ENTROPY_SOURCETYPE_FILE:
+               case ENTROPY_SOURCETYPE_USOCKET:
                        destroysource(&source);
                        break;
                }
index 3129ce6af84798bf482f1d19c5b2c5f6ca62b439..a3e933ad7b0f6548e95c3df339e28a23da883e84 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: entropy.c,v 1.65 2002/05/10 06:41:55 marka Exp $ */
+/* $Id: entropy.c,v 1.66 2002/05/30 04:21:15 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>
 
  */
 #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
@@ -89,6 +105,131 @@ get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
        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 != 0) {
+                               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);
+}
+
 /*
  * Poll each source, trying to get data from it to stuff into the entropy
  * pool.
@@ -176,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;
 
@@ -232,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) {
@@ -245,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);
 
@@ -263,6 +433,11 @@ destroyfilesource(isc_entropyfilesource_t *source) {
        (void)close(source->handle);
 }
 
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source) {
+       close(source->handle);
+}
+
 /*
  * Make a fd non-blocking
  */
@@ -291,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_boolean_t is_connected = ISC_FALSE;
        isc_result_t ret;
        isc_entropysource_t *source;
 
@@ -301,15 +479,63 @@ 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 ((_stat.st_mode & S_IFSOCK) != 0
+#ifdef _SOCKET_IS_FIFO
+            || (_stat.st_mode & S_IFIFO) != 0
+#endif
+           ) {
+               fd = socket(PF_UNIX, SOCK_STREAM, 0);
+               is_usocket = ISC_TRUE;
+       } else {
+               fd = open(fname, O_RDONLY | O_NONBLOCK, 0);
+               is_usocket = ISC_FALSE;
+       }
+
        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;
@@ -320,13 +546,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.
index 67095c37865b54b6752d16a0752e316c43749a3b..8fbef4e99bb06a0ae7517eda973508b9a9edcafa 100644 (file)
@@ -15,7 +15,7 @@
  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: entropy.c,v 1.4 2001/11/27 00:56:21 gson Exp $ */
+/* $Id: entropy.c,v 1.5 2002/05/30 04:21:17 marka Exp $ */
 
 /*
  * This is the system depenedent part of the ISC entropy API.
  */
 #define FILESOURCE_HANDLE_TYPE HCRYPTPROV
 
+typedef struct {
+       int dummy;
+} isc_entropyusocketsource_t;
+
 #include "../entropy.c"
 
 static unsigned int
@@ -227,6 +231,11 @@ destroyfilesource(isc_entropyfilesource_t *source) {
        CryptReleaseContext(source->handle, 0);
 }
 
+static void
+destroyusocketsource(isc_entropyusocketsource_t *source) {
+       UNUSED(source);
+}
+
 
 isc_result_t
 isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {