Blame lib/isc/unix/entropy.c

Packit Service ae04f2
/*
Packit Service ae04f2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
Packit Service ae04f2
 *
Packit Service ae04f2
 * This Source Code Form is subject to the terms of the Mozilla Public
Packit Service ae04f2
 * License, v. 2.0. If a copy of the MPL was not distributed with this
Packit Service ae04f2
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
Packit Service ae04f2
 *
Packit Service ae04f2
 * See the COPYRIGHT file distributed with this work for additional
Packit Service ae04f2
 * information regarding copyright ownership.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
/* \file unix/entropy.c
Packit Service ae04f2
 * \brief
Packit Service ae04f2
 * This is the system dependent part of the ISC entropy API.
Packit Service ae04f2
 */
Packit Service ae04f2
Packit Service ae04f2
#include <config.h>
Packit Service ae04f2
Packit Service ae04f2
#include <stdbool.h>
Packit Service ae04f2
Packit Service ae04f2
#include <sys/param.h>	/* Openserver 5.0.6A and FD_SETSIZE */
Packit Service ae04f2
#include <sys/types.h>
Packit Service ae04f2
#include <sys/time.h>
Packit Service ae04f2
#include <sys/stat.h>
Packit Service ae04f2
#include <sys/socket.h>
Packit Service ae04f2
#include <sys/un.h>
Packit Service ae04f2
Packit Service ae04f2
#ifdef HAVE_NANOSLEEP
Packit Service ae04f2
#include <time.h>
Packit Service ae04f2
#endif
Packit Service ae04f2
#include <unistd.h>
Packit Service ae04f2
Packit Service ae04f2
#include <isc/platform.h>
Packit Service ae04f2
#include <isc/print.h>
Packit Service ae04f2
#include <isc/strerror.h>
Packit Service ae04f2
#include <isc/string.h>
Packit Service ae04f2
Packit Service ae04f2
#ifdef ISC_PLATFORM_NEEDSYSSELECTH
Packit Service ae04f2
#include <sys/select.h>
Packit Service ae04f2
#endif
Packit Service ae04f2
Packit Service ae04f2
#include "errno2result.h"
Packit Service ae04f2
Packit Service ae04f2
/*%
Packit Service ae04f2
 * There is only one variable in the entropy data structures that is not
Packit Service ae04f2
 * system independent, but pulling the structure that uses it into this file
Packit Service ae04f2
 * ultimately means pulling several other independent structures here also to
Packit Service ae04f2
 * resolve their interdependencies.  Thus only the problem variable's type
Packit Service ae04f2
 * is defined here.
Packit Service ae04f2
 */
