1254721Semaste/*
2254721Semaste * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
3254721Semaste * Copyright (C) 2000-2003  Internet Software Consortium.
4254721Semaste *
5254721Semaste * Permission to use, copy, modify, and/or distribute this software for any
6254721Semaste * purpose with or without fee is hereby granted, provided that the above
7254721Semaste * copyright notice and this permission notice appear in all copies.
8254721Semaste *
9254721Semaste * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10254721Semaste * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11254721Semaste * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12254721Semaste * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13254721Semaste * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14254721Semaste * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15254721Semaste * PERFORMANCE OF THIS SOFTWARE.
16254721Semaste */
17254721Semaste
18254721Semaste/* $Id: entropy.c,v 1.82 2008/12/01 23:47:45 tbox Exp $ */
19254721Semaste
20254721Semaste/* \file unix/entropy.c
21269024Semaste * \brief
22254721Semaste * This is the system dependent part of the ISC entropy API.
23254721Semaste */
24254721Semaste
25254721Semaste#include <config.h>
26254721Semaste
27254721Semaste#include <sys/param.h>	/* Openserver 5.0.6A and FD_SETSIZE */
28254721Semaste#include <sys/types.h>
29254721Semaste#include <sys/time.h>
30254721Semaste#include <sys/stat.h>
31254721Semaste#include <sys/socket.h>
32254721Semaste#include <sys/un.h>
33254721Semaste
34254721Semaste#ifdef HAVE_NANOSLEEP
35254721Semaste#include <time.h>
36254721Semaste#endif
37254721Semaste#include <unistd.h>
38254721Semaste
39254721Semaste#include <isc/platform.h>
40254721Semaste#include <isc/strerror.h>
41254721Semaste
42254721Semaste#ifdef ISC_PLATFORM_NEEDSYSSELECTH
43254721Semaste#include <sys/select.h>
44254721Semaste#endif
45254721Semaste
46254721Semaste#include "errno2result.h"
47254721Semaste
48254721Semaste/*%
49254721Semaste * There is only one variable in the entropy data structures that is not
50254721Semaste * system independent, but pulling the structure that uses it into this file
51254721Semaste * ultimately means pulling several other independent structures here also to
52254721Semaste * resolve their interdependencies.  Thus only the problem variable's type
53254721Semaste * is defined here.
54254721Semaste */
55254721Semaste#define FILESOURCE_HANDLE_TYPE	int
56254721Semaste
57254721Semastetypedef struct {
58254721Semaste	int	handle;
59254721Semaste	enum	{
60254721Semaste		isc_usocketsource_disconnected,
61254721Semaste		isc_usocketsource_connecting,
62254721Semaste		isc_usocketsource_connected,
63254721Semaste		isc_usocketsource_ndesired,
64254721Semaste		isc_usocketsource_wrote,
65269024Semaste		isc_usocketsource_reading
66254721Semaste	} status;
67254721Semaste	size_t	sz_to_recv;
68254721Semaste} isc_entropyusocketsource_t;
69254721Semaste
70254721Semaste#include "../entropy.c"
71254721Semaste
72269024Semastestatic unsigned int
73254721Semasteget_from_filesource(isc_entropysource_t *source, isc_uint32_t desired) {
74254721Semaste	isc_entropy_t *ent = source->ent;
75254721Semaste	unsigned char buf[128];
76254721Semaste	int fd = source->sources.file.handle;
77254721Semaste	ssize_t n, ndesired;
78254721Semaste	unsigned int added;
79254721Semaste
80254721Semaste	if (source->bad)
81254721Semaste		return (0);
82254721Semaste
83254721Semaste	desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
84254721Semaste
85254721Semaste	added = 0;
86254721Semaste	while (desired > 0) {
87254721Semaste		ndesired = ISC_MIN(desired, sizeof(buf));
88254721Semaste		n = read(fd, buf, ndesired);
89254721Semaste		if (n < 0) {
90254721Semaste			if (errno == EAGAIN || errno == EINTR)
91254721Semaste				goto out;
92254721Semaste			goto err;
93254721Semaste		}
94254721Semaste		if (n == 0)
95254721Semaste			goto err;
96254721Semaste
97254721Semaste		entropypool_adddata(ent, buf, n, n * 8);
98254721Semaste		added += n * 8;
99254721Semaste		desired -= n;
100254721Semaste	}
101254721Semaste	goto out;
102254721Semaste
103254721Semaste err:
104254721Semaste	(void)close(fd);
105254721Semaste	source->sources.file.handle = -1;
106254721Semaste	source->bad = ISC_TRUE;
107254721Semaste
108254721Semaste out:
109254721Semaste	return (added);
110254721Semaste}
111254721Semaste
112254721Semastestatic unsigned int
113254721Semasteget_from_usocketsource(isc_entropysource_t *source, isc_uint32_t desired) {
114254721Semaste	isc_entropy_t *ent = source->ent;
115254721Semaste	unsigned char buf[128];
116254721Semaste	int fd = source->sources.usocket.handle;
117254721Semaste	ssize_t n = 0, ndesired;
118254721Semaste	unsigned int added;
119254721Semaste	size_t sz_to_recv = source->sources.usocket.sz_to_recv;
120254721Semaste
121254721Semaste	if (source->bad)
122254721Semaste		return (0);
123254721Semaste
124254721Semaste	desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
125254721Semaste
126254721Semaste	added = 0;
127254721Semaste	while (desired > 0) {
128254721Semaste		ndesired = ISC_MIN(desired, sizeof(buf));
129254721Semaste eagain_loop:
130254721Semaste
131254721Semaste		switch ( source->sources.usocket.status ) {
132254721Semaste		case isc_usocketsource_ndesired:
133254721Semaste			buf[0] = ndesired;
134254721Semaste			if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) {
135254721Semaste				if (errno == EWOULDBLOCK || errno == EINTR ||
136254721Semaste				    errno == ECONNRESET)
137254721Semaste					goto out;
138269024Semaste				goto err;
139269024Semaste			}
140269024Semaste			INSIST(n == 1);
141269024Semaste			source->sources.usocket.status =
142269024Semaste						isc_usocketsource_wrote;
143269024Semaste			goto eagain_loop;
144269024Semaste
145269024Semaste		case isc_usocketsource_connecting:
146269024Semaste		case isc_usocketsource_connected:
147254721Semaste			buf[0] = 1;
148254721Semaste			buf[1] = ndesired;
149254721Semaste			if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) {
150254721Semaste				if (errno == EWOULDBLOCK || errno == EINTR ||
151254721Semaste				    errno == ECONNRESET)
152254721Semaste					goto out;
153254721Semaste				goto err;
154254721Semaste			}
155254721Semaste			if (n == 1) {
156254721Semaste				source->sources.usocket.status =
157254721Semaste					isc_usocketsource_ndesired;
158254721Semaste				goto eagain_loop;
159254721Semaste			}
160254721Semaste			INSIST(n == 2);
161254721Semaste			source->sources.usocket.status =
162254721Semaste						isc_usocketsource_wrote;
163254721Semaste			/*FALLTHROUGH*/
164254721Semaste
165254721Semaste		case isc_usocketsource_wrote:
166254721Semaste			if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) {
167254721Semaste				if (errno == EAGAIN) {
168254721Semaste					/*
169254721Semaste					 * The problem of EAGAIN (try again
170254721Semaste					 * later) is a major issue on HP-UX.
171254721Semaste					 * Solaris actually tries the recvfrom
172254721Semaste					 * call again, while HP-UX just dies.
173254721Semaste					 * This code is an attempt to let the
174254721Semaste					 * entropy pool fill back up (at least
175254721Semaste					 * that's what I think the problem is.)
176254721Semaste					 * We go to eagain_loop because if we
177254721Semaste					 * just "break", then the "desired"
178254721Semaste					 * amount gets borked.
179254721Semaste					 */
180254721Semaste#ifdef HAVE_NANOSLEEP
181254721Semaste					struct timespec ts;
182254721Semaste
183254721Semaste					ts.tv_sec = 0;
184254721Semaste					ts.tv_nsec = 1000000;
185254721Semaste					nanosleep(&ts, NULL);
186254721Semaste#else
187254721Semaste					usleep(1000);
188254721Semaste#endif
189254721Semaste					goto eagain_loop;
190254721Semaste				}
191254721Semaste				if (errno == EWOULDBLOCK || errno == EINTR)
192254721Semaste					goto out;
193254721Semaste				goto err;
194254721Semaste			}
195254721Semaste			source->sources.usocket.status =
196254721Semaste					isc_usocketsource_reading;
197254721Semaste			sz_to_recv = buf[0];
198254721Semaste			source->sources.usocket.sz_to_recv = sz_to_recv;
199254721Semaste			if (sz_to_recv > sizeof(buf))
200254721Semaste				goto err;
201254721Semaste			/*FALLTHROUGH*/
202254721Semaste
203254721Semaste		case isc_usocketsource_reading:
204254721Semaste			if (sz_to_recv != 0U) {
205254721Semaste				n = recv(fd, buf, sz_to_recv, 0);
206254721Semaste				if (n < 0) {
207254721Semaste					if (errno == EWOULDBLOCK ||
208254721Semaste					    errno == EINTR)
209254721Semaste						goto out;
210254721Semaste					goto err;
211254721Semaste				}
212254721Semaste			} else
213254721Semaste				n = 0;
214254721Semaste			break;
215254721Semaste
216254721Semaste		default:
217254721Semaste			goto err;
218254721Semaste		}
219254721Semaste
220254721Semaste		if ((size_t)n != sz_to_recv)
221254721Semaste			source->sources.usocket.sz_to_recv -= n;
222254721Semaste		else
223254721Semaste			source->sources.usocket.status =
224254721Semaste				isc_usocketsource_connected;
225254721Semaste
226254721Semaste		if (n == 0)
227254721Semaste			goto out;
228254721Semaste
229254721Semaste		entropypool_adddata(ent, buf, n, n * 8);
230254721Semaste		added += n * 8;
231254721Semaste		desired -= n;
232254721Semaste	}
233254721Semaste	goto out;
234254721Semaste
235254721Semaste err:
236254721Semaste	close(fd);
237254721Semaste	source->bad = ISC_TRUE;
238254721Semaste	source->sources.usocket.status = isc_usocketsource_disconnected;
239254721Semaste	source->sources.usocket.handle = -1;
240254721Semaste
241254721Semaste out:
242254721Semaste	return (added);
243254721Semaste}
244254721Semaste
245254721Semaste/*
246254721Semaste * Poll each source, trying to get data from it to stuff into the entropy
247254721Semaste * pool.
248254721Semaste */
249254721Semastestatic void
250254721Semastefillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
251254721Semaste	unsigned int added;
252254721Semaste	unsigned int remaining;
253254721Semaste	unsigned int needed;
254254721Semaste	unsigned int nsource;
255254721Semaste	isc_entropysource_t *source;
256254721Semaste
257254721Semaste	REQUIRE(VALID_ENTROPY(ent));
258254721Semaste
259254721Semaste	needed = desired;
260254721Semaste
261254721Semaste	/*
262254721Semaste	 * This logic is a little strange, so an explanation is in order.
263254721Semaste	 *
264254721Semaste	 * If needed is 0, it means we are being asked to "fill to whatever
265254721Semaste	 * we think is best."  This means that if we have at least a
266254721Semaste	 * partially full pool (say, > 1/4th of the pool) we probably don't
267254721Semaste	 * need to add anything.
268254721Semaste	 *
269254721Semaste	 * Also, we will check to see if the "pseudo" count is too high.
270254721Semaste	 * If it is, try to mix in better data.  Too high is currently
271254721Semaste	 * defined as 1/4th of the pool.
272254721Semaste	 *
273254721Semaste	 * Next, if we are asked to add a specific bit of entropy, make
274254721Semaste	 * certain that we will do so.  Clamp how much we try to add to
275254721Semaste	 * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
276254721Semaste	 *
277254721Semaste	 * Note that if we are in a blocking mode, we will only try to
278254721Semaste	 * get as much data as we need, not as much as we might want
279254721Semaste	 * to build up.
280254721Semaste	 */
281254721Semaste	if (needed == 0) {
282254721Semaste		REQUIRE(!blocking);
283254721Semaste
284254721Semaste		if ((ent->pool.entropy >= RND_POOLBITS / 4)
285254721Semaste		    && (ent->pool.pseudo <= RND_POOLBITS / 4))
286254721Semaste			return;
287254721Semaste
288254721Semaste		needed = THRESHOLD_BITS * 4;
289254721Semaste	} else {
290254721Semaste		needed = ISC_MAX(needed, THRESHOLD_BITS);
291254721Semaste		needed = ISC_MIN(needed, RND_POOLBITS);
292254721Semaste	}
293254721Semaste
294254721Semaste	/*
295254721Semaste	 * In any case, clamp how much we need to how much we can add.
296254721Semaste	 */
297263363Semaste	needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
298263363Semaste
299263363Semaste	/*
300254721Semaste	 * But wait!  If we're not yet initialized, we need at least
301254721Semaste	 *	THRESHOLD_BITS
302254721Semaste	 * of randomness.
303263363Semaste	 */
304263363Semaste	if (ent->initialized < THRESHOLD_BITS)
305263363Semaste		needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
306263363Semaste
307263363Semaste	/*
308263363Semaste	 * Poll each file source to see if we can read anything useful from
309254721Semaste	 * it.  XXXMLG When where are multiple sources, we should keep a
310254721Semaste	 * record of which one we last used so we can start from it (or the
311254721Semaste	 * next one) to avoid letting some sources build up entropy while
312254721Semaste	 * others are always drained.
313254721Semaste	 */
314254721Semaste
315254721Semaste	added = 0;
316254721Semaste	remaining = needed;
317254721Semaste	if (ent->nextsource == NULL) {
318254721Semaste		ent->nextsource = ISC_LIST_HEAD(ent->sources);
319254721Semaste		if (ent->nextsource == NULL)
320254721Semaste			return;
321254721Semaste	}
322254721Semaste	source = ent->nextsource;
323254721Semaste again_file:
324254721Semaste	for (nsource = 0; nsource < ent->nsources; nsource++) {
325254721Semaste		unsigned int got;
326254721Semaste
327254721Semaste		if (remaining == 0)
328254721Semaste			break;
329254721Semaste
330254721Semaste		got = 0;
331254721Semaste
332254721Semaste		switch ( source->type ) {
333254721Semaste		case ENTROPY_SOURCETYPE_FILE:
334254721Semaste			got = get_from_filesource(source, remaining);
335254721Semaste			break;
336254721Semaste
337254721Semaste		case ENTROPY_SOURCETYPE_USOCKET:
338254721Semaste			got = get_from_usocketsource(source, remaining);
339254721Semaste			break;
340254721Semaste		}
341254721Semaste
342254721Semaste		added += got;
343254721Semaste
344254721Semaste		remaining -= ISC_MIN(remaining, got);
345254721Semaste
346254721Semaste		source = ISC_LIST_NEXT(source, link);
347254721Semaste		if (source == NULL)
348254721Semaste			source = ISC_LIST_HEAD(ent->sources);
349254721Semaste	}
350254721Semaste	ent->nextsource = source;
351254721Semaste
352254721Semaste	if (blocking && remaining != 0) {
353254721Semaste		int fds;
354254721Semaste
355254721Semaste		fds = wait_for_sources(ent);
356254721Semaste		if (fds > 0)
357254721Semaste			goto again_file;
358254721Semaste	}
359254721Semaste
360254721Semaste	/*
361254721Semaste	 * Here, if there are bits remaining to be had and we can block,
362254721Semaste	 * check to see if we have a callback source.  If so, call them.
363254721Semaste	 */
364254721Semaste	source = ISC_LIST_HEAD(ent->sources);
365254721Semaste	while ((remaining != 0) && (source != NULL)) {
366254721Semaste		unsigned int got;
367254721Semaste
368254721Semaste		got = 0;
369254721Semaste
370254721Semaste		if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
371254721Semaste			got = get_from_callback(source, remaining, blocking);
372254721Semaste
373254721Semaste		added += got;
374254721Semaste		remaining -= ISC_MIN(remaining, got);
375254721Semaste
376254721Semaste		if (added >= needed)
377254721Semaste			break;
378254721Semaste
379254721Semaste		source = ISC_LIST_NEXT(source, link);
380254721Semaste	}
381254721Semaste
382254721Semaste	/*
383254721Semaste	 * Mark as initialized if we've added enough data.
384254721Semaste	 */
385254721Semaste	if (ent->initialized < THRESHOLD_BITS)
386254721Semaste		ent->initialized += added;
387254721Semaste}
388254721Semaste
389254721Semastestatic int
390254721Semastewait_for_sources(isc_entropy_t *ent) {
391254721Semaste	isc_entropysource_t *source;
392254721Semaste	int maxfd, fd;
393254721Semaste	int cc;
394254721Semaste	fd_set reads;
395254721Semaste	fd_set writes;
396254721Semaste
397254721Semaste	maxfd = -1;
398254721Semaste	FD_ZERO(&reads);
399254721Semaste	FD_ZERO(&writes);
400254721Semaste
401254721Semaste	source = ISC_LIST_HEAD(ent->sources);
402254721Semaste	while (source != NULL) {
403254721Semaste		if (source->type == ENTROPY_SOURCETYPE_FILE) {
404254721Semaste			fd = source->sources.file.handle;
405254721Semaste			if (fd >= 0) {
406254721Semaste				maxfd = ISC_MAX(maxfd, fd);
407254721Semaste				FD_SET(fd, &reads);
408254721Semaste			}
409254721Semaste		}
410254721Semaste		if (source->type == ENTROPY_SOURCETYPE_USOCKET) {
411254721Semaste			fd = source->sources.usocket.handle;
412254721Semaste			if (fd >= 0) {
413254721Semaste				switch (source->sources.usocket.status) {
414254721Semaste				case isc_usocketsource_disconnected:
415254721Semaste					break;
416254721Semaste				case isc_usocketsource_connecting:
417254721Semaste				case isc_usocketsource_connected:
418254721Semaste				case isc_usocketsource_ndesired:
419254721Semaste					maxfd = ISC_MAX(maxfd, fd);
420254721Semaste					FD_SET(fd, &writes);
421254721Semaste					break;
422254721Semaste				case isc_usocketsource_wrote:
423254721Semaste				case isc_usocketsource_reading:
424254721Semaste					maxfd = ISC_MAX(maxfd, fd);
425254721Semaste					FD_SET(fd, &reads);
426254721Semaste					break;
427254721Semaste				}
428254721Semaste			}
429254721Semaste		}
430254721Semaste		source = ISC_LIST_NEXT(source, link);
431254721Semaste	}
432254721Semaste
433254721Semaste	if (maxfd < 0)
434254721Semaste		return (-1);
435254721Semaste
436254721Semaste	cc = select(maxfd + 1, &reads, &writes, NULL, NULL);
437254721Semaste	if (cc < 0)
438254721Semaste		return (-1);
439254721Semaste
440254721Semaste	return (cc);
441254721Semaste}
442254721Semaste
443254721Semastestatic void
444254721Semastedestroyfilesource(isc_entropyfilesource_t *source) {
445254721Semaste	(void)close(source->handle);
446254721Semaste}
447254721Semaste
448254721Semastestatic void
449254721Semastedestroyusocketsource(isc_entropyusocketsource_t *source) {
450254721Semaste	close(source->handle);
451254721Semaste}
452254721Semaste
453254721Semaste/*
454254721Semaste * Make a fd non-blocking
455254721Semaste */
456254721Semastestatic isc_result_t
457254721Semastemake_nonblock(int fd) {
458254721Semaste	int ret;
459254721Semaste	int flags;
460254721Semaste	char strbuf[ISC_STRERRORSIZE];
461254721Semaste#ifdef USE_FIONBIO_IOCTL
462254721Semaste	int on = 1;
463254721Semaste
464254721Semaste	ret = ioctl(fd, FIONBIO, (char *)&on);
465254721Semaste#else
466254721Semaste	flags = fcntl(fd, F_GETFL, 0);
467254721Semaste	flags |= PORT_NONBLOCK;
468254721Semaste	ret = fcntl(fd, F_SETFL, flags);
469254721Semaste#endif
470254721Semaste
471254721Semaste	if (ret == -1) {
472254721Semaste		isc__strerror(errno, strbuf, sizeof(strbuf));
473254721Semaste		UNEXPECTED_ERROR(__FILE__, __LINE__,
474254721Semaste#ifdef USE_FIONBIO_IOCTL
475254721Semaste				 "ioctl(%d, FIONBIO, &on): %s", fd,
476254721Semaste#else
477254721Semaste				 "fcntl(%d, F_SETFL, %d): %s", fd, flags,
478254721Semaste#endif
479254721Semaste				 strbuf);
480254721Semaste
481254721Semaste		return (ISC_R_UNEXPECTED);
482254721Semaste	}
483254721Semaste
484254721Semaste	return (ISC_R_SUCCESS);
485254721Semaste}
486254721Semaste
487254721Semasteisc_result_t
488254721Semasteisc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
489254721Semaste	int fd;
490254721Semaste	struct stat _stat;
491254721Semaste	isc_boolean_t is_usocket = ISC_FALSE;
492254721Semaste	isc_boolean_t is_connected = ISC_FALSE;
493254721Semaste	isc_result_t ret;
494254721Semaste	isc_entropysource_t *source;
495254721Semaste
496254721Semaste	REQUIRE(VALID_ENTROPY(ent));
497254721Semaste	REQUIRE(fname != NULL);
498254721Semaste
499254721Semaste	LOCK(&ent->lock);
500254721Semaste
501254721Semaste	if (stat(fname, &_stat) < 0) {
502254721Semaste		ret = isc__errno2result(errno);
503254721Semaste		goto errout;
504254721Semaste	}
505254721Semaste	/*
506254721Semaste	 * Solaris 2.5.1 does not have support for sockets (S_IFSOCK),
507254721Semaste	 * but it does return type S_IFIFO (the OS believes that
508254721Semaste	 * the socket is a fifo).  This may be an issue if we tell
509254721Semaste	 * the program to look at an actual FIFO as its source of
510254721Semaste	 * entropy.
511263367Semaste	 */
512263367Semaste#if defined(S_ISSOCK)
513263367Semaste	if (S_ISSOCK(_stat.st_mode))
514263367Semaste		is_usocket = ISC_TRUE;
515263367Semaste#endif
516263367Semaste#if defined(S_ISFIFO) && defined(sun)
517263367Semaste	if (S_ISFIFO(_stat.st_mode))
518263367Semaste		is_usocket = ISC_TRUE;
519263367Semaste#endif
520263367Semaste	if (is_usocket)
521263367Semaste		fd = socket(PF_UNIX, SOCK_STREAM, 0);
522263367Semaste	else
523263367Semaste		fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0);
524254721Semaste
525254721Semaste	if (fd < 0) {
526254721Semaste		ret = isc__errno2result(errno);
527254721Semaste		goto errout;
528254721Semaste	}
529254721Semaste
530254721Semaste	ret = make_nonblock(fd);
531254721Semaste	if (ret != ISC_R_SUCCESS)
532254721Semaste		goto closefd;
533254721Semaste
534254721Semaste	if (is_usocket) {
535254721Semaste		struct sockaddr_un sname;
536254721Semaste
537254721Semaste		memset(&sname, 0, sizeof(sname));
538263367Semaste		sname.sun_family = AF_UNIX;
539263367Semaste		strncpy(sname.sun_path, fname, sizeof(sname.sun_path));
540263367Semaste		sname.sun_path[sizeof(sname.sun_path)-1] = '0';
541263367Semaste#ifdef ISC_PLATFORM_HAVESALEN
542263367Semaste#if !defined(SUN_LEN)
543263367Semaste#define SUN_LEN(su) \
544263367Semaste	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
545263367Semaste#endif
546263367Semaste		sname.sun_len = SUN_LEN(&sname);
547263367Semaste#endif
548263367Semaste
549263367Semaste		if (connect(fd, (struct sockaddr *) &sname,
550263367Semaste			    sizeof(struct sockaddr_un)) < 0) {
551263367Semaste			if (errno != EINPROGRESS) {
552263367Semaste				ret = isc__errno2result(errno);
553263367Semaste				goto closefd;
554263367Semaste			}
555263367Semaste		} else
556263367Semaste			is_connected = ISC_TRUE;
557263367Semaste	}
558254721Semaste
559254721Semaste	source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
560254721Semaste	if (source == NULL) {
561254721Semaste		ret = ISC_R_NOMEMORY;
562254721Semaste		goto closefd;
563254721Semaste	}
564254721Semaste
565254721Semaste	/*
566254721Semaste	 * From here down, no failures can occur.
567254721Semaste	 */
568254721Semaste	source->magic = SOURCE_MAGIC;
569254721Semaste	source->ent = ent;
570254721Semaste	source->total = 0;
571254721Semaste	source->bad = ISC_FALSE;
572254721Semaste	memset(source->name, 0, sizeof(source->name));
573254721Semaste	ISC_LINK_INIT(source, link);
574254721Semaste	if (is_usocket) {
575254721Semaste		source->sources.usocket.handle = fd;
576254721Semaste		if (is_connected)
577254721Semaste			source->sources.usocket.status =
578254721Semaste					isc_usocketsource_connected;
579254721Semaste		else
580254721Semaste			source->sources.usocket.status =
581254721Semaste					isc_usocketsource_connecting;
582254721Semaste		source->sources.usocket.sz_to_recv = 0;
583254721Semaste		source->type = ENTROPY_SOURCETYPE_USOCKET;
584254721Semaste	} else {
585254721Semaste		source->sources.file.handle = fd;
586254721Semaste		source->type = ENTROPY_SOURCETYPE_FILE;
587254721Semaste	}
588254721Semaste
589254721Semaste	/*
590254721Semaste	 * Hook it into the entropy system.
591254721Semaste	 */
592254721Semaste	ISC_LIST_APPEND(ent->sources, source, link);
593254721Semaste	ent->nsources++;
594254721Semaste
595254721Semaste	UNLOCK(&ent->lock);
596254721Semaste	return (ISC_R_SUCCESS);
597254721Semaste
598254721Semaste closefd:
599254721Semaste	(void)close(fd);
600254721Semaste
601254721Semaste errout:
602254721Semaste	UNLOCK(&ent->lock);
603254721Semaste
604254721Semaste	return (ret);
605254721Semaste}
606254721Semaste