예제 #1
0
파일: entropy.c 프로젝트: Gradwell/bind9
isc_result_t
isc_entropy_createfilesource(isc_entropy_t *ent, const char *fname) {
	isc_result_t ret;
	isc_entropysource_t *source;
	HCRYPTPROV hcryptprov;
	BOOL err;

	REQUIRE(VALID_ENTROPY(ent));
	REQUIRE(fname != NULL);

	LOCK(&ent->lock);

	source = NULL;

	/*
	 * The first time we just try to acquire the context
	 */
	err = CryptAcquireContext(&hcryptprov, NULL, NULL, PROV_RSA_FULL,
				  CRYPT_VERIFYCONTEXT);
	if (!err){
		(void)GetLastError();
		ret = ISC_R_IOERROR;
		goto errout;
	}

	source = isc_mem_get(ent->mctx, sizeof(isc_entropysource_t));
	if (source == NULL) {
		ret = ISC_R_NOMEMORY;
		goto closecontext;
	}

	/*
	 * From here down, no failures can occur.
	 */
	source->magic = SOURCE_MAGIC;
	source->type = ENTROPY_SOURCETYPE_FILE;
	source->ent = ent;
	source->total = 0;
	source->bad = ISC_FALSE;
	memset(source->name, 0, sizeof(source->name));
	ISC_LINK_INIT(source, link);
	source->sources.file.handle = hcryptprov;

	/*
	 * Hook it into the entropy system.
	 */
	ISC_LIST_APPEND(ent->sources, source, link);
	ent->nsources++;

	UNLOCK(&ent->lock);
	return (ISC_R_SUCCESS);

 closecontext:
	CryptReleaseContext(hcryptprov, 0);

 errout:
	if (source != NULL)
		isc_mem_put(ent->mctx, source, sizeof(isc_entropysource_t));

	UNLOCK(&ent->lock);

	return (ret);
}
예제 #2
0
파일: entropy.c 프로젝트: Gradwell/bind9
/*
 * Poll each source, trying to get data from it to stuff into the entropy
 * pool.
 */
