2 * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2002 Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: entropy.c,v 1.60.2.4 2004/03/09 06:12:09 marka Exp $ */
21 * This is the system depenedent part of the ISC entropy API.
26 #include <sys/param.h> /* Openserver 5.0.6A and FD_SETSIZE */
27 #include <sys/types.h>
32 #include <isc/platform.h>
33 #include <isc/strerror.h>
35 #ifdef ISC_PLATFORM_NEEDSYSSELECTH
36 #include <sys/select.h>
39 #include "errno2result.h"
42 * There is only one variable in the entropy data structures that is not
43 * system independent, but pulling the structure that uses it into this file
44 * ultimately means pulling several other independent structures here also to
45 * resolve their interdependencies. Thus only the problem variable's type
48 #define FILESOURCE_HANDLE_TYPE int
50 #include "../entropy.c"
53 get_from_filesource(isc_entropysource_t
*source
, isc_uint32_t desired
) {
54 isc_entropy_t
*ent
= source
->ent
;
55 unsigned char buf
[128];
56 int fd
= source
->sources
.file
.handle
;
63 desired
= desired
/ 8 + (((desired
& 0x07) > 0) ? 1 : 0);
67 ndesired
= ISC_MIN(desired
, sizeof(buf
));
68 n
= read(fd
, buf
, ndesired
);
70 if (errno
== EAGAIN
|| errno
== EINTR
)
73 source
->bad
= ISC_TRUE
;
78 source
->bad
= ISC_TRUE
;
82 entropypool_adddata(ent
, buf
, n
, n
* 8);
92 * Poll each source, trying to get data from it to stuff into the entropy
96 fillpool(isc_entropy_t
*ent
, unsigned int desired
, isc_boolean_t blocking
) {
98 unsigned int remaining
;
100 unsigned int nsource
;
101 isc_entropysource_t
*source
;
103 REQUIRE(VALID_ENTROPY(ent
));
108 * This logic is a little strange, so an explanation is in order.
110 * If needed is 0, it means we are being asked to "fill to whatever
111 * we think is best." This means that if we have at least a
112 * partially full pool (say, > 1/4th of the pool) we probably don't
113 * need to add anything.
115 * Also, we will check to see if the "pseudo" count is too high.
116 * If it is, try to mix in better data. Too high is currently
117 * defined as 1/4th of the pool.
119 * Next, if we are asked to add a specific bit of entropy, make
120 * certain that we will do so. Clamp how much we try to add to
121 * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
123 * Note that if we are in a blocking mode, we will only try to
124 * get as much data as we need, not as much as we might want
130 if ((ent
->pool
.entropy
>= RND_POOLBITS
/ 4)
131 && (ent
->pool
.pseudo
<= RND_POOLBITS
/ 4))
134 needed
= THRESHOLD_BITS
* 4;
136 needed
= ISC_MAX(needed
, THRESHOLD_BITS
);
137 needed
= ISC_MIN(needed
, RND_POOLBITS
);
141 * In any case, clamp how much we need to how much we can add.
143 needed
= ISC_MIN(needed
, RND_POOLBITS
- ent
->pool
.entropy
);
146 * But wait! If we're not yet initialized, we need at least
150 if (ent
->initialized
< THRESHOLD_BITS
)
151 needed
= ISC_MAX(needed
, THRESHOLD_BITS
- ent
->initialized
);
154 * Poll each file source to see if we can read anything useful from
155 * it. XXXMLG When where are multiple sources, we should keep a
156 * record of which one we last used so we can start from it (or the
157 * next one) to avoid letting some sources build up entropy while
158 * others are always drained.
163 if (ent
->nextsource
== NULL
) {
164 ent
->nextsource
= ISC_LIST_HEAD(ent
->sources
);
165 if (ent
->nextsource
== NULL
)
168 source
= ent
->nextsource
;
170 for (nsource
= 0 ; nsource
< ent
->nsources
; nsource
++) {
178 if (source
->type
== ENTROPY_SOURCETYPE_FILE
)
179 got
= get_from_filesource(source
, remaining
);
183 remaining
-= ISC_MIN(remaining
, got
);
185 source
= ISC_LIST_NEXT(source
, link
);
187 source
= ISC_LIST_HEAD(ent
->sources
);
189 ent
->nextsource
= source
;
191 if (blocking
&& remaining
!= 0) {
194 fds
= wait_for_sources(ent
);
200 * Here, if there are bits remaining to be had and we can block,
201 * check to see if we have a callback source. If so, call them.
203 source
= ISC_LIST_HEAD(ent
->sources
);
204 while ((remaining
!= 0) && (source
!= NULL
)) {
209 if (source
->type
== ENTROPY_SOURCETYPE_CALLBACK
)
210 got
= get_from_callback(source
, remaining
, blocking
);
213 remaining
-= ISC_MIN(remaining
, got
);
218 source
= ISC_LIST_NEXT(source
, link
);
222 * Mark as initialized if we've added enough data.
224 if (ent
->initialized
< THRESHOLD_BITS
)
225 ent
->initialized
+= added
;
229 wait_for_sources(isc_entropy_t
*ent
) {
230 isc_entropysource_t
*source
;
238 source
= ISC_LIST_HEAD(ent
->sources
);
239 while (source
!= NULL
) {
240 if (source
->type
== ENTROPY_SOURCETYPE_FILE
) {
241 fd
= source
->sources
.file
.handle
;
243 maxfd
= ISC_MAX(maxfd
, fd
);
247 source
= ISC_LIST_NEXT(source
, link
);
253 cc
= select(maxfd
+ 1, &reads
, NULL
, NULL
, NULL
);
261 destroyfilesource(isc_entropyfilesource_t
*source
) {
262 close(source
->handle
);
266 * Make a fd non-blocking
269 make_nonblock(int fd
) {
272 char strbuf
[ISC_STRERRORSIZE
];
274 flags
= fcntl(fd
, F_GETFL
, 0);
276 ret
= fcntl(fd
, F_SETFL
, flags
);
279 isc__strerror(errno
, strbuf
, sizeof(strbuf
));
280 UNEXPECTED_ERROR(__FILE__
, __LINE__
,
281 "fcntl(%d, F_SETFL, %d): %s",
284 return (ISC_R_UNEXPECTED
);
287 return (ISC_R_SUCCESS
);
291 isc_entropy_createfilesource(isc_entropy_t
*ent
, const char *fname
) {
294 isc_entropysource_t
*source
;
296 REQUIRE(VALID_ENTROPY(ent
));
297 REQUIRE(fname
!= NULL
);
303 fd
= open(fname
, O_RDONLY
| O_NONBLOCK
, 0);
305 ret
= isc__errno2result(errno
);
308 ret
= make_nonblock(fd
);
309 if (ret
!= ISC_R_SUCCESS
)
312 source
= isc_mem_get(ent
->mctx
, sizeof(isc_entropysource_t
));
313 if (source
== NULL
) {
314 ret
= ISC_R_NOMEMORY
;
319 * From here down, no failures can occur.
321 source
->magic
= SOURCE_MAGIC
;
322 source
->type
= ENTROPY_SOURCETYPE_FILE
;
325 source
->bad
= ISC_FALSE
;
326 memset(source
->name
, 0, sizeof(source
->name
));
327 ISC_LINK_INIT(source
, link
);
328 source
->sources
.file
.handle
= fd
;
331 * Hook it into the entropy system.
333 ISC_LIST_APPEND(ent
->sources
, source
, link
);
337 return (ISC_R_SUCCESS
);
344 isc_mem_put(ent
->mctx
, source
, sizeof(isc_entropysource_t
));