1*00b67f09SDavid van Moolenbroek /* $NetBSD: entropy.c,v 1.5 2014/12/10 04:38:01 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2004-2008, 2012 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek * Copyright (C) 2000-2003 Internet Software Consortium.
6*00b67f09SDavid van Moolenbroek *
7*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
8*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
9*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
10*00b67f09SDavid van Moolenbroek *
11*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
18*00b67f09SDavid van Moolenbroek */
19*00b67f09SDavid van Moolenbroek
20*00b67f09SDavid van Moolenbroek /* Id: entropy.c,v 1.82 2008/12/01 23:47:45 tbox Exp */
21*00b67f09SDavid van Moolenbroek
22*00b67f09SDavid van Moolenbroek /* \file unix/entropy.c
23*00b67f09SDavid van Moolenbroek * \brief
24*00b67f09SDavid van Moolenbroek * This is the system dependent part of the ISC entropy API.
25*00b67f09SDavid van Moolenbroek */
26*00b67f09SDavid van Moolenbroek
27*00b67f09SDavid van Moolenbroek #include <config.h>
28*00b67f09SDavid van Moolenbroek
29*00b67f09SDavid van Moolenbroek #include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
30*00b67f09SDavid van Moolenbroek #include <sys/types.h>
31*00b67f09SDavid van Moolenbroek #include <sys/time.h>
32*00b67f09SDavid van Moolenbroek #include <sys/stat.h>
33*00b67f09SDavid van Moolenbroek #include <sys/socket.h>
34*00b67f09SDavid van Moolenbroek #include <sys/un.h>
35*00b67f09SDavid van Moolenbroek
36*00b67f09SDavid van Moolenbroek #ifdef HAVE_NANOSLEEP
37*00b67f09SDavid van Moolenbroek #include <time.h>
38*00b67f09SDavid van Moolenbroek #endif
39*00b67f09SDavid van Moolenbroek #include <unistd.h>
40*00b67f09SDavid van Moolenbroek
41*00b67f09SDavid van Moolenbroek #include <isc/platform.h>
42*00b67f09SDavid van Moolenbroek #include <isc/strerror.h>
43*00b67f09SDavid van Moolenbroek
44*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_NEEDSYSSELECTH
45*00b67f09SDavid van Moolenbroek #include <sys/select.h>
46*00b67f09SDavid van Moolenbroek #endif
47*00b67f09SDavid van Moolenbroek
48*00b67f09SDavid van Moolenbroek #include "errno2result.h"
49*00b67f09SDavid van Moolenbroek
50*00b67f09SDavid van Moolenbroek /*%
51*00b67f09SDavid van Moolenbroek * There is only one variable in the entropy data structures that is not
52*00b67f09SDavid van Moolenbroek * system independent, but pulling the structure that uses it into this file
53*00b67f09SDavid van Moolenbroek * ultimately means pulling several other independent structures here also to
54*00b67f09SDavid van Moolenbroek * resolve their interdependencies. Thus only the problem variable's type
55*00b67f09SDavid van Moolenbroek * is defined here.
56*00b67f09SDavid van Moolenbroek */
57*00b67f09SDavid van Moolenbroek #define FILESOURCE_HANDLE_TYPE int
58*00b67f09SDavid van Moolenbroek
59*00b67f09SDavid van Moolenbroek typedef struct {
60*00b67f09SDavid van Moolenbroek int handle;
61*00b67f09SDavid van Moolenbroek enum {
62*00b67f09SDavid van Moolenbroek isc_usocketsource_disconnected,
63*00b67f09SDavid van Moolenbroek isc_usocketsource_connecting,
64*00b67f09SDavid van Moolenbroek isc_usocketsource_connected,
65*00b67f09SDavid van Moolenbroek isc_usocketsource_ndesired,
66*00b67f09SDavid van Moolenbroek isc_usocketsource_wrote,
67*00b67f09SDavid van Moolenbroek isc_usocketsource_reading
68*00b67f09SDavid van Moolenbroek } status;
69*00b67f09SDavid van Moolenbroek size_t sz_to_recv;
70*00b67f09SDavid van Moolenbroek } isc_entropyusocketsource_t;
71*00b67f09SDavid van Moolenbroek
72*00b67f09SDavid van Moolenbroek #include "../entropy.c"
73*00b67f09SDavid van Moolenbroek
74*00b67f09SDavid van Moolenbroek static unsigned int
get_from_filesource(isc_entropysource_t * source,isc_uint32_t desired)75*00b67f09SDavid van Moolenbroek get_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
76*00b67f09SDavid van Moolenbroek isc_entropy_t *ent = source->ent;
77*00b67f09SDavid van Moolenbroek unsigned char buf[128];
78*00b67f09SDavid van Moolenbroek int fd = source->sources.file.handle;
79*00b67f09SDavid van Moolenbroek ssize_t n, ndesired;
80*00b67f09SDavid van Moolenbroek unsigned int added;
81*00b67f09SDavid van Moolenbroek
82*00b67f09SDavid van Moolenbroek if (source->bad)
83*00b67f09SDavid van Moolenbroek return (0);
84*00b67f09SDavid van Moolenbroek
85*00b67f09SDavid van Moolenbroek desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
86*00b67f09SDavid van Moolenbroek
87*00b67f09SDavid van Moolenbroek added = 0;
88*00b67f09SDavid van Moolenbroek while (desired > 0) {
89*00b67f09SDavid van Moolenbroek ndesired = ISC_MIN(desired, sizeof(buf));
90*00b67f09SDavid van Moolenbroek n = read(fd, buf, ndesired);
91*00b67f09SDavid van Moolenbroek if (n < 0) {
92*00b67f09SDavid van Moolenbroek if (errno == EAGAIN || errno == EINTR)
93*00b67f09SDavid van Moolenbroek goto out;
94*00b67f09SDavid van Moolenbroek goto err;
95*00b67f09SDavid van Moolenbroek }
96*00b67f09SDavid van Moolenbroek if (n == 0)
97*00b67f09SDavid van Moolenbroek goto err;
98*00b67f09SDavid van Moolenbroek
99*00b67f09SDavid van Moolenbroek entropypool_adddata(ent, buf, n, n * 8);
100*00b67f09SDavid van Moolenbroek added += n * 8;
101*00b67f09SDavid van Moolenbroek desired -= n;
102*00b67f09SDavid van Moolenbroek }
103*00b67f09SDavid van Moolenbroek goto out;
104*00b67f09SDavid van Moolenbroek
105*00b67f09SDavid van Moolenbroek err:
106*00b67f09SDavid van Moolenbroek (void)close(fd);
107*00b67f09SDavid van Moolenbroek source->sources.file.handle = -1;
108*00b67f09SDavid van Moolenbroek source->bad = ISC_TRUE;
109*00b67f09SDavid van Moolenbroek
110*00b67f09SDavid van Moolenbroek out:
111*00b67f09SDavid van Moolenbroek return (added);
112*00b67f09SDavid van Moolenbroek }
113*00b67f09SDavid van Moolenbroek
114*00b67f09SDavid van Moolenbroek static unsigned int
get_from_usocketsource(isc_entropysource_t * source,isc_uint32_t desired)115*00b67f09SDavid van Moolenbroek get_from_usocketsource(isc_entropysource_t *source, isc_uint32_t desired) {
116*00b67f09SDavid van Moolenbroek isc_entropy_t *ent = source->ent;
117*00b67f09SDavid van Moolenbroek unsigned char buf[128];
118*00b67f09SDavid van Moolenbroek int fd = source->sources.usocket.handle;
119*00b67f09SDavid van Moolenbroek ssize_t n = 0, ndesired;
120*00b67f09SDavid van Moolenbroek unsigned int added;
121*00b67f09SDavid van Moolenbroek size_t sz_to_recv = source->sources.usocket.sz_to_recv;
122*00b67f09SDavid van Moolenbroek
123*00b67f09SDavid van Moolenbroek if (source->bad)
124*00b67f09SDavid van Moolenbroek return (0);
125*00b67f09SDavid van Moolenbroek
126*00b67f09SDavid van Moolenbroek desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
127*00b67f09SDavid van Moolenbroek
128*00b67f09SDavid van Moolenbroek added = 0;
129*00b67f09SDavid van Moolenbroek while (desired > 0) {
130*00b67f09SDavid van Moolenbroek ndesired = ISC_MIN(desired, sizeof(buf));
131*00b67f09SDavid van Moolenbroek eagain_loop:
132*00b67f09SDavid van Moolenbroek
133*00b67f09SDavid van Moolenbroek switch ( source->sources.usocket.status ) {
134*00b67f09SDavid van Moolenbroek case isc_usocketsource_ndesired:
135*00b67f09SDavid van Moolenbroek buf[0] = ndesired;
136*00b67f09SDavid van Moolenbroek if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) {
137*00b67f09SDavid van Moolenbroek if (errno == EWOULDBLOCK || errno == EINTR ||
138*00b67f09SDavid van Moolenbroek errno == ECONNRESET)
139*00b67f09SDavid van Moolenbroek goto out;
140*00b67f09SDavid van Moolenbroek goto err;
141*00b67f09SDavid van Moolenbroek }
142*00b67f09SDavid van Moolenbroek INSIST(n == 1);
143*00b67f09SDavid van Moolenbroek source->sources.usocket.status =
144*00b67f09SDavid van Moolenbroek isc_usocketsource_wrote;
145*00b67f09SDavid van Moolenbroek goto eagain_loop;
146*00b67f09SDavid van Moolenbroek
147*00b67f09SDavid van Moolenbroek case isc_usocketsource_connecting:
148*00b67f09SDavid van Moolenbroek case isc_usocketsource_connected:
149*00b67f09SDavid van Moolenbroek buf[0] = 1;
150*00b67f09SDavid van Moolenbroek buf[1] = ndesired;
151*00b67f09SDavid van Moolenbroek if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) {
152*00b67f09SDavid van Moolenbroek if (errno == EWOULDBLOCK || errno == EINTR ||
153*00b67f09SDavid van Moolenbroek errno == ECONNRESET)
154*00b67f09SDavid van Moolenbroek goto out;
155*00b67f09SDavid van Moolenbroek goto err;
156*00b67f09SDavid van Moolenbroek }
157*00b67f09SDavid van Moolenbroek if (n == 1) {
158*00b67f09SDavid van Moolenbroek source->sources.usocket.status =
159*00b67f09SDavid van Moolenbroek isc_usocketsource_ndesired;
160*00b67f09SDavid van Moolenbroek goto eagain_loop;
161*00b67f09SDavid van Moolenbroek }
162*00b67f09SDavid van Moolenbroek INSIST(n == 2);
163*00b67f09SDavid van Moolenbroek source->sources.usocket.status =
164*00b67f09SDavid van Moolenbroek isc_usocketsource_wrote;
165*00b67f09SDavid van Moolenbroek /*FALLTHROUGH*/
166*00b67f09SDavid van Moolenbroek
167*00b67f09SDavid van Moolenbroek case isc_usocketsource_wrote:
168*00b67f09SDavid van Moolenbroek if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) {
169*00b67f09SDavid van Moolenbroek if (errno == EAGAIN) {
170*00b67f09SDavid van Moolenbroek /*
171*00b67f09SDavid van Moolenbroek * The problem of EAGAIN (try again
172*00b67f09SDavid van Moolenbroek * later) is a major issue on HP-UX.
173*00b67f09SDavid van Moolenbroek * Solaris actually tries the recvfrom
174*00b67f09SDavid van Moolenbroek * call again, while HP-UX just dies.
175*00b67f09SDavid van Moolenbroek * This code is an attempt to let the
176*00b67f09SDavid van Moolenbroek * entropy pool fill back up (at least
177*00b67f09SDavid van Moolenbroek * that's what I think the problem is.)
178*00b67f09SDavid van Moolenbroek * We go to eagain_loop because if we
179*00b67f09SDavid van Moolenbroek * just "break", then the "desired"
180*00b67f09SDavid van Moolenbroek * amount gets borked.
181*00b67f09SDavid van Moolenbroek */
182*00b67f09SDavid van Moolenbroek #ifdef HAVE_NANOSLEEP
183*00b67f09SDavid van Moolenbroek struct timespec ts;
184*00b67f09SDavid van Moolenbroek
185*00b67f09SDavid van Moolenbroek ts.tv_sec = 0;
186*00b67f09SDavid van Moolenbroek ts.tv_nsec = 1000000;
187*00b67f09SDavid van Moolenbroek nanosleep(&ts, NULL);
188*00b67f09SDavid van Moolenbroek #else
189*00b67f09SDavid van Moolenbroek usleep(1000);
190*00b67f09SDavid van Moolenbroek #endif
191*00b67f09SDavid van Moolenbroek goto eagain_loop;
192*00b67f09SDavid van Moolenbroek }
193*00b67f09SDavid van Moolenbroek if (errno == EWOULDBLOCK || errno == EINTR)
194*00b67f09SDavid van Moolenbroek goto out;
195*00b67f09SDavid van Moolenbroek goto err;
196*00b67f09SDavid van Moolenbroek }
197*00b67f09SDavid van Moolenbroek source->sources.usocket.status =
198*00b67f09SDavid van Moolenbroek isc_usocketsource_reading;
199*00b67f09SDavid van Moolenbroek sz_to_recv = buf[0];
200*00b67f09SDavid van Moolenbroek source->sources.usocket.sz_to_recv = sz_to_recv;
201*00b67f09SDavid van Moolenbroek if (sz_to_recv > sizeof(buf))
202*00b67f09SDavid van Moolenbroek goto err;
203*00b67f09SDavid van Moolenbroek /*FALLTHROUGH*/
204*00b67f09SDavid van Moolenbroek
205*00b67f09SDavid van Moolenbroek case isc_usocketsource_reading:
206*00b67f09SDavid van Moolenbroek if (sz_to_recv != 0U) {
207*00b67f09SDavid van Moolenbroek n = recv(fd, buf, sz_to_recv, 0);
208*00b67f09SDavid van Moolenbroek if (n < 0) {
209*00b67f09SDavid van Moolenbroek if (errno == EWOULDBLOCK ||
210*00b67f09SDavid van Moolenbroek errno == EINTR)
211*00b67f09SDavid van Moolenbroek goto out;
212*00b67f09SDavid van Moolenbroek goto err;
213*00b67f09SDavid van Moolenbroek }
214*00b67f09SDavid van Moolenbroek } else
215*00b67f09SDavid van Moolenbroek n = 0;
216*00b67f09SDavid van Moolenbroek break;
217*00b67f09SDavid van Moolenbroek
218*00b67f09SDavid van Moolenbroek default:
219*00b67f09SDavid van Moolenbroek goto err;
220*00b67f09SDavid van Moolenbroek }
221*00b67f09SDavid van Moolenbroek
222*00b67f09SDavid van Moolenbroek if ((size_t)n != sz_to_recv)
223*00b67f09SDavid van Moolenbroek source->sources.usocket.sz_to_recv -= n;
224*00b67f09SDavid van Moolenbroek else
225*00b67f09SDavid van Moolenbroek source->sources.usocket.status =
226*00b67f09SDavid van Moolenbroek isc_usocketsource_connected;
227*00b67f09SDavid van Moolenbroek
228*00b67f09SDavid van Moolenbroek if (n == 0)
229*00b67f09SDavid van Moolenbroek goto out;
230*00b67f09SDavid van Moolenbroek
231*00b67f09SDavid van Moolenbroek entropypool_adddata(ent, buf, n, n * 8);
232*00b67f09SDavid van Moolenbroek added += n * 8;
233*00b67f09SDavid van Moolenbroek desired -= n;
234*00b67f09SDavid van Moolenbroek }
235*00b67f09SDavid van Moolenbroek goto out;
236*00b67f09SDavid van Moolenbroek
237*00b67f09SDavid van Moolenbroek err:
238*00b67f09SDavid van Moolenbroek close(fd);
239*00b67f09SDavid van Moolenbroek source->bad = ISC_TRUE;
240*00b67f09SDavid van Moolenbroek source->sources.usocket.status = isc_usocketsource_disconnected;
241*00b67f09SDavid van Moolenbroek source->sources.usocket.handle = -1;
242*00b67f09SDavid van Moolenbroek
243*00b67f09SDavid van Moolenbroek out:
244*00b67f09SDavid van Moolenbroek return (added);
245*00b67f09SDavid van Moolenbroek }
246*00b67f09SDavid van Moolenbroek
247*00b67f09SDavid van Moolenbroek /*
248*00b67f09SDavid van Moolenbroek * Poll each source, trying to get data from it to stuff into the entropy
249*00b67f09SDavid van Moolenbroek * pool.
250*00b67f09SDavid van Moolenbroek */
251*00b67f09SDavid van Moolenbroek static void
fillpool(isc_entropy_t * ent,unsigned int desired,isc_boolean_t blocking)252*00b67f09SDavid van Moolenbroek fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
253*00b67f09SDavid van Moolenbroek unsigned int added;
254*00b67f09SDavid van Moolenbroek unsigned int remaining;
255*00b67f09SDavid van Moolenbroek unsigned int needed;
256*00b67f09SDavid van Moolenbroek unsigned int nsource;
257*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
258*00b67f09SDavid van Moolenbroek
259*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
260*00b67f09SDavid van Moolenbroek
261*00b67f09SDavid van Moolenbroek needed = desired;
262*00b67f09SDavid van Moolenbroek
263*00b67f09SDavid van Moolenbroek /*
264*00b67f09SDavid van Moolenbroek * This logic is a little strange, so an explanation is in order.
265*00b67f09SDavid van Moolenbroek *
266*00b67f09SDavid van Moolenbroek * If needed is 0, it means we are being asked to "fill to whatever
267*00b67f09SDavid van Moolenbroek * we think is best." This means that if we have at least a
268*00b67f09SDavid van Moolenbroek * partially full pool (say, > 1/4th of the pool) we probably don't
269*00b67f09SDavid van Moolenbroek * need to add anything.
270*00b67f09SDavid van Moolenbroek *
271*00b67f09SDavid van Moolenbroek * Also, we will check to see if the "pseudo" count is too high.
272*00b67f09SDavid van Moolenbroek * If it is, try to mix in better data. Too high is currently
273*00b67f09SDavid van Moolenbroek * defined as 1/4th of the pool.
274*00b67f09SDavid van Moolenbroek *
275*00b67f09SDavid van Moolenbroek * Next, if we are asked to add a specific bit of entropy, make
276*00b67f09SDavid van Moolenbroek * certain that we will do so. Clamp how much we try to add to
277*00b67f09SDavid van Moolenbroek * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
278*00b67f09SDavid van Moolenbroek *
279*00b67f09SDavid van Moolenbroek * Note that if we are in a blocking mode, we will only try to
280*00b67f09SDavid van Moolenbroek * get as much data as we need, not as much as we might want
281*00b67f09SDavid van Moolenbroek * to build up.
282*00b67f09SDavid van Moolenbroek */
283*00b67f09SDavid van Moolenbroek if (needed == 0) {
284*00b67f09SDavid van Moolenbroek REQUIRE(!blocking);
285*00b67f09SDavid van Moolenbroek
286*00b67f09SDavid van Moolenbroek if ((ent->pool.entropy >= RND_POOLBITS / 4)
287*00b67f09SDavid van Moolenbroek && (ent->pool.pseudo <= RND_POOLBITS / 4))
288*00b67f09SDavid van Moolenbroek return;
289*00b67f09SDavid van Moolenbroek
290*00b67f09SDavid van Moolenbroek needed = THRESHOLD_BITS * 4;
291*00b67f09SDavid van Moolenbroek } else {
292*00b67f09SDavid van Moolenbroek needed = ISC_MAX(needed, THRESHOLD_BITS);
293*00b67f09SDavid van Moolenbroek needed = ISC_MIN(needed, RND_POOLBITS);
294*00b67f09SDavid van Moolenbroek }
295*00b67f09SDavid van Moolenbroek
296*00b67f09SDavid van Moolenbroek /*
297*00b67f09SDavid van Moolenbroek * In any case, clamp how much we need to how much we can add.
298*00b67f09SDavid van Moolenbroek */
299*00b67f09SDavid van Moolenbroek needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
300*00b67f09SDavid van Moolenbroek
301*00b67f09SDavid van Moolenbroek /*
302*00b67f09SDavid van Moolenbroek * But wait! If we're not yet initialized, we need at least
303*00b67f09SDavid van Moolenbroek * THRESHOLD_BITS
304*00b67f09SDavid van Moolenbroek * of randomness.
305*00b67f09SDavid van Moolenbroek */
306*00b67f09SDavid van Moolenbroek if (ent->initialized < THRESHOLD_BITS)
307*00b67f09SDavid van Moolenbroek needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
308*00b67f09SDavid van Moolenbroek
309*00b67f09SDavid van Moolenbroek /*
310*00b67f09SDavid van Moolenbroek * Poll each file source to see if we can read anything useful from
311*00b67f09SDavid van Moolenbroek * it. XXXMLG When where are multiple sources, we should keep a
312*00b67f09SDavid van Moolenbroek * record of which one we last used so we can start from it (or the
313*00b67f09SDavid van Moolenbroek * next one) to avoid letting some sources build up entropy while
314*00b67f09SDavid van Moolenbroek * others are always drained.
315*00b67f09SDavid van Moolenbroek */
316*00b67f09SDavid van Moolenbroek
317*00b67f09SDavid van Moolenbroek added = 0;
318*00b67f09SDavid van Moolenbroek remaining = needed;
319*00b67f09SDavid van Moolenbroek if (ent->nextsource == NULL) {
320*00b67f09SDavid van Moolenbroek ent->nextsource = ISC_LIST_HEAD(ent->sources);
321*00b67f09SDavid van Moolenbroek if (ent->nextsource == NULL)
322*00b67f09SDavid van Moolenbroek return;
323*00b67f09SDavid van Moolenbroek }
324*00b67f09SDavid van Moolenbroek source = ent->nextsource;
325*00b67f09SDavid van Moolenbroek again_file:
326*00b67f09SDavid van Moolenbroek for (nsource = 0; nsource < ent->nsources; nsource++) {
327*00b67f09SDavid van Moolenbroek unsigned int got;
328*00b67f09SDavid van Moolenbroek
329*00b67f09SDavid van Moolenbroek if (remaining == 0)
330*00b67f09SDavid van Moolenbroek break;
331*00b67f09SDavid van Moolenbroek
332*00b67f09SDavid van Moolenbroek got = 0;
333*00b67f09SDavid van Moolenbroek
334*00b67f09SDavid van Moolenbroek switch ( source->type ) {
335*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_FILE:
336*00b67f09SDavid van Moolenbroek got = get_from_filesource(source, remaining);
337*00b67f09SDavid van Moolenbroek break;
338*00b67f09SDavid van Moolenbroek
339*00b67f09SDavid van Moolenbroek case ENTROPY_SOURCETYPE_USOCKET:
340*00b67f09SDavid van Moolenbroek got = get_from_usocketsource(source, remaining);
341*00b67f09SDavid van Moolenbroek break;
342*00b67f09SDavid van Moolenbroek }
343*00b67f09SDavid van Moolenbroek
344*00b67f09SDavid van Moolenbroek added += got;
345*00b67f09SDavid van Moolenbroek
346*00b67f09SDavid van Moolenbroek remaining -= ISC_MIN(remaining, got);
347*00b67f09SDavid van Moolenbroek
348*00b67f09SDavid van Moolenbroek source = ISC_LIST_NEXT(source, link);
349*00b67f09SDavid van Moolenbroek if (source == NULL)
350*00b67f09SDavid van Moolenbroek source = ISC_LIST_HEAD(ent->sources);
351*00b67f09SDavid van Moolenbroek }
352*00b67f09SDavid van Moolenbroek ent->nextsource = source;
353*00b67f09SDavid van Moolenbroek
354*00b67f09SDavid van Moolenbroek if (blocking && remaining != 0) {
355*00b67f09SDavid van Moolenbroek int fds;
356*00b67f09SDavid van Moolenbroek
357*00b67f09SDavid van Moolenbroek fds = wait_for_sources(ent);
358*00b67f09SDavid van Moolenbroek if (fds > 0)
359*00b67f09SDavid van Moolenbroek goto again_file;
360*00b67f09SDavid van Moolenbroek }
361*00b67f09SDavid van Moolenbroek
362*00b67f09SDavid van Moolenbroek /*
363*00b67f09SDavid van Moolenbroek * Here, if there are bits remaining to be had and we can block,
364*00b67f09SDavid van Moolenbroek * check to see if we have a callback source. If so, call them.
365*00b67f09SDavid van Moolenbroek */
366*00b67f09SDavid van Moolenbroek source = ISC_LIST_HEAD(ent->sources);
367*00b67f09SDavid van Moolenbroek while ((remaining != 0) && (source != NULL)) {
368*00b67f09SDavid van Moolenbroek unsigned int got;
369*00b67f09SDavid van Moolenbroek
370*00b67f09SDavid van Moolenbroek got = 0;
371*00b67f09SDavid van Moolenbroek
372*00b67f09SDavid van Moolenbroek if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
373*00b67f09SDavid van Moolenbroek got = get_from_callback(source, remaining, blocking);
374*00b67f09SDavid van Moolenbroek
375*00b67f09SDavid van Moolenbroek added += got;
376*00b67f09SDavid van Moolenbroek remaining -= ISC_MIN(remaining, got);
377*00b67f09SDavid van Moolenbroek
378*00b67f09SDavid van Moolenbroek if (added >= needed)
379*00b67f09SDavid van Moolenbroek break;
380*00b67f09SDavid van Moolenbroek
381*00b67f09SDavid van Moolenbroek source = ISC_LIST_NEXT(source, link);
382*00b67f09SDavid van Moolenbroek }
383*00b67f09SDavid van Moolenbroek
384*00b67f09SDavid van Moolenbroek /*
385*00b67f09SDavid van Moolenbroek * Mark as initialized if we've added enough data.
386*00b67f09SDavid van Moolenbroek */
387*00b67f09SDavid van Moolenbroek if (ent->initialized < THRESHOLD_BITS)
388*00b67f09SDavid van Moolenbroek ent->initialized += added;
389*00b67f09SDavid van Moolenbroek }
390*00b67f09SDavid van Moolenbroek
391*00b67f09SDavid van Moolenbroek static int
wait_for_sources(isc_entropy_t * ent)392*00b67f09SDavid van Moolenbroek wait_for_sources(isc_entropy_t *ent) {
393*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
394*00b67f09SDavid van Moolenbroek int maxfd, fd;
395*00b67f09SDavid van Moolenbroek int cc;
396*00b67f09SDavid van Moolenbroek fd_set reads;
397*00b67f09SDavid van Moolenbroek fd_set writes;
398*00b67f09SDavid van Moolenbroek
399*00b67f09SDavid van Moolenbroek maxfd = -1;
400*00b67f09SDavid van Moolenbroek FD_ZERO(&reads);
401*00b67f09SDavid van Moolenbroek FD_ZERO(&writes);
402*00b67f09SDavid van Moolenbroek
403*00b67f09SDavid van Moolenbroek source = ISC_LIST_HEAD(ent->sources);
404*00b67f09SDavid van Moolenbroek while (source != NULL) {
405*00b67f09SDavid van Moolenbroek if (source->type == ENTROPY_SOURCETYPE_FILE) {
406*00b67f09SDavid van Moolenbroek fd = source->sources.file.handle;
407*00b67f09SDavid van Moolenbroek if (fd >= 0) {
408*00b67f09SDavid van Moolenbroek maxfd = ISC_MAX(maxfd, fd);
409*00b67f09SDavid van Moolenbroek FD_SET(fd, &reads);
410*00b67f09SDavid van Moolenbroek }
411*00b67f09SDavid van Moolenbroek }
412*00b67f09SDavid van Moolenbroek if (source->type == ENTROPY_SOURCETYPE_USOCKET) {
413*00b67f09SDavid van Moolenbroek fd = source->sources.usocket.handle;
414*00b67f09SDavid van Moolenbroek if (fd >= 0) {
415*00b67f09SDavid van Moolenbroek switch (source->sources.usocket.status) {
416*00b67f09SDavid van Moolenbroek case isc_usocketsource_disconnected:
417*00b67f09SDavid van Moolenbroek break;
418*00b67f09SDavid van Moolenbroek case isc_usocketsource_connecting:
419*00b67f09SDavid van Moolenbroek case isc_usocketsource_connected:
420*00b67f09SDavid van Moolenbroek case isc_usocketsource_ndesired:
421*00b67f09SDavid van Moolenbroek maxfd = ISC_MAX(maxfd, fd);
422*00b67f09SDavid van Moolenbroek FD_SET(fd, &writes);
423*00b67f09SDavid van Moolenbroek break;
424*00b67f09SDavid van Moolenbroek case isc_usocketsource_wrote:
425*00b67f09SDavid van Moolenbroek case isc_usocketsource_reading:
426*00b67f09SDavid van Moolenbroek maxfd = ISC_MAX(maxfd, fd);
427*00b67f09SDavid van Moolenbroek FD_SET(fd, &reads);
428*00b67f09SDavid van Moolenbroek break;
429*00b67f09SDavid van Moolenbroek }
430*00b67f09SDavid van Moolenbroek }
431*00b67f09SDavid van Moolenbroek }
432*00b67f09SDavid van Moolenbroek source = ISC_LIST_NEXT(source, link);
433*00b67f09SDavid van Moolenbroek }
434*00b67f09SDavid van Moolenbroek
435*00b67f09SDavid van Moolenbroek if (maxfd < 0)
436*00b67f09SDavid van Moolenbroek return (-1);
437*00b67f09SDavid van Moolenbroek
438*00b67f09SDavid van Moolenbroek cc = select(maxfd + 1, &reads, &writes, NULL, NULL);
439*00b67f09SDavid van Moolenbroek if (cc < 0)
440*00b67f09SDavid van Moolenbroek return (-1);
441*00b67f09SDavid van Moolenbroek
442*00b67f09SDavid van Moolenbroek return (cc);
443*00b67f09SDavid van Moolenbroek }
444*00b67f09SDavid van Moolenbroek
445*00b67f09SDavid van Moolenbroek static void
destroyfilesource(isc_entropyfilesource_t * source)446*00b67f09SDavid van Moolenbroek destroyfilesource(isc_entropyfilesource_t *source) {
447*00b67f09SDavid van Moolenbroek (void)close(source->handle);
448*00b67f09SDavid van Moolenbroek }
449*00b67f09SDavid van Moolenbroek
450*00b67f09SDavid van Moolenbroek static void
destroyusocketsource(isc_entropyusocketsource_t * source)451*00b67f09SDavid van Moolenbroek destroyusocketsource(isc_entropyusocketsource_t *source) {
452*00b67f09SDavid van Moolenbroek close(source->handle);
453*00b67f09SDavid van Moolenbroek }
454*00b67f09SDavid van Moolenbroek
455*00b67f09SDavid van Moolenbroek /*
456*00b67f09SDavid van Moolenbroek * Make a fd non-blocking
457*00b67f09SDavid van Moolenbroek */
458*00b67f09SDavid van Moolenbroek static isc_result_t
make_nonblock(int fd)459*00b67f09SDavid van Moolenbroek make_nonblock(int fd) {
460*00b67f09SDavid van Moolenbroek int ret;
461*00b67f09SDavid van Moolenbroek int flags;
462*00b67f09SDavid van Moolenbroek char strbuf[ISC_STRERRORSIZE];
463*00b67f09SDavid van Moolenbroek #ifdef USE_FIONBIO_IOCTL
464*00b67f09SDavid van Moolenbroek int on = 1;
465*00b67f09SDavid van Moolenbroek
466*00b67f09SDavid van Moolenbroek ret = ioctl(fd, FIONBIO, (char *)&on);
467*00b67f09SDavid van Moolenbroek #else
468*00b67f09SDavid van Moolenbroek flags = fcntl(fd, F_GETFL, 0);
469*00b67f09SDavid van Moolenbroek flags |= PORT_NONBLOCK;
470*00b67f09SDavid van Moolenbroek ret = fcntl(fd, F_SETFL, flags);
471*00b67f09SDavid van Moolenbroek #endif
472*00b67f09SDavid van Moolenbroek
473*00b67f09SDavid van Moolenbroek if (ret == -1) {
474*00b67f09SDavid van Moolenbroek isc__strerror(errno, strbuf, sizeof(strbuf));
475*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
476*00b67f09SDavid van Moolenbroek #ifdef USE_FIONBIO_IOCTL
477*00b67f09SDavid van Moolenbroek "ioctl(%d, FIONBIO, &on): %s", fd,
478*00b67f09SDavid van Moolenbroek #else
479*00b67f09SDavid van Moolenbroek "fcntl(%d, F_SETFL, %d): %s", fd, flags,
480*00b67f09SDavid van Moolenbroek #endif
481*00b67f09SDavid van Moolenbroek strbuf);
482*00b67f09SDavid van Moolenbroek
483*00b67f09SDavid van Moolenbroek return (ISC_R_UNEXPECTED);
484*00b67f09SDavid van Moolenbroek }
485*00b67f09SDavid van Moolenbroek
486*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
487*00b67f09SDavid van Moolenbroek }
488*00b67f09SDavid van Moolenbroek
489*00b67f09SDavid van Moolenbroek isc_result_t
isc_entropy_createfilesource(isc_entropy_t * ent,const char * fname)490*00b67f09SDavid van Moolenbroek isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
491*00b67f09SDavid van Moolenbroek int fd;
492*00b67f09SDavid van Moolenbroek struct stat _stat;
493*00b67f09SDavid van Moolenbroek isc_boolean_t is_usocket = ISC_FALSE;
494*00b67f09SDavid van Moolenbroek isc_boolean_t is_connected = ISC_FALSE;
495*00b67f09SDavid van Moolenbroek isc_result_t ret;
496*00b67f09SDavid van Moolenbroek isc_entropysource_t *source;
497*00b67f09SDavid van Moolenbroek
498*00b67f09SDavid van Moolenbroek REQUIRE(VALID_ENTROPY(ent));
499*00b67f09SDavid van Moolenbroek REQUIRE(fname != NULL);
500*00b67f09SDavid van Moolenbroek
501*00b67f09SDavid van Moolenbroek LOCK(&ent->lock);
502*00b67f09SDavid van Moolenbroek
503*00b67f09SDavid van Moolenbroek if (stat(fname, &_stat) < 0) {
504*00b67f09SDavid van Moolenbroek ret = isc__errno2result(errno);
505*00b67f09SDavid van Moolenbroek goto errout;
506*00b67f09SDavid van Moolenbroek }
507*00b67f09SDavid van Moolenbroek /*
508*00b67f09SDavid van Moolenbroek * Solaris 2.5.1 does not have support for sockets (S_IFSOCK),
509*00b67f09SDavid van Moolenbroek * but it does return type S_IFIFO (the OS believes that
510*00b67f09SDavid van Moolenbroek * the socket is a fifo). This may be an issue if we tell
511*00b67f09SDavid van Moolenbroek * the program to look at an actual FIFO as its source of
512*00b67f09SDavid van Moolenbroek * entropy.
513*00b67f09SDavid van Moolenbroek */
514*00b67f09SDavid van Moolenbroek #if defined(S_ISSOCK)
515*00b67f09SDavid van Moolenbroek if (S_ISSOCK(_stat.st_mode))
516*00b67f09SDavid van Moolenbroek is_usocket = ISC_TRUE;
517*00b67f09SDavid van Moolenbroek #endif
518*00b67f09SDavid van Moolenbroek #if defined(S_ISFIFO) && defined(sun)
519*00b67f09SDavid van Moolenbroek if (S_ISFIFO(_stat.st_mode))
520*00b67f09SDavid van Moolenbroek is_usocket = ISC_TRUE;
521*00b67f09SDavid van Moolenbroek #endif
522*00b67f09SDavid van Moolenbroek if (is_usocket)
523*00b67f09SDavid van Moolenbroek fd = socket(PF_UNIX, SOCK_STREAM, 0);
524*00b67f09SDavid van Moolenbroek else
525*00b67f09SDavid van Moolenbroek fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0);
526*00b67f09SDavid van Moolenbroek
527*00b67f09SDavid van Moolenbroek if (fd < 0) {
528*00b67f09SDavid van Moolenbroek ret = isc__errno2result(errno);
529*00b67f09SDavid van Moolenbroek goto errout;
530*00b67f09SDavid van Moolenbroek }
531*00b67f09SDavid van Moolenbroek
532*00b67f09SDavid van Moolenbroek ret = make_nonblock(fd);
533*00b67f09SDavid van Moolenbroek if (ret != ISC_R_SUCCESS)
534*00b67f09SDavid van Moolenbroek goto closefd;
535*00b67f09SDavid van Moolenbroek
536*00b67f09SDavid van Moolenbroek if (is_usocket) {
537*00b67f09SDavid van Moolenbroek struct sockaddr_un sname;
538*00b67f09SDavid van Moolenbroek
539*00b67f09SDavid van Moolenbroek memset(&sname, 0, sizeof(sname));
540*00b67f09SDavid van Moolenbroek sname.sun_family = AF_UNIX;
541*00b67f09SDavid van Moolenbroek strlcpy(sname.sun_path, fname, sizeof(sname.sun_path));
542*00b67f09SDavid van Moolenbroek #ifdef ISC_PLATFORM_HAVESALEN
543*00b67f09SDavid van Moolenbroek #if !defined(SUN_LEN)
544*00b67f09SDavid van Moolenbroek #define SUN_LEN(su) \
545*00b67f09SDavid van Moolenbroek (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
546*00b67f09SDavid van Moolenbroek #endif
547*00b67f09SDavid van Moolenbroek sname.sun_len = SUN_LEN(&sname);
548*00b67f09SDavid van Moolenbroek #endif
549*00b67f09SDavid van Moolenbroek
550*00b67f09SDavid van Moolenbroek if (connect(fd, (struct sockaddr *) &sname,
551*00b67f09SDavid van Moolenbroek sizeof(struct sockaddr_un)) < 0) {
552*00b67f09SDavid van Moolenbroek if (errno != EINPROGRESS) {
553*00b67f09SDavid van Moolenbroek ret = isc__errno2result(errno);
554*00b67f09SDavid van Moolenbroek goto closefd;
555*00b67f09SDavid van Moolenbroek }
556*00b67f09SDavid van Moolenbroek } else
557*00b67f09SDavid van Moolenbroek is_connected = ISC_TRUE;
558*00b67f09SDavid van Moolenbroek }
559*00b67f09SDavid van Moolenbroek
560*00b67f09SDavid van Moolenbroek source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
561*00b67f09SDavid van Moolenbroek if (source == NULL) {
562*00b67f09SDavid van Moolenbroek ret = ISC_R_NOMEMORY;
563*00b67f09SDavid van Moolenbroek goto closefd;
564*00b67f09SDavid van Moolenbroek }
565*00b67f09SDavid van Moolenbroek
566*00b67f09SDavid van Moolenbroek /*
567*00b67f09SDavid van Moolenbroek * From here down, no failures can occur.
568*00b67f09SDavid van Moolenbroek */
569*00b67f09SDavid van Moolenbroek source->magic = SOURCE_MAGIC;
570*00b67f09SDavid van Moolenbroek source->ent = ent;
571*00b67f09SDavid van Moolenbroek source->total = 0;
572*00b67f09SDavid van Moolenbroek source->bad = ISC_FALSE;
573*00b67f09SDavid van Moolenbroek memset(source->name, 0, sizeof(source->name));
574*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(source, link);
575*00b67f09SDavid van Moolenbroek if (is_usocket) {
576*00b67f09SDavid van Moolenbroek source->sources.usocket.handle = fd;
577*00b67f09SDavid van Moolenbroek if (is_connected)
578*00b67f09SDavid van Moolenbroek source->sources.usocket.status =
579*00b67f09SDavid van Moolenbroek isc_usocketsource_connected;
580*00b67f09SDavid van Moolenbroek else
581*00b67f09SDavid van Moolenbroek source->sources.usocket.status =
582*00b67f09SDavid van Moolenbroek isc_usocketsource_connecting;
583*00b67f09SDavid van Moolenbroek source->sources.usocket.sz_to_recv = 0;
584*00b67f09SDavid van Moolenbroek source->type = ENTROPY_SOURCETYPE_USOCKET;
585*00b67f09SDavid van Moolenbroek } else {
586*00b67f09SDavid van Moolenbroek source->sources.file.handle = fd;
587*00b67f09SDavid van Moolenbroek source->type = ENTROPY_SOURCETYPE_FILE;
588*00b67f09SDavid van Moolenbroek }
589*00b67f09SDavid van Moolenbroek
590*00b67f09SDavid van Moolenbroek /*
591*00b67f09SDavid van Moolenbroek * Hook it into the entropy system.
592*00b67f09SDavid van Moolenbroek */
593*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(ent->sources, source, link);
594*00b67f09SDavid van Moolenbroek ent->nsources++;
595*00b67f09SDavid van Moolenbroek
596*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
597*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
598*00b67f09SDavid van Moolenbroek
599*00b67f09SDavid van Moolenbroek closefd:
600*00b67f09SDavid van Moolenbroek (void)close(fd);
601*00b67f09SDavid van Moolenbroek
602*00b67f09SDavid van Moolenbroek errout:
603*00b67f09SDavid van Moolenbroek UNLOCK(&ent->lock);
604*00b67f09SDavid van Moolenbroek
605*00b67f09SDavid van Moolenbroek return (ret);
606*00b67f09SDavid van Moolenbroek }
607