static void
fillpool(isc_entropy_t *ent, unsigned int desired, isc_boolean_t blocking) {
	unsigned int added;
	unsigned int remaining;
	unsigned int needed;
	unsigned int nsource;
	isc_entropysource_t *source;
	isc_entropysource_t *firstsource;

	REQUIRE(VALID_ENTROPY(ent));

	needed = desired;

	/*
	 * This logic is a little strange, so an explanation is in order.
	 *
	 * If needed is 0, it means we are being asked to "fill to whatever
	 * we think is best."  This means that if we have at least a
	 * partially full pool (say, > 1/4th of the pool) we probably don't
	 * need to add anything.
	 *
	 * Also, we will check to see if the "pseudo" count is too high.
	 * If it is, try to mix in better data.  Too high is currently
	 * defined as 1/4th of the pool.
	 *
	 * Next, if we are asked to add a specific bit of entropy, make
	 * certain that we will do so.  Clamp how much we try to add to
	 * (DIGEST_SIZE * 8 < needed < POOLBITS - entropy).
	 *
	 * Note that if we are in a blocking mode, we will only try to
	 * get as much data as we need, not as much as we might want
	 * to build up.
	 */
	if (needed == 0) {
		REQUIRE(!blocking);

		if ((ent->pool.entropy >= RND_POOLBITS / 4)
		    && (ent->pool.pseudo <= RND_POOLBITS / 4))
			return;

		needed = THRESHOLD_BITS * 4;
	} else {
		needed = ISC_MAX(needed, THRESHOLD_BITS);
		needed = ISC_MIN(needed, RND_POOLBITS);
	}

	/*
	 * In any case, clamp how much we need to how much we can add.
	 */
	needed = ISC_MIN(needed, RND_POOLBITS - ent->pool.entropy);

	/*
	 * But wait!  If we're not yet initialized, we need at least
	 *	THRESHOLD_BITS
	 * of randomness.
	 */
	if (ent->initialized < THRESHOLD_BITS)
		needed = ISC_MAX(needed, THRESHOLD_BITS - ent->initialized);

	/*
	 * Poll each file source to see if we can read anything useful from
	 * it.  XXXMLG When where are multiple sources, we should keep a
	 * record of which one we last used so we can start from it (or the
	 * next one) to avoid letting some sources build up entropy while
	 * others are always drained.
	 */

	added = 0;
	remaining = needed;
	if (ent->nextsource == NULL) {
		ent->nextsource = ISC_LIST_HEAD(ent->sources);
		if (ent->nextsource == NULL)
			return;
	}
	source = ent->nextsource;
	/*
	 * Remember the first source so we can break if we have looped back to
	 * the beginning and still have nothing
	 */
	firstsource = source;
 again_file:
	for (nsource = 0; nsource < ent->nsources; nsource++) {
		unsigned int got;

		if (remaining == 0)
			break;

		got = 0;

		if (source->type == ENTROPY_SOURCETYPE_FILE)
			got = get_from_filesource(source, remaining);

		added += got;

		remaining -= ISC_MIN(remaining, got);

		source = ISC_LIST_NEXT(source, link);
		if (source == NULL)
			source = ISC_LIST_HEAD(ent->sources);
	}
	ent->nextsource = source;

	/*
	 * Go again only if there's been progress and we've not
	 * gone back to the beginning
	 */
	if (!(ent->nextsource == firstsource && added == 0)) {
		if (blocking && remaining != 0) {
				goto again_file;
		}
	}

	/*
	 * Here, if there are bits remaining to be had and we can block,
	 * check to see if we have a callback source.  If so, call them.
	 */
	source = ISC_LIST_HEAD(ent->sources);
	while ((remaining != 0) && (source != NULL)) {
		unsigned int got;

		got = 0;

		if (source->type == ENTROPY_SOURCETYPE_CALLBACK)
			got = get_from_callback(source, remaining, blocking);

		added += got;
		remaining -= ISC_MIN(remaining, got);

		if (added >= needed)
			break;

		source = ISC_LIST_NEXT(source, link);
	}

	/*
	 * Mark as initialized if we've added enough data.
	 */
	if (ent->initialized < THRESHOLD_BITS)
		ent->initialized += added;
}
예제 #3
0
파일: entropy.c 프로젝트: 274914765/C
isc_result_t isc_entropy_createfilesource (isc_entropy_t * ent, const char *fname)
{
    int fd;

    struct stat _stat;

    isc_boolean_t is_usocket = ISC_FALSE;

    isc_boolean_t is_connected = ISC_FALSE;

    isc_result_t ret;

    isc_entropysource_t *source;

    REQUIRE (VALID_ENTROPY (ent));
    REQUIRE (fname != NULL);

    LOCK (&ent->lock);

    if (stat (fname, &_stat) < 0)
    {
        ret = isc__errno2result (errno);
        goto errout;
    }
    /*
     * Solaris 2.5.1 does not have support for sockets (S_IFSOCK),
     * but it does return type S_IFIFO (the OS believes that
     * the socket is a fifo).  This may be an issue if we tell
     * the program to look at an actual FIFO as its source of
     * entropy.
     */
#if defined(S_ISSOCK)
    if (S_ISSOCK (_stat.st_mode))
        is_usocket = ISC_TRUE;
#endif
#if defined(S_ISFIFO) && defined(sun)
    if (S_ISFIFO (_stat.st_mode))
        is_usocket = ISC_TRUE;
#endif
    if (is_usocket)
        fd = socket (PF_UNIX, SOCK_STREAM, 0);
    else
        fd = open (fname, O_RDONLY | PORT_NONBLOCK, 0);

    if (fd < 0)
    {
        ret = isc__errno2result (errno);
        goto errout;
    }

    ret = make_nonblock (fd);
    if (ret != ISC_R_SUCCESS)
        goto closefd;

    if (is_usocket)
    {
        struct sockaddr_un sname;

        memset (&sname, 0, sizeof (sname));
        sname.sun_family = AF_UNIX;
        strncpy (sname.sun_path, fname, sizeof (sname.sun_path));
        sname.sun_path[sizeof (sname.sun_path) - 1] = '0';
#ifdef ISC_PLATFORM_HAVESALEN
#if !defined(SUN_LEN)
#define SUN_LEN(su) \
    (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
#endif
        sname.sun_len = SUN_LEN (&sname);
#endif

        if (connect (fd, (struct sockaddr *) &sname, sizeof (struct sockaddr_un)) < 0)
        {
            if (errno != EINPROGRESS)
            {
                ret = isc__errno2result (errno);
                goto closefd;
            }
        }
        else
            is_connected = ISC_TRUE;
    }

    source = isc_mem_get (ent->mctx, sizeof (isc_entropysource_t));
    if (source == NULL)
    {
        ret = ISC_R_NOMEMORY;
        goto closefd;
    }

    /*
     * From here down, no failures can occur.
     */
    source->magic = SOURCE_MAGIC;
    source->ent = ent;
    source->total = 0;
    source->bad = ISC_FALSE;
    memset (source->name, 0, sizeof (source->name));
    ISC_LINK_INIT (source, link);
    if (is_usocket)
    {
        source->sources.usocket.handle = fd;
        if (is_connected)
            source->sources.usocket.status = isc_usocketsource_connected;
        else
            source->sources.usocket.status = isc_usocketsource_connecting;
        source->sources.usocket.sz_to_recv = 0;
        source->type = ENTROPY_SOURCETYPE_USOCKET;
    }
    else
    {
        source->sources.file.handle = fd;
        source->type = ENTROPY_SOURCETYPE_FILE;
    }

    /*
     * Hook it into the entropy system.
     */
    ISC_LIST_APPEND (ent->sources, source, link);
    ent->nsources++;

    UNLOCK (&ent->lock);
    return (ISC_R_SUCCESS);

  closefd:
    (void) close (fd);

  errout:
    UNLOCK (&ent->lock);

    return (ret);
}