view compat/getentropy.c @ 25:616385fa1fd9

Build common functions as a library that can be reused
author Guido Berhoerster <guido+pwm@berhoerster.name>
date Wed, 20 Sep 2017 23:57:51 +0200
parents a7e41e1a79c8
children
line wrap: on
line source

/*
 * Copyright (C) 2016 Guido Berhoerster <guido+pwm@berhoerster.name>
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be included
 * in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

/* needed for syscall(2) on Linux */
#define	_GNU_SOURCE

/* Linux >= 3.17 has getrandom(2) system call */
#ifdef	__linux__
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/random.h>
#ifdef	SYS_getrandom
#define	HAVE_GETRANDOM
#endif /* SYS_getrandom */
#endif /* __linux__ */
/*
 * on unknown Unix systems without getentropy(2) or Linux without getrandom(2)
 * fall back to * reading from /dev/(u)random
 */
#ifndef	HAVE_GETRANDOM
#include <stdio.h>
#ifndef	RANDOM_DEVICE
#ifdef	__linux__
/* on Linux /dev/urandom should be good enough */
#define	RANDOM_DEVICE	"/dev/urandom"
#else /* __linux__ */
/* on unknown Unix systems use the possibly blocking /dev/random */
#define	RANDOM_DEVICE	"/dev/random"
#endif /* __linux__ */
#endif /* !RANDOM_DEVICE */
#endif /* !HAVE_GETRANDOM */
#include <errno.h>

#ifdef	HAVE_GETRANDOM
static int
getentropy_linux_getrandom(void *buf, size_t buf_len)
{
	int retval;

	retval = syscall(SYS_getrandom, buf, buf_len, 0);
	if (retval < 0) {
		return (-1);
	} else if ((size_t)retval != buf_len) {
		errno = EIO;
		return (-1);
	}

	return (0);
}
#else
static int
getentropy_dev_random(void *buf, size_t buf_len)
{
	FILE	*fp;
	int	saved_errno;

	fp = fopen(RANDOM_DEVICE, "r");
	if (fp == NULL) {
		return (-1);
	}
	if (fread(buf, 1, buf_len, fp) != buf_len) {
		saved_errno = errno;
		fclose(fp);
		errno = saved_errno;
		return (-1);
	}
	if (fclose(fp) != 0) {
		return (-1);
	}

	return (0);
}
#endif /* HAVE_GETRANDOM */

int
getentropy(void *buf, size_t buf_len)
{
	if (buf_len > 256) {
		errno = EIO;
		return (-1);
	}

	return (
#ifdef	HAVE_GETRANDOM
	    getentropy_linux_getrandom(
#else /* HAVE_GETRANDOM */
	    getentropy_dev_random(
#endif /* HAVE_GETRANDOM */
	    buf, buf_len));
}