Packit Service ae04f2
#define FILESOURCE_HANDLE_TYPE	int
Packit Service ae04f2
Packit Service ae04f2
typedef struct {
Packit Service ae04f2
	int	handle;
Packit Service ae04f2
	enum	{
Packit Service ae04f2
		isc_usocketsource_disconnected,
Packit Service ae04f2
		isc_usocketsource_connecting,
Packit Service ae04f2
		isc_usocketsource_connected,
Packit Service ae04f2
		isc_usocketsource_ndesired,
Packit Service ae04f2
		isc_usocketsource_wrote,
Packit Service ae04f2
		isc_usocketsource_reading
Packit Service ae04f2
	} status;
Packit Service ae04f2
	size_t	sz_to_recv;
Packit Service ae04f2
} isc_entropyusocketsource_t;
Packit Service ae04f2
Packit Service ae04f2
#include "../entropy.c"
Packit Service ae04f2
Packit Service ae04f2
static unsigned int
Packit Service ae04f2
get_from_filesource(isc_entropysource_t *source, uint32_t desired) {
Packit Service ae04f2
	isc_entropy_t *ent = source->ent;
Packit Service ae04f2
	unsigned char buf[128];
Packit Service ae04f2
	int fd = source->sources.file.handle;
Packit Service ae04f2
	ssize_t n, ndesired;
Packit Service ae04f2
	unsigned int added;
Packit Service ae04f2
Packit Service ae04f2
	if (source->bad)
Packit Service ae04f2
		return (0);
Packit Service ae04f2
Packit Service ae04f2
	desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
Packit Service ae04f2
Packit Service ae04f2
	added = 0;
Packit Service ae04f2
	while (desired > 0) {
Packit Service ae04f2
		ndesired = ISC_MIN(desired, sizeof(buf));
Packit Service ae04f2
		n = read(fd, buf, ndesired);
Packit Service ae04f2
		if (n < 0) {
Packit Service ae04f2
			if (errno == EAGAIN || errno == EINTR)
Packit Service ae04f2
				goto out;
Packit Service ae04f2
			goto err;
Packit Service ae04f2
		}
Packit Service ae04f2
		if (n == 0)
Packit Service ae04f2
			goto err;
Packit Service ae04f2
Packit Service ae04f2
		entropypool_adddata(ent, buf, n, n * 8);
Packit Service ae04f2
		added += n * 8;
Packit Service ae04f2
		desired -= n;
Packit Service ae04f2
	}
Packit Service ae04f2
	goto out;
Packit Service ae04f2
Packit Service ae04f2
 err:
Packit Service ae04f2
	(void)close(fd);
Packit Service ae04f2
	source->sources.file.handle = -1;
Packit Service ae04f2
	source->bad = true;
Packit Service ae04f2
Packit Service ae04f2
 out:
Packit Service ae04f2
	return (added);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static unsigned int
Packit Service ae04f2
get_from_usocketsource(isc_entropysource_t *source, uint32_t desired) {
Packit Service ae04f2
	isc_entropy_t *ent = source->ent;
Packit Service ae04f2
	unsigned char buf[128];
Packit Service ae04f2
	int fd = source->sources.usocket.handle;
Packit Service ae04f2
	ssize_t n = 0, ndesired;
Packit Service ae04f2
	unsigned int added;
Packit Service ae04f2
	size_t sz_to_recv = source->sources.usocket.sz_to_recv;
Packit Service ae04f2
Packit Service ae04f2
	if (source->bad)
Packit Service ae04f2
		return (0);
Packit Service ae04f2
Packit Service ae04f2
	desired = desired / 8 + (((desired & 0x07) > 0) ? 1 : 0);
Packit Service ae04f2
Packit Service ae04f2
	added = 0;
Packit Service ae04f2
	while (desired > 0) {
Packit Service ae04f2
		ndesired = ISC_MIN(desired, sizeof(buf));
Packit Service ae04f2
 eagain_loop:
Packit Service ae04f2
Packit Service ae04f2
		switch ( source->sources.usocket.status ) {
Packit Service ae04f2
		case isc_usocketsource_ndesired:
Packit Service ae04f2
			buf[0] = ndesired;
Packit Service ae04f2
			if ((n = sendto(fd, buf, 1, 0, NULL, 0)) < 0) {
Packit Service ae04f2
				if (errno == EWOULDBLOCK || errno == EINTR ||
Packit Service ae04f2
				    errno == ECONNRESET)
Packit Service ae04f2
					goto out;
Packit Service ae04f2
				goto err;
Packit Service ae04f2
			}
Packit Service ae04f2
			INSIST(n == 1);
Packit Service ae04f2
			source->sources.usocket.status =
Packit Service ae04f2
						isc_usocketsource_wrote;
Packit Service ae04f2
			goto eagain_loop;
Packit Service ae04f2
Packit Service ae04f2
		case isc_usocketsource_connecting:
Packit Service ae04f2
		case isc_usocketsource_connected:
Packit Service ae04f2
			buf[0] = 1;
Packit Service ae04f2
			buf[1] = ndesired;
Packit Service ae04f2
			if ((n = sendto(fd, buf, 2, 0, NULL, 0)) < 0) {
Packit Service ae04f2
				if (errno == EWOULDBLOCK || errno == EINTR ||
Packit Service ae04f2
				    errno == ECONNRESET)
Packit Service ae04f2
					goto out;
Packit Service ae04f2
				goto err;
Packit Service ae04f2
			}
Packit Service ae04f2
			if (n == 1) {
Packit Service ae04f2
				source->sources.usocket.status =
Packit Service ae04f2
					isc_usocketsource_ndesired;
Packit Service ae04f2
				goto eagain_loop;
Packit Service ae04f2
			}
Packit Service ae04f2
			INSIST(n == 2);
Packit Service ae04f2
			source->sources.usocket.status =
Packit Service ae04f2
						isc_usocketsource_wrote;
Packit Service ae04f2
			/* FALLTHROUGH */
Packit Service ae04f2
Packit Service ae04f2
		case isc_usocketsource_wrote:
Packit Service ae04f2
			if (recvfrom(fd, buf, 1, 0, NULL, NULL) != 1) {
Packit Service ae04f2
				if (errno == EAGAIN) {
Packit Service ae04f2
					/*
Packit Service ae04f2
					 * The problem of EAGAIN (try again
Packit Service ae04f2
					 * later) is a major issue on HP-UX.
Packit Service ae04f2
					 * Solaris actually tries the recvfrom
Packit Service ae04f2
					 * call again, while HP-UX just dies.
Packit Service ae04f2
					 * This code is an attempt to let the
Packit Service ae04f2
					 * entropy pool fill back up (at least
Packit Service ae04f2
					 * that's what I think the problem is.)
Packit Service ae04f2
					 * We go to eagain_loop because if we
Packit Service ae04f2
					 * just "break", then the "desired"
Packit Service ae04f2
					 * amount gets borked.
Packit Service ae04f2
					 */
Packit Service ae04f2
#ifdef HAVE_NANOSLEEP
Packit Service ae04f2
					struct timespec ts;
Packit Service ae04f2
Packit Service ae04f2
					ts.tv_sec = 0;
Packit Service ae04f2
					ts.tv_nsec = 1000000;
Packit Service ae04f2
					nanosleep(&ts, NULL);
Packit Service ae04f2
#else
Packit Service ae04f2
					usleep(1000);
Packit Service ae04f2
#endif
Packit Service ae04f2
					goto eagain_loop;
Packit Service ae04f2
				}
Packit Service ae04f2
				if (errno == EWOULDBLOCK || errno == EINTR)
Packit Service ae04f2
					goto out;
Packit Service ae04f2
				goto err;
Packit Service ae04f2
			}
Packit Service ae04f2
			source->sources.usocket.status =
Packit Service ae04f2
					isc_usocketsource_reading;
Packit Service ae04f2
			sz_to_recv = buf[0];
Packit Service ae04f2
			source->sources.usocket.sz_to_recv = sz_to_recv;
Packit Service ae04f2
			if (sz_to_recv > sizeof(buf))
Packit Service ae04f2
				goto err;
Packit Service ae04f2
			/* FALLTHROUGH */
Packit Service ae04f2
Packit Service ae04f2
		case isc_usocketsource_reading:
Packit Service ae04f2
			if (sz_to_recv != 0U) {
Packit Service ae04f2
				n = recv(fd, buf, sz_to_recv, 0);
Packit Service ae04f2
				if (n < 0) {
Packit Service ae04f2
					if (errno == EWOULDBLOCK ||
Packit Service ae04f2
					    errno == EINTR)
Packit Service ae04f2
						goto out;
Packit Service ae04f2
					goto err;
Packit Service ae04f2
				}
Packit Service ae04f2
			} else
Packit Service ae04f2
				n = 0;
Packit Service ae04f2
			break;
Packit Service ae04f2
Packit Service ae04f2
		default:
Packit Service ae04f2
			goto err;
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		if ((size_t)n != sz_to_recv)
Packit Service ae04f2
			source->sources.usocket.sz_to_recv -= n;
Packit Service ae04f2
		else
Packit Service ae04f2
			source->sources.usocket.status =
Packit Service ae04f2
				isc_usocketsource_connected;
Packit Service ae04f2
Packit Service ae04f2
		if (n == 0)
Packit Service ae04f2
			goto out;
Packit Service ae04f2
Packit Service ae04f2
		entropypool_adddata(ent, buf, n, n * 8);
Packit Service ae04f2
		added += n * 8;
Packit Service ae04f2
		desired -= n;
Packit Service ae04f2
	}
Packit Service ae04f2
	goto out;
Packit Service ae04f2
Packit Service ae04f2
 err:
Packit Service ae04f2
	close(fd);
Packit Service ae04f2
	source->bad = true;
Packit Service ae04f2
	source->sources.usocket.status = isc_usocketsource_disconnected;
Packit Service ae04f2
	source->sources.usocket.handle = -1;
Packit Service ae04f2
Packit Service ae04f2
 out:
Packit Service ae04f2
	return (added);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Poll each source, trying to get data from it to stuff into the entropy
Packit Service ae04f2
 * pool.
Packit Service ae04f2
 */
Packit Service ae04f2
static void
Packit Service ae04f2
fillpool(isc_entropy_t *ent, unsigned int desired, bool blocking) {
Packit Service ae04f2
	unsigned int added;
Packit Service ae04f2
	unsigned int remaining;
Packit Service ae04f2
	unsigned int needed;
Packit Service ae04f2
	unsigned int nsource;
Packit Service ae04f2
	isc_entropysource_t *source;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(VALID_ENTROPY(ent));
Packit Service ae04f2
Packit Service ae04f2
	needed = desired;
Packit Service ae04f2
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * This logic is a little strange, so an explanation is in order.
Packit Service ae04f2
	 *
Packit Service ae04f2
	 * If needed is 0, it means we are being asked to "fill to whatever
Packit Service ae04f2
	 * we think is best."  This means that if we have at least a
Packit Service ae04f2
	 * partially full pool (say, > 1/4th of the pool) we probably don't
Packit Service ae04f2
	 * need to add anything.
Packit Service ae04f2
	 *
Packit Service ae04f2
	 * Also, we will check to see if the "pseudo" count is too high.
Packit Service ae04f2
	 * If it is, try to mix in better data.  Too high is currently
Packit Service ae04f2
	 * defined as 1/4th of the pool.
Packit Service ae04f2
	 *
Packit Service ae04f2
	 * Next, if we are asked to add a specific bit of entropy, make
Packit Service ae04f2
	 * certain that we will do so.  Clamp how much we try to add to
Packit Service ae04f2
	 * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
Packit Service ae04f2
	 *
Packit Service ae04f2
	 * Note that if we are in a blocking mode, we will only try to
Packit Service ae04f2
	 * get as much data as we need, not as much as we might want
Packit Service ae04f2
	 * to build up.
Packit Service ae04f2
	 */
Packit Service ae04f2
	if (needed == 0) {
Packit Service ae04f2
		REQUIRE(!blocking);
Packit Service ae04f2
Packit Service ae04f2
		if ((ent->pool.entropy >= RND_POOLBITS / 4)
Packit Service ae04f2
		    && (ent->pool.pseudo <= RND_POOLBITS / 4))
Packit Service ae04f2
			return;
Packit Service ae04f2
Packit Service ae04f2
		needed = THRESHOLD_BITS * 4;
Packit Service ae04f2
	} else {
Packit Service ae04f2
		needed = ISC_MAX(needed, THRESHOLD_BITS);
Packit Service ae04f2
		needed = ISC_MIN(needed, RND_POOLBITS);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * In any case, clamp how much we need to how much we can add.
Packit Service ae04f2
	 */
Packit Service ae04f2
	needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);
Packit Service ae04f2
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * But wait!  If we're not yet initialized, we need at least
Packit Service ae04f2
	 *	THRESHOLD_BITS
Packit Service ae04f2
	 * of randomness.
Packit Service ae04f2
	 */
Packit Service ae04f2
	if (ent->initialized < THRESHOLD_BITS)
Packit Service ae04f2
		needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);
Packit Service ae04f2
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * Poll each file source to see if we can read anything useful from
Packit Service ae04f2
	 * it.  XXXMLG When where are multiple sources, we should keep a
Packit Service ae04f2
	 * record of which one we last used so we can start from it (or the
Packit Service ae04f2
	 * next one) to avoid letting some sources build up entropy while
Packit Service ae04f2
	 * others are always drained.
Packit Service ae04f2
	 */
Packit Service ae04f2
Packit Service ae04f2
	added = 0;
Packit Service ae04f2
	remaining = needed;
Packit Service ae04f2
	if (ent->nextsource == NULL) {
Packit Service ae04f2
		ent->nextsource = ISC_LIST_HEAD(ent->sources);
Packit Service ae04f2
		if (ent->nextsource == NULL)
Packit Service ae04f2
			return;
Packit Service ae04f2
	}
Packit Service ae04f2
	source = ent->nextsource;
Packit Service ae04f2
 again_file:
Packit Service ae04f2
	for (nsource = 0; nsource < ent->nsources; nsource++) {
Packit Service ae04f2
		unsigned int got;
Packit Service ae04f2
Packit Service ae04f2
		if (remaining == 0)
Packit Service ae04f2
			break;
Packit Service ae04f2
Packit Service ae04f2
		got = 0;
Packit Service ae04f2
Packit Service ae04f2
		switch ( source->type ) {
Packit Service ae04f2
		case ENTROPY_SOURCETYPE_FILE:
Packit Service ae04f2
			got = get_from_filesource(source, remaining);
Packit Service ae04f2
			break;
Packit Service ae04f2
Packit Service ae04f2
		case ENTROPY_SOURCETYPE_USOCKET:
Packit Service ae04f2
			got = get_from_usocketsource(source, remaining);
Packit Service ae04f2
			break;
Packit Service ae04f2
		}
Packit Service ae04f2
Packit Service ae04f2
		added += got;
Packit Service ae04f2
Packit Service ae04f2
		remaining -= ISC_MIN(remaining, got);
Packit Service ae04f2
Packit Service ae04f2
		source = ISC_LIST_NEXT(source, link);
Packit Service ae04f2
		if (source == NULL)
Packit Service ae04f2
			source = ISC_LIST_HEAD(ent->sources);
Packit Service ae04f2
	}
Packit Service ae04f2
	ent->nextsource = source;
Packit Service ae04f2
Packit Service ae04f2
	if (blocking && remaining != 0) {
Packit Service ae04f2
		int fds;
Packit Service ae04f2
Packit Service ae04f2
		fds = wait_for_sources(ent);
Packit Service ae04f2
		if (fds > 0)
Packit Service ae04f2
			goto again_file;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * Here, if there are bits remaining to be had and we can block,
Packit Service ae04f2
	 * check to see if we have a callback source.  If so, call them.
Packit Service ae04f2
	 */
Packit Service ae04f2
	source = ISC_LIST_HEAD(ent->sources);
Packit Service ae04f2
	while ((remaining != 0) && (source != NULL)) {
Packit Service ae04f2
		unsigned int got;
Packit Service ae04f2
Packit Service ae04f2
		got = 0;
Packit Service ae04f2
Packit Service ae04f2
		if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
Packit Service ae04f2
			got = get_from_callback(source, remaining, blocking);
Packit Service ae04f2
Packit Service ae04f2
		added += got;
Packit Service ae04f2
		remaining -= ISC_MIN(remaining, got);
Packit Service ae04f2
Packit Service ae04f2
		if (added >= needed)
Packit Service ae04f2
			break;
Packit Service ae04f2
Packit Service ae04f2
		source = ISC_LIST_NEXT(source, link);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * Mark as initialized if we've added enough data.
Packit Service ae04f2
	 */
Packit Service ae04f2
	if (ent->initialized < THRESHOLD_BITS)
Packit Service ae04f2
		ent->initialized += added;
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static int
Packit Service ae04f2
wait_for_sources(isc_entropy_t *ent) {
Packit Service ae04f2
	isc_entropysource_t *source;
Packit Service ae04f2
	int maxfd, fd;
Packit Service ae04f2
	int cc;
Packit Service ae04f2
	fd_set reads;
Packit Service ae04f2
	fd_set writes;
Packit Service ae04f2
Packit Service ae04f2
	maxfd = -1;
Packit Service ae04f2
	FD_ZERO(&reads);
Packit Service ae04f2
	FD_ZERO(&writes);
Packit Service ae04f2
Packit Service ae04f2
	source = ISC_LIST_HEAD(ent->sources);
Packit Service ae04f2
	while (source != NULL) {
Packit Service ae04f2
		if (source->type == ENTROPY_SOURCETYPE_FILE) {
Packit Service ae04f2
			fd = source->sources.file.handle;
Packit Service ae04f2
			if (fd >= 0) {
Packit Service ae04f2
				maxfd = ISC_MAX(maxfd, fd);
Packit Service ae04f2
				FD_SET(fd, &reads);
Packit Service ae04f2
			}
Packit Service ae04f2
		}
Packit Service ae04f2
		if (source->type == ENTROPY_SOURCETYPE_USOCKET) {
Packit Service ae04f2
			fd = source->sources.usocket.handle;
Packit Service ae04f2
			if (fd >= 0) {
Packit Service ae04f2
				switch (source->sources.usocket.status) {
Packit Service ae04f2
				case isc_usocketsource_disconnected:
Packit Service ae04f2
					break;
Packit Service ae04f2
				case isc_usocketsource_connecting:
Packit Service ae04f2
				case isc_usocketsource_connected:
Packit Service ae04f2
				case isc_usocketsource_ndesired:
Packit Service ae04f2
					maxfd = ISC_MAX(maxfd, fd);
Packit Service ae04f2
					FD_SET(fd, &writes);
Packit Service ae04f2
					break;
Packit Service ae04f2
				case isc_usocketsource_wrote:
Packit Service ae04f2
				case isc_usocketsource_reading:
Packit Service ae04f2
					maxfd = ISC_MAX(maxfd, fd);
Packit Service ae04f2
					FD_SET(fd, &reads);
Packit Service ae04f2
					break;
Packit Service ae04f2
				}
Packit Service ae04f2
			}
Packit Service ae04f2
		}
Packit Service ae04f2
		source = ISC_LIST_NEXT(source, link);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	if (maxfd < 0)
Packit Service ae04f2
		return (-1);
Packit Service ae04f2
Packit Service ae04f2
	cc = select(maxfd + 1, &reads, &writes, NULL, NULL);
Packit Service ae04f2
	if (cc < 0)
Packit Service ae04f2
		return (-1);
Packit Service ae04f2
Packit Service ae04f2
	return (cc);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
destroyfilesource(isc_entropyfilesource_t *source) {
Packit Service ae04f2
	(void)close(source->handle);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
static void
Packit Service ae04f2
destroyusocketsource(isc_entropyusocketsource_t *source) {
Packit Service ae04f2
	close(source->handle);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
/*
Packit Service ae04f2
 * Make a fd non-blocking
Packit Service ae04f2
 */
Packit Service ae04f2
static isc_result_t
Packit Service ae04f2
make_nonblock(int fd) {
Packit Service ae04f2
	int ret;
Packit Service ae04f2
	char strbuf[ISC_STRERRORSIZE];
Packit Service ae04f2
#ifdef USE_FIONBIO_IOCTL
Packit Service ae04f2
	int on = 1;
Packit Service ae04f2
#else
Packit Service ae04f2
	int flags;
Packit Service ae04f2
#endif
Packit Service ae04f2
Packit Service ae04f2
#ifdef USE_FIONBIO_IOCTL
Packit Service ae04f2
	ret = ioctl(fd, FIONBIO, (char *)&on;;
Packit Service ae04f2
#else
Packit Service ae04f2
	flags = fcntl(fd, F_GETFL, 0);
Packit Service ae04f2
	flags |= PORT_NONBLOCK;
Packit Service ae04f2
	ret = fcntl(fd, F_SETFL, flags);
Packit Service ae04f2
#endif
Packit Service ae04f2
Packit Service ae04f2
	if (ret == -1) {
Packit Service ae04f2
		isc__strerror(errno, strbuf, sizeof(strbuf));
Packit Service ae04f2
		UNEXPECTED_ERROR(__FILE__, __LINE__,
Packit Service ae04f2
#ifdef USE_FIONBIO_IOCTL
Packit Service ae04f2
				 "ioctl(%d, FIONBIO, &on): %s", fd,
Packit Service ae04f2
#else
Packit Service ae04f2
				 "fcntl(%d, F_SETFL, %d): %s", fd, flags,
Packit Service ae04f2
#endif
Packit Service ae04f2
				 strbuf);
Packit Service ae04f2
Packit Service ae04f2
		return (ISC_R_UNEXPECTED);
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
}
Packit Service ae04f2
Packit Service ae04f2
isc_result_t
Packit Service ae04f2
isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
Packit Service ae04f2
	int fd;
Packit Service ae04f2
	struct stat _stat;
Packit Service ae04f2
	bool is_usocket = false;
Packit Service ae04f2
	bool is_connected = false;
Packit Service ae04f2
	isc_result_t ret;
Packit Service ae04f2
	isc_entropysource_t *source;
Packit Service ae04f2
Packit Service ae04f2
	REQUIRE(VALID_ENTROPY(ent));
Packit Service ae04f2
	REQUIRE(fname != NULL);
Packit Service ae04f2
Packit Service ae04f2
	LOCK(&ent->lock);
Packit Service ae04f2
Packit Service ae04f2
	if (stat(fname, &_stat) < 0) {
Packit Service ae04f2
		ret = isc__errno2result(errno);
Packit Service ae04f2
		goto errout;
Packit Service ae04f2
	}
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * Solaris 2.5.1 does not have support for sockets (S_IFSOCK),
Packit Service ae04f2
	 * but it does return type S_IFIFO (the OS believes that
Packit Service ae04f2
	 * the socket is a fifo).  This may be an issue if we tell
Packit Service ae04f2
	 * the program to look at an actual FIFO as its source of
Packit Service ae04f2
	 * entropy.
Packit Service ae04f2
	 */
Packit Service ae04f2
#if defined(S_ISSOCK)
Packit Service ae04f2
	if (S_ISSOCK(_stat.st_mode))
Packit Service ae04f2
		is_usocket = true;
Packit Service ae04f2
#endif
Packit Service ae04f2
#if defined(S_ISFIFO) && defined(sun)
Packit Service ae04f2
	if (S_ISFIFO(_stat.st_mode))
Packit Service ae04f2
		is_usocket = true;
Packit Service ae04f2
#endif
Packit Service ae04f2
	if (is_usocket)
Packit Service ae04f2
		fd = socket(PF_UNIX, SOCK_STREAM, 0);
Packit Service ae04f2
	else
Packit Service ae04f2
		fd = open(fname, O_RDONLY | PORT_NONBLOCK, 0);
Packit Service ae04f2
Packit Service ae04f2
	if (fd < 0) {
Packit Service ae04f2
		ret = isc__errno2result(errno);
Packit Service ae04f2
		goto errout;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	ret = make_nonblock(fd);
Packit Service ae04f2
	if (ret != ISC_R_SUCCESS)
Packit Service ae04f2
		goto closefd;
Packit Service ae04f2
Packit Service ae04f2
	if (is_usocket) {
Packit Service ae04f2
		struct sockaddr_un sname;
Packit Service ae04f2
Packit Service ae04f2
		memset(&sname, 0, sizeof(sname));
Packit Service ae04f2
		sname.sun_family = AF_UNIX;
Packit Service ae04f2
		strlcpy(sname.sun_path, fname, sizeof(sname.sun_path));
Packit Service ae04f2
#ifdef ISC_PLATFORM_HAVESALEN
Packit Service ae04f2
#if !defined(SUN_LEN)
Packit Service ae04f2
#define SUN_LEN(su) \
Packit Service ae04f2
	(sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
Packit Service ae04f2
#endif
Packit Service ae04f2
		sname.sun_len = SUN_LEN(&sname);
Packit Service ae04f2
#endif
Packit Service ae04f2
Packit Service ae04f2
		if (connect(fd, (struct sockaddr *) &sname,
Packit Service ae04f2
			    sizeof(struct sockaddr_un)) < 0) {
Packit Service ae04f2
			if (errno != EINPROGRESS) {
Packit Service ae04f2
				ret = isc__errno2result(errno);
Packit Service ae04f2
				goto closefd;
Packit Service ae04f2
			}
Packit Service ae04f2
		} else
Packit Service ae04f2
			is_connected = true;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
Packit Service ae04f2
	if (source == NULL) {
Packit Service ae04f2
		ret = ISC_R_NOMEMORY;
Packit Service ae04f2
		goto closefd;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * From here down, no failures can occur.
Packit Service ae04f2
	 */
Packit Service ae04f2
	source->magic = SOURCE_MAGIC;
Packit Service ae04f2
	source->ent = ent;
Packit Service ae04f2
	source->total = 0;
Packit Service ae04f2
	source->bad = false;
Packit Service ae04f2
	memset(source->name, 0, sizeof(source->name));
Packit Service ae04f2
	ISC_LINK_INIT(source, link);
Packit Service ae04f2
	if (is_usocket) {
Packit Service ae04f2
		source->sources.usocket.handle = fd;
Packit Service ae04f2
		if (is_connected)
Packit Service ae04f2
			source->sources.usocket.status =
Packit Service ae04f2
					isc_usocketsource_connected;
Packit Service ae04f2
		else
Packit Service ae04f2
			source->sources.usocket.status =
Packit Service ae04f2
					isc_usocketsource_connecting;
Packit Service ae04f2
		source->sources.usocket.sz_to_recv = 0;
Packit Service ae04f2
		source->type = ENTROPY_SOURCETYPE_USOCKET;
Packit Service ae04f2
	} else {
Packit Service ae04f2
		source->sources.file.handle = fd;
Packit Service ae04f2
		source->type = ENTROPY_SOURCETYPE_FILE;
Packit Service ae04f2
	}
Packit Service ae04f2
Packit Service ae04f2
	/*
Packit Service ae04f2
	 * Hook it into the entropy system.
Packit Service ae04f2
	 */
Packit Service ae04f2
	ISC_LIST_APPEND(ent->sources, source, link);
Packit Service ae04f2
	ent->nsources++;
Packit Service ae04f2
Packit Service ae04f2
	UNLOCK(&ent->lock);
Packit Service ae04f2
	return (ISC_R_SUCCESS);
Packit Service ae04f2
Packit Service ae04f2
 closefd:
Packit Service ae04f2
	(void)close(fd);
Packit Service ae04f2
Packit Service ae04f2
 errout:
Packit Service ae04f2
	UNLOCK(&ent->lock);
Packit Service ae04f2
Packit Service ae04f2
	return (ret);
Packit Service ae04f2